PageRenderTime 45ms CodeModel.GetById 1ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/jeromes-keywords/jeromes-keywords.php

http://cartonbank.googlecode.com/
PHP | 710 lines | 466 code | 95 blank | 149 comment | 71 complexity | 11a581ee45e014f3c665a41f48574549 MD5 | raw file
  1<?php
  2/*
  3Plugin Name: Jerome's Keywords
  4Plugin URI: http://vapourtrails.ca/wp-keywords
  5Version: 2.0-beta3
  6Description: Allows keywords to be associated with each post, which can be used as meta keywords and for creating a local tag system.
  7Author: Jerome Lavigne
  8Author URI: http://vapourtrails.ca
  9*/
 10
 11/*	Copyright 2005  Jerome Lavigne  (email : darkcanuck@vapourtrails.ca)
 12	
 13	This program is free software; you can redistribute it and/or modify
 14	it under the terms of the GNU General Public License as published by
 15	the Free Software Foundation; either version 2 of the License, or
 16	(at your option) any later version.
 17	
 18	This program is distributed in the hope that it will be useful,
 19	but WITHOUT ANY WARRANTY; without even the implied warranty of
 20	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21	GNU General Public License for more details.
 22	
 23	You should have received a copy of the GNU General Public License
 24	along with this program; if not, write to the Free Software
 25	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 26*/
 27
 28/* Credits:
 29	Special thanks also to Dave Metzener, Mark Eckenrode, Dan Taarin, N. Godbout,
 30    "theanomaly", "oso", Wayne @ AcmeTech, Will Luke, Gyu-In Lee, Denis de Bernardy,
 31    Horst Gutmann, "Chip" Camden, Christian Davén, Johannes Jarolim, Mike Koepke
 32    and the many others who have provided feedback, spotted bugs, and suggested
 33    improvements.
 34*/
 35
 36/* ChangeLog:
 37
 389-Sep-2006:  Version 2.0-beta3
 39    - major overhaul of entire plugin
 40    - added tag management features from LightPress
 41    - added default options which are saved to the db
 42    - moved old functions (template tags) to legacy.php
 43    - many minor improvements, including random sorting of tag cloud & automatic meta keyword generation
 44
 45*/
 46
 47/* uncomment these lines to see how many warnings WP can throw */
 48//error_reporting(E_ALL);
 49//ini_set('display_errors', 1);
 50
 51class JeromesKeywords {
 52
 53    /* plugin options */
 54    var $option = array(
 55        'version'        => '2.0',          // keywords options version
 56        'keywords_table' => 'jkeywords',    // table where keywords/tags are stored
 57        'query_varname'  => 'tag',          // HTTP var name used for tag searches
 58        'template'       => 'keywords.php', // template file to use for displaying tag queries
 59
 60        'meta_always_include' => '',        // meta keywords to always include
 61        'meta_includecats' => 'default',    // default' => include cats in meta keywords only for home page
 62                                            // all' => includes cats on every page, none' => never included
 63        
 64        'meta_autoheader'    => '1',        // automatically output meta keywords in header
 65        'search_strict'      => '1',        // returns only exact tag matches if true
 66        'use_feed_cats'      => '1',        // insert tags into feeds as categories
 67    
 68        /* post tag options */
 69        'post_linkformat'    => '',         // post tag format (initialized to $link_localsearch)
 70        'post_tagseparator'  => ', ',       // tag separator character(s)
 71        'post_includecats'   => '0',        // include categories in post's tag list
 72        'post_notagstext'    => 'none',     // text to display if no tags found
 73        
 74        /* tag cloud options */
 75        'cloud_linkformat'   => '',         // post tag format (initialized to $link_tagcloud)
 76        'cloud_tagseparator' => ' ',        // tag separator character(s)
 77        'cloud_includecats'  => '0',        // include categories in tag cloud
 78        'cloud_sortorder'    => 'natural',  // tag sorting: natural, countup/asc, countdown/desc, alpha
 79        'cloud_displaymax'   => '0',        // maximum # of tags to display (all if set to zero)
 80        'cloud_displaymin'   => '0',        // minimum tag count to include in tag cloud
 81        'cloud_scalemax'     => '0',        // maximum value for count scaling (no scaling if zero)
 82        'cloud_scalemin'     => '0'         // minimum value for count scaling
 83        );
 84    
 85    /* standard tag link formats */
 86    var $link_localsearch = '<a href="%fulltaglink%" title="Search site for %tagname%" rel="tag">%tagname%</a>';
 87    var $link_technorati = '<a href="http://technorati.com/tag/%taglink%/" title="Technorati tag page for %tagname%" rel="tag">%tagname%</a>';
 88    var $link_tagcloud = '<li class="cosmos keyword%count%"><a href="%fulltaglink%">%tagname%</a></li>';
 89    
 90    /* set during class setup */
 91    var $keyword = '';          // keyword search value
 92    var $rewriteon = false;     // defaults to using no rewrite rules
 93    var $base_url  = '';        // base URL for local tags (depending on permalink style)
 94    var $admin = null;          // reference to admin class
 95    
 96    
 97    /* private members */
 98    var $_table = '';           // full name of tags table
 99    var $_postids = '';         // stores comma-separated list of post IDs in current view
100    var $_posttags = null;      // post tag data cache
101    var $_alltags = null;       // all published tag data cache
102    var $_allcats = null;       // all published categories cache
103    var $_allcombined = null;   // sorted compilation of tags & cats
104    var $_initdone = false;
105    var $_flushrules = false;
106    
107    
108    /* initialization and basic setup methods */
109
110    function JeromesKeywords() {
111        $this->loadOptions();
112        
113        /* set custom table name */
114        global $table_prefix;
115        $this->_table = $table_prefix . $this->option['keywords_table'];
116        
117        /* setup filter/action triggers */
118        add_action('init', array(&$this, 'initRewrite'));           // can't use WP rewrite flags until "init" hook
119        add_filter('the_posts', array(&$this, 'getPostIds'), 90);   // get post IDs once WP query is done
120        add_filter('query_vars', array(&$this, 'addQueryVar'));     // used for keyword searches
121        add_action('parse_query', array(&$this, 'parseQuery'));     // used for keyword searches
122        if (is_admin())
123            add_action('admin_menu', array(&$this, 'setAdminHooks'));    // administration interface
124        if ($this->option['use_feed_cats'])       // insert tags into feeds as categories
125            add_filter('the_category_rss', array(&$this, 'createFeedCategories'), 5, 2);
126        if ($this->option['meta_autoheader'])     // automagic meta keywords in header
127            add_action('wp_head', array(&$this, 'outputHeader'));
128    }
129    
130    function initRewrite() {
131        global $wp_rewrite;
132        /* detect permalink type & construct base URL for local links */
133        $this->base_url = get_option('home') . '/';
134        if (isset($wp_rewrite) && $wp_rewrite->using_permalinks()) {
135            $this->rewriteon = true;                    // using rewrite rules
136            $this->base_url .= $wp_rewrite->root;		// set to "index.php/" if using that style
137            $this->base_url .= $this->option['query_varname'] . '/';
138        } else {
139            $this->base_url .= '?' . $this->option['query_varname'] . '=';
140        }
141        
142        /* generate rewrite rules for tag queries */
143        if ($this->rewriteon)
144            add_filter('search_rewrite_rules', array(&$this, 'createRewriteRules'));
145        
146        /* flush rules if requested */
147        $this->_initdone = true;
148        if ($this->_flushrules) 
149            $wp_rewrite->flush_rules();
150    }
151
152    function createRewriteRules($rewrite) {
153        global $wp_rewrite;
154        /* add rewrite tokens */
155        $qvar =& $this->option['query_varname'];
156        $token = '%' . $qvar . '%';
157        $wp_rewrite->add_rewrite_tag($token, '(.+)', $qvar . '=');
158        
159        $keywords_structure = $wp_rewrite->root . $qvar . "/$token";
160        $keywords_rewrite = $wp_rewrite->generate_rewrite_rules($keywords_structure);
161
162        return ( $rewrite + $keywords_rewrite );
163    }
164
165    function setAdminHooks() {
166        /* load administration class */
167        include (dirname(__FILE__) . DIRECTORY_SEPARATOR . 'LightPressTagging.php');
168        $this->admin =& new LightPressTagging($this->_table);
169        
170        /* add tag management menu */
171        add_management_page('Manage Jerome\'s Keywords', 'Keywords/Tags', 'manage_categories', 'jeromes-keywords/managetags.php');
172        add_options_page('Jerome\'s Keywords Options', 'Jerome\'s Keywords', 'manage_options', 'jeromes-keywords/options-jkeywords.php');
173    }
174
175    function loadOptions() {
176        /* check if options exist */
177        if (substr(get_option('jkeywords_version'),1,-1) < 2.0) {
178            $this->option['post_linkformat'] = $this->link_localsearch;
179            $this->option['cloud_linkformat'] = $this->link_tagcloud;
180            $this->saveOptions();
181        } else {
182            /* read option values from the database, stripping our spacer characters */
183            foreach($this->option as $optname => $optval) {
184                $newval = substr(get_option('jkeywords_' . $optname), 1, -1);
185                if ($newval != '')
186                    $this->option[$optname] = $newval;
187            }
188        }
189    }
190    
191    function setOption($optname, $optval) {
192        /* update option value */
193        $this->option[$optname] = $optval;
194    }
195
196    function saveOptions() {
197        /* flush WP rewrite rules if query var has changed */
198        global $wp_rewrite;
199        $qvar = 'query_varname';
200        if ($this->option[$qvar] != substr(get_option("jkeywords_$qvar"),1,-1)) {
201            if ($this->_initdone)
202                $wp_rewrite->flush_rules();
203            else
204                $this->_flushrules = true;
205        }
206        
207        /* write current option values to the database */
208        /* add a dummy char to beginning & end because WP won't save spaces! */
209        foreach($this->option as $optname => $optval)
210            update_option('jkeywords_' . $optname, '*' . $optval . '*');
211    }
212
213
214    /* tag fetch & caching */
215    
216    function getPostIds($posts) {
217        /* extract list of post IDs from the posts array */
218        if (!is_null($posts) && is_array($posts)) {
219            foreach($posts as $p) {
220                $this->_postids .= (!empty($this->_postids) ? ',' : '') . $p->ID;   //create comma-separated list
221            }
222        }
223        return $posts;  //send'em back to WP
224    }
225    
226    function getPostTags($postid=null, $force=false) {
227        /*
228         * caches all tags matching current post selection
229         */
230        if (is_null($this->_posttags) || $force) {
231            if (empty($this->_postids)) {
232                $this->_posttags = array(); // no posts, thus no tags
233                return $this->_posttags;
234            }
235            
236            global $wpdb;
237            $q = "SELECT DISTINCT post_id, tag_name AS name
238                    FROM {$this->_table} tags
239                    WHERE post_id IN ({$this->_postids})
240                    ORDER BY post_id, name";
241            $tag_results = $wpdb->get_results($q);
242            
243            $post_tags = array();
244            if (!is_null($tag_results) && is_array($tag_results)) {
245                foreach ($tag_results as $tag) {
246                    $post_id = $tag->post_id;
247                    if (!isset($post_tags[$post_id]))
248                            $post_tags[$post_id] = array();
249                    $post_tags[$post_id][] = $tag->name;
250                }
251            }
252            $this->_posttags =& $post_tags;
253        }
254        if (is_null($postid))
255            return $this->_posttags;
256        elseif (isset($this->_posttags[$postid]))
257            return $this->_posttags[$postid];
258        else
259            return array();
260    }
261
262    function getAllTags($force=false) {
263        /*
264         * gets all published site tags
265         */
266        if (is_null($this->_alltags) || $force) {
267            global $wpdb;
268            $q = "SELECT tag.tag_name AS name, COUNT(tag.post_id) AS numposts
269                FROM {$this->_table} tag
270                INNER JOIN {$wpdb->posts} p ON tag.post_id=p.id
271                WHERE (p.post_status='publish' OR p.post_status='static')
272                  AND p.post_date_gmt<='" . gmdate("Y-m-d H:i:s", time()) . "'
273                GROUP BY tag.tag_name
274                ORDER BY numposts DESC ";
275            $tag_results = $wpdb->get_results($q);
276            
277            $alltags = array();
278            if (!is_null($tag_results) && is_array($tag_results)) {
279                foreach ($tag_results as $tag) {
280                    $alltags[$tag->name] = array('name' => $tag->name,
281                                                 'count'=> $tag->numposts,
282                                                 'link' => $this->getTagPermalink($tag->name)
283                                                );
284                }
285            }
286            $this->_alltags =& $alltags;
287        }
288        return $this->_alltags;
289    }
290
291    function getAllCats($force=false) {
292        /*
293         * gets all published site categories (same format as getAllTags)
294         */
295        if (is_null($this->_allcats) || $force) {
296            global $wpdb;
297            $q = "SELECT p2c.category_id AS cat_id, COUNT(p2c.rel_id) AS numposts,
298                    UNIX_TIMESTAMP(max(p.post_date_gmt)) + '" . get_option('gmt_offset') . "' AS last_post_date,
299                    UNIX_TIMESTAMP(max(p.post_date_gmt)) AS last_post_date_gmt
300                FROM {$wpdb->post2cat} p2c
301                INNER JOIN {$wpdb->posts} p ON p2c.post_id=p.id
302                WHERE (p.post_status='publish' OR p.post_status='static')
303                  AND p.post_date_gmt<='" . gmdate("Y-m-d H:i:s", time()) . "'
304                GROUP BY p2c.category_id
305                ORDER BY numposts DESC ";
306            $results = $wpdb->get_results($q);
307            
308            $allcats = array();
309            if (!is_null($results) && is_array($results)) {
310                foreach ($results as $cat) {
311                    $catname = get_catname($cat->cat_id);
312                    $allcats[$catname] = array('name' => get_catname($cat->cat_id),
313                                               'count'=> $cat->numposts,
314                                               'link' => get_category_link((int)$cat->cat_id)
315                                              );
316                }
317            }
318            $this->_allcats =& $allcats;
319        }
320        return $this->_allcats;
321    }
322
323    function getAllCombined($force=false) {
324        /*
325         * combines all published tags & categories
326         */
327        if (is_null($this->_allcombined) || $force) {
328            $combined = array_merge($this->getAllTags(), $this->getAllCats());
329            uasort($combined, array(&$this, 'sortCombined'));
330            $this->_allcombined =& $combined;
331        }
332        return $this->_allcombined;
333    }
334
335    function sortCombined($a, $b) {
336        /* sort by descending count, ties broken by nat case ascending name */
337        if ($a['count'] == $b['count']) 
338            return strnatcasecmp($a['name'], $b['name']);
339        else
340            return ( ($a['count'] > $b['count']) ? -1 : 1 );
341    }
342    
343    
344    /* meta keywords methods */
345    
346    function getMetaKeywords($before='', $after='', $separator=',', $include_cats=null) {
347        /* add pre-defined keywords */
348        $pagekeys = explode(',', $this->option['meta_always_include']);
349        
350        /* get tags for all posts in current view */
351        foreach($this->getPostTags() as $post_tags)
352            $pagekeys = array_merge($pagekeys, $post_tags);
353        
354        /* add categories if necessary */
355        if (is_null($include_cats))
356            $include_cats = $this->option['meta_includecats'];
357        if ($include_cats) {
358            global $category_cache;
359            if ( ($include_cats == 'all') || (($include_cats == 'default') && is_home()) ) {
360                /* include all site categories */
361                foreach($this->getAllCats() as $category)
362                    $pagekeys[] = $category['name'];
363            } elseif (isset($category_cache) && ($include_cats != 'none')) {
364                /* include only categories from posts in current view */
365                foreach($category_cache as $post_category) {
366                    foreach($post_category as $category)
367                        $pagekeys[] = $category->cat_name;
368                }
369            }
370        }
371        $pagekeys = array_unique($pagekeys);    // remove duplicates
372        
373        /* setup meta keywords for page header */
374        $keywordlist = '';
375        foreach($pagekeys as $keyword) {
376            $keywordlist .= (($keywordlist != '') ? $separator : '') .
377                                $before . $keyword . $after;
378        }
379        return htmlspecialchars($keywordlist);
380    }
381    
382    function outputMetaKeywords($before='', $after='', $separator=',', $include_cats=null) {
383        /* output meta keyword list */
384        echo $this->getMetaKeywords($before, $after, $separator, $include_cats);
385    }
386    
387    function outputHeader() {
388        /* automagically output meta keywords tag */
389        echo "\t" . '<meta name="keywords" content="' . $this->getMetaKeywords() . '" />';
390    }
391    
392    /* post keywords methods */
393    
394    function formatPostTags($include_cats=null, $linkformat=null) {
395        /* check parameters vs. class options */
396        $include_cats = (is_null($include_cats)) ? $this->option['post_includecats'] : $include_cats;
397        $linkformat   = (is_null($linkformat))   ? $this->option['post_linkformat']  : $linkformat;
398        
399        /* create array of tags & full links */
400        $taglinks = array();
401        if ($include_cats) {
402            $categories = get_the_category();
403            foreach($categories as $cat)
404                $taglinks[ $cat->cat_name ] = get_category_link((int)$cat->cat_ID);
405        }
406        global $id;
407        $post_tags = $this->getPostTags($id);
408        foreach($post_tags as $tag) {
409            $taglinks [ $tag ] = $this->getTagPermalink($tag);
410        }
411        
412        /* substitute values into link format */
413        $output = '';
414        foreach($taglinks as $tag => $url) {
415            $output .= (($output != '') ? $this->option['post_tagseparator'] : '') . 
416                        $this->formatLink($tag, $url, $linkformat);
417        }
418        return($output);
419    }
420    
421    function outputPostTags($include_cats=null, $linkformat=null) {
422        /* output formatted tag list or text indicating no tags */
423        $tags = $this->formatPostTags($include_cats, $linkformat);
424        if (empty($tags))
425            echo $this->option['post_notagstext'];
426        else
427            echo $tags;
428    }
429    
430    
431    /* tag cloud methods */
432    
433    function formatAllTags($include_cats=null, $linkformat=null, $sort_order=null,
434                           $display_max=null, $display_min=null,
435                           $scale_max=null, $scale_min=null) {
436        /* check parameters vs. class options */
437        $include_cats = (is_null($include_cats)) ? $this->option['cloud_includecats']: $include_cats;
438        $linkformat   = (is_null($linkformat))   ? $this->option['cloud_linkformat'] : $linkformat;
439        $sort_order   = (is_null($sort_order))   ? $this->option['cloud_sortorder']  : $sort_order;
440        $display_max  = (is_null($display_max))  ? $this->option['cloud_displaymax'] : $display_max;
441        $display_min  = (is_null($display_min))  ? $this->option['cloud_displaymin'] : $display_min;
442        $scale_max    = (is_null($scale_max))    ? $this->option['cloud_scalemax']   : $scale_max;
443        $scale_min    = (is_null($scale_min))    ? $this->option['cloud_scalemin']   : $scale_min;
444        
445        /* creatarray of tags & full links */
446        if ($include_cats)
447            $alltags = $this->getAllCombined();
448        else
449            $alltags = $this->getAllTags();
450        
451        /* limit results */
452        $limit = (int) $display_max;
453        if (($limit > 0) && (count($alltags) > $limit))       
454            $alltags = array_slice($alltags, 0, $limit, true);  // already in descending order
455        
456        /* re-sort results */
457        switch(strtolower($sort_order)) {
458            case 'alpha':
459                ksort($alltags);
460                break;
461            case 'countup':
462            case 'asc':
463                $alltags = array_reverse($alltags, true);       // reverse array order to be ascending
464                break;
465            case 'countdown':
466            case 'desc':
467                // already in descending order
468                break;
469            case 'random':
470                srand((float)microtime() * 1000000);
471                shuffle($alltags);                              // WARNING: keys not kept!
472                break;
473            default:    // case for 'natural'
474                uksort($alltags, 'strnatcasecmp');
475                break;
476        }
477        
478        /* scaling */
479        $do_scale = ($scale_max != 0);
480        if ($do_scale) {
481            $minval = $maxval = $alltags[ key($alltags) ]['count'];
482            foreach($alltags as $tag) {
483                $minval = min($tag['count'], $minval);
484                $maxval = max($tag['count'], $maxval, $display_min);
485            }
486            $minval = max($minval, $display_min);
487            $minout = max($scale_min, 0);
488            $maxout = max($scale_max, $minout);
489            $scale = ($maxval > $minval) ? (($maxout - $minout) / ($maxval - $minval)) : 0;
490        }
491        
492        /* scale counts & format links */
493        $output = '';
494        foreach($alltags as $tag) {
495            if ($tag['count'] >= $display_min) {
496                $output .= (($output != '') ? $this->option['cloud_tagseparator'] : '') . 
497                            $this->formatLink($tag['name'], $tag['link'], $linkformat, 
498                                              ( ($do_scale) ?
499                                                (int) (($tag['count'] - $minval) * $scale + $minout) 
500                                                : $tag['count'] )
501                            );
502            }
503        }
504        return($output);
505    }
506
507
508    /* link formatting */
509
510    function formatLink($name, $full_link, $format, $count=0) {
511        /* substitute values into link format */
512        $newlink = $format;
513        $newlink = str_replace(array('%tagname%', '%keyword%'), $name, $newlink);
514        $newlink = str_replace(array('%taglink%', '%keylink%'), $this->localLink($name), $newlink);
515        $newlink = str_replace('%flickr%', $this->flickrLink($name), $newlink);
516        $newlink = str_replace('%delicious%', $this->deliciousLink($name), $newlink);
517        $newlink = str_replace(array('%fulltaglink%', '%fullkeylink%'), $full_link, $newlink);
518		$newlink = str_replace('%count%', $count, $newlink);
519		$newlink = str_replace('%em%', str_repeat('<em>', $count), $newlink);
520		$newlink = str_replace('%/em%', str_repeat('</em>', $count), $newlink);
521		return $newlink;
522    }
523    
524    function localLink($keyword) {
525        return str_replace('%2F', '/', urlencode($keyword));
526    }
527    
528    function getTagPermalink($tag) {
529        return ($this->base_url . 
530                (($this->rewriteon) ? $this->localLink($tag) : urlencode($tag)));
531    }
532    
533    function flickrLink($keyword) {
534        return urlencode(preg_replace('/[^a-zA-Z0-9]/', '', strtolower($keyword)));
535    }
536    
537    function deliciousLink($keyword) {
538        $del = preg_replace('/\s/', '', $keyword);
539        if (strstr($del, '+'))
540            $del = '"' . $del . '"';
541        return str_replace('%2F', '/', rawurlencode($del));
542    }
543    
544    
545    /* keyword search results */
546    
547    function is_keyword() {
548        if (!is_null($this->keyword) && ($this->keyword != ''))
549            return true;
550        else
551            return false;
552    }
553
554    function addQueryVar($wpvar_array) {
555        $wpvar_array[] = $this->option['query_varname'];
556        return($wpvar_array);
557    }
558    
559    function parseQuery() {
560        /* set the search keyword if it's available */
561        /* WP2.0's new rewrite rules mean we need to grab it from the query vars */
562        $this->keyword = stripslashes(get_query_var($this->option['query_varname']));
563        if (get_magic_quotes_gpc())
564            $this->keyword = stripslashes($this->keyword);  // why so many freakin' slashes?
565
566        /* if this is a keyword query, then reset other is_x flags and add query filters */
567        if ($this->keyword != '') {
568            global $wp_query;
569            $wp_query->is_single = false;
570            $wp_query->is_page = false;
571            $wp_query->is_archive = false;
572            $wp_query->is_search = false;
573            $wp_query->is_home = false;
574            add_filter('posts_where', array(&$this, 'postsWhere'));
575            add_filter('posts_join',  array(&$this, 'postsJoin'));
576            add_action('template_redirect', array(&$this, 'includeTemplate'));
577        }
578    }
579    
580    function postsWhere($where) {
581        /* update where clause to search on keywords table */
582        if ($this->option['search_strict'])
583            $where .= " AND jkeywords.tag_name='" . addslashes($this->keyword) . "' ";
584        else
585            $where .= " AND jkeywords.tag_name LIKE '%" . addslashes($this->keyword) . "%' ";
586        // include pages in search (from jeromes-search.php)
587        return str_replace(' AND (post_status = "publish"', ' AND ((post_status = \'static\' OR post_status = \'publish\')', $where);
588    }
589    
590    function postsJoin($join) {
591        /* update join clause to include keywords table */
592        global $wpdb;
593        $join .= " LEFT JOIN {$this->_table} AS jkeywords ON ({$wpdb->posts}.ID = jkeywords.post_id) ";
594        return ($join);
595    }
596
597    function includeTemplate() {
598        /* switch template when doing a keyword search */
599        if ($this->is_keyword()) {
600            $template = '';
601            
602            if ( file_exists(TEMPLATEPATH . "/" . $this->option['template']) )
603                $template = TEMPLATEPATH . "/" . $this->option['template'];
604            else if ( file_exists(TEMPLATEPATH . "/tags.php") )
605                $template = TEMPLATEPATH . "/tags.php";
606            else
607                $template = get_category_template();
608            
609            if ($template) {
610                load_template($template);
611                exit;
612            }
613        }
614        return;
615    }
616    
617    
618    /* Tagging feeds */
619
620    function createFeedCategories($list, $type) {
621        /* insert post's tags as categories */
622        global $id;
623        $post_tags = $this->getPostTags($id);
624        
625        foreach($post_tags as $tag) {
626            if ($type == "rdf")
627                $list .= "<dc:subject>$tag</dc:subject>";
628            else
629                $list .= "<category>$tag</category>";
630        }
631        return $list;   //send'em back to WP
632    }
633}
634$JKeywords =& new JeromesKeywords();
635
636
637/* 2.0 "template tags" */
638
639/* jkeywords_post_tags
640 *
641 * Outputs the list of tags related to the current post.
642 * Use this function "in the loop", e.g.
643 *      <?php jkeywords_post_tags(); ? >
644 */
645function jkeywords_post_tags($include_cats=null, $linkformat=null) {
646	global $JKeywords;
647    $JKeywords->outputPostTags($include_cats, $linkformat);
648}
649
650/* jkeywords_meta_keywords
651 *
652 * Outputs the list of meta keywords for the current view
653 * Use this within your site's header, e.g.
654 *      <meta name="keywords" content="<?php jkeywords_meta_keywords(); ? >" />
655 */
656function jkeywords_meta_keywords($before='', $after='', $separator=',', $include_cats=null) {
657	global $JKeywords;
658    $JKeywords->outputMetaKeywords($before, $after, $separator, $include_cats);
659}
660
661/* jkeywords_is_keyword
662 *
663 * Use this to check if the current view will be returning keyword search results.
664 * Returns TRUE if a keyword search was requested, FALSE otherwise.
665 */
666function jkeywords_is_keyword() {
667	global $JKeywords;
668    return $JKeywords->is_keyword();
669}
670
671/* jkeywords_search_keyword
672 *
673 * Outputs the keyword used in a keyword search.  Useful in your tags.php page:
674 *      <h2>All results for "<?php jkeywords_search_keyword(); ? >"</h2>
675 */
676function jkeywords_search_keyword() {
677    global $JKeywords;
678    echo $JKeywords->keyword;
679}
680
681/* jkeywords_tag_cloud
682 *
683 * Outputs a tag cloud for your entire weblog, e.g.
684 *      <h2>All tags on my site</h2>
685 *      <?php jkeywords_tag_cloud(); ? >
686 */
687function jkeywords_tag_cloud($include_cats=null, $linkformat=null, $sort_order=null,
688                             $display_max=null, $display_min=null,
689                             $scale_max=null, $scale_min=null) {
690	global $JKeywords;
691	echo $JKeywords->formatAllTags($include_cats, $linkformat, $sort_order, $display_max,
692                                   $display_min, $scale_max, $scale_min);
693}
694
695/* jkeywords_top_tags
696 *
697 * Similar to a tag cloud, but sorted with the most popular tags listed first.
698 */
699function jkeywords_top_tags($display_max=null,
700                             $linkformat='<li><a href="%fulltaglink%">%keyword%</a></li>',
701                             $sort_order='desc', $display_min=null,
702                             $include_cats=null, $scale_max=null, $scale_min=null) {
703	global $JKeywords;
704	echo $JKeywords->formatAllTags($include_cats, $linkformat, $sort_order, $display_max,
705                                   $display_min, $scale_max, $scale_min);
706}
707
708/* to provide compatibility with 1.x "template tags" */
709include (dirname(__FILE__) . DIRECTORY_SEPARATOR . 'legacy.php');
710?>