Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Note that this action tag has been changed to {{titletag}} to avoid conflicting with an existing action of the same name.
 


SEO Hacks

I use a customized Wikka engine for my company's website. I've been teaching myself the finer points of SEO (search engine optimization), and have modified the code my site runs under to support various SEO initiatives I'm working on to increase the visibility of my company website in the major search engines. I'm tackling Google first, and discovered an excellent resource that outlines several SEO strategies. I'm sharing these ideas with the Wikka community to further demonstrate the flexibility of WikkaWiki. Please feel free to contribute your own SEO hacks on this page!

Note: All code below has been tested and implemented on trunk (unstable) versions of Wikka, in a rather WikiInAVacuum heavily modified environment. These examples may or may not work on production versions of Wikka "as is," and might require additional modifications. The code as posted is working code on my website. These examples are not secure enough to be made available to users you do not explicitly trust. All examples are proof-of-concept and are not intended for use on production sites!
 


title action

One of the recommendations made by Google in their SEO guide is to customize the title of each page, using relevant keywords. Wikka currently does not support per-page title capabilities. This action, along with a minor modification in templates/header.php, permits the display of a customized title for each page. Note that making these modifications disables site-wide titles, so pages without explicit titles set will not contain title tags.

templates/header.php
Locate and comment out the following line (shown as commented out here):
    /* <title><?php echo $doctitle; ?></title> */


Create the following new action directory/file:
actions/title/title.php
<?php
$string = $vars['string'];
$this->AddCustomHeader("<title>".$string."</title>");
?>


Usage
{{title string="My page title with important keywords"}}


meta action

Requires the AddCustomHeader() method, a relatively new addition to Wikka. Check your libs/Wakka.php function library if in doubt.

actions/meta/meta.php
<?php
$name = $vars['name'];
$content = $vars['content'];
$this->AddCustomHeader("<meta name=\"".$name."\" content=\"".$content."\"/>");
?>


Usage
{{meta name="description" content="Specializing in machining and finishing of fine widgets"}}


Display of search term frequencies in the referrers handler page

Create the following new directory/handler. Be sure the plugin path precedes the handlers path in your wikka_handler_path in wikka.config.php:

plugins/handlers/referrers/referrers.php
<?php
/**
 * Display, filter and search a list of referrers or referring sites for the current page or the site as a whole.
 *
 * Usage: append /referrers to the URL of the page
 *      add global=1 to specify referrers for the site instead of the current page
 *      add sites=1 to specify referrerring domains instead of full URLs
 *
 * This handler allows logged-in users to display, filter and search the referrer list for
 * the current page and for the whole site. Current search criteria include strings,
 * number of hits, reference period.
 *
 * @package     Handlers
 *
 * @author      {@link http://wikkawiki.org/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
 * @author      {@link http://wikkawiki.org/JavaWoman JavaWoman} - more code cleanup, accessibility, integration with referrers_sites
 * @uses        Config::$referrers_purge_time
 * @uses        Config::$wakka_name
 * @uses        Wakka::FormClose()
 * @uses        Wakka::FormOpen()
 * @uses        Wakka::GetHandler()
 * @uses        Wakka::GetPageTag()
 * @uses        Wakka::GetUser()
 * @uses        Wakka::Href()
 * @uses        Wakka::htmlspecialchars_ent()
 * @uses        Wakka::IsAdmin()
 * @uses        Wakka::LoadAll()
 * @uses        Wakka::LoadSingle()
 * @uses        Wakka::makeId()
 *
 * @since       Wikka 1.1.7
 *
 * @todo       
 *              - clean up debug code
 *              - remove LoadReferrers() from core
 *              - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
 *              - configurable parameters for building days dropdown (config, installer)
 *              - configurable limit to express days as hours (config, installer)
 *              - build an index on the referrer column in the referrers table (installer)
 *              later:
 *              - transfer filter parameters as well so we cen redirect to the exact view we came from
 *              - (global) icons to represent each of the five views, small and larger versions (menu/page)
 *              - adapt FormOpen() to accept id; then fix form kluge here and in stylesheet
 *              - adapt text definitions to take singular-plural into account
 *              - add paging
 *              - turn list into form with checkboxes to allow mass blacklisting
 *
 * @input       string  $qs  optional: string used to filter the referrers;
 *              default: NULL;
 *              the default can be overridden by providing a POST parameter 'q'
 * @input       integer $qo optional: determines the kind of search to be performed for string $qs:
 *              1: search for all referrers containing a given string
 *              0: search for all referrers not containing a given string
 *              default: 1;
 *              the default can be overridden by providing a POST parameter 'qo'
 * @input       integer $h  optional: number of hits used to filter the referrers;
 *              default: 1;
 *              the default can be overridden by providing a POST parameter 'h'
 * @input       integer $ho optional: determines the kind of filter to be applied to $h:
 *              1: search for referrers with at least $h hits;
 *              0: search for referrers with no more than $h hits;
 *              default: 1;
 *              the default can be overridden by providing a POST parameter 'ho'
 * @input       integer $days  optional: number of days used to filter the referrers;
 *              default: 1;
 *              the default can be overridden by providing a POST parameter 'h'
 * @input       integer $global optional: switches between local/global referrers:
 *              1: display referrers for the whole site;
 *              0: display referrers for the current page;
 *              default: 0;
 *              the default can be overridden by providing a GET/POST parameter 'global'
 * @input       integer $sites  optional: switches between referring urls and domains
 *              1: display referring sites (domains);
 *              0: display referrers (URLs);
 *              default: 0;
 *              the default can be overridden by providing a GET/POST parameter 'sites'
 * @input       integer $refdel optional: number of referrer records deleted
 * @input       integer $bladd  optional: number of blacklist records added
 */


// Utilities

/**
 * Build an array of numbers consisting of 'ranges' with increasing step size in each 'range'.
 *
 * A list of numbers like this is useful for instance for a dropdown to choose
 * a period expressed in number of days: a difference between 2 and 5 days may
 * be significant while that between 92 and 95 may not be.
 *
 * @author      {@link http://wikkawiki.org/JavaWoman JavaWoman}
 * @copyright   Copyright © 2005, Marjolein Katsma
 * @license     http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
 * @version     1.0
 *
 * @param   mixed   $limits required: single integer or array of integers;
 *                  defines the upper limits of the ranges as well as the next step size
 * @param   int     $max    required: upper limit for the whole list
 *                  (will be included if smaller than the largest limit)
 * @param   int     $firstinc optional: increment for the first range; default 1
 * @return  array   resulting list of numbers
 * @todo    find better name
 * @todo    move to core
 */

function optionRanges($limits, $max, $firstinc = 1)
{
    // initializations
    if (is_int($limits)) $limits = array($limits);
    if ($firstinc < 1) $firstinc = 1;
    $opts = array();
    $inc = $firstinc;

    // first element is the first increment
    $opts[] = $inc;
    // each $limit is the upper limit of a 'range'
    foreach ($limits as $limit)
    {
        for ($i = $inc + $inc; $i <= $limit && $i < $max; $i += $inc)
        {
            $opts[] = $i;
        }
        // we quit at $max, even if there are more $limit elements
        if ($limit >= $max)
        {
            // add $max to the list; then break out of the loop
            $opts[] = $max;
            break;
        }
        // when $limit is reached, it becomes the new start and increment for the next 'range'
        $inc = $limit;
    }

    return $opts;
}

// constants

define('DEBUG',FALSE);      # @@@ set TRUE to generate debugging output

define('SEARCH_LIKE','LIKE');           # search string operator
define('SEARCH_UNLIKE','NOT LIKE');     # search string operator
define('HITS_DEFAULT', '1');            # (was 0 for referrers, 1 for sites)
define('HITS_MIN_OPTION', '>=');
define('HITS_MAX_OPTION', '<=');

define('HOURS_LIMIT',2);                # days expressed as hours               @@@ could be made configurable
define('DAYS_MAX', $this->GetConfigValue('referrers_purge_time'));
define('DAYS_DEFAULT', '7');                    # default period to retrieve    @@@ make configurable

$days_limits = array(7,30,90,365);              # ranges for days dropdown      @@@ make configurable

// -------------------------------------

// initialize parameters

$qs = NULL;                             # search string sanitized for SQL query
$qx = '';                               # search string sanitized for XHTML
$qo = 1;                                # search string option
$h = HITS_DEFAULT;                      # hits number
$ho = 1;                                # hits option
$days = DAYS_DEFAULT;                   # period selection
$global = FALSE;                        # global (site) or this page only
$sites = FALSE;                         # referrers or referring sites
$refdel = NULL;                         # referrer records deleted
$bladd = NULL;                          # blacklist records added
$r = 1;                                 # row counter

// -------------------------------------

// initialize internal variables

$string_option = SEARCH_LIKE;           # LIKE or NOT LIKE
$hits_option = HITS_MIN_OPTION;         # MIN (>=) or MAX (<=)
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$par = '';

$query = '';
$rows = 0;

// -------------------------------------

// User-interface strings

define('NAME_GLOBAL',$this->GetConfigValue('wakka_name'));

define('TITLE_REFERRERS','External pages linking to %s');
define('TITLE_SITES','Domains linking to %s');
define('TITLE_SEARCH_TERMS','(Search term rankings)');

define('REPORT_BLACKLIST','Referrer records removed: %d; blacklist records added: %d');

define('TOTAL_REFERRERS','Total: %d referrers linking to %s');
define('TOTAL_SITES','Total: %d referrers linking to %s');

// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE', $tag);

// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');

define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_REFERRERS','URL:');
define('FORM_URL_OPT_SITES','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_HITS_OPT_LABEL','Hits:');
define('FORM_HITS_OPT_TITLE','Select filter option');
define('FORM_HITS_OPT_1','at least');
define('FORM_HITS_OPT_0','no more than');
define('FORM_HITS_NUM_LABEL','hits');
define('FORM_HITS_NUM_TITLE','Enter number of hits');
define('FORM_DAYS_OPT_LABEL','Period:');
define('FORM_DAYS_OPT_TITLE','Select period in days');
define('FORM_DAYS_NUM_LABEL','days');
define('FORM_SUBMIT_URLS','Show referrers');
define('FORM_SUBMIT_SEARCH_TERMS','Rank_search_terms');
define('FORM_SUBMIT_SEARCH_TERMS_LABEL','Rank search terms');
define('FORM_SUBMIT_SITES','Show referring domains');

define('LIST_PERIOD_HOURS',' (last %d hours)');
define('LIST_PERIOD_DAYS',' (last %d days)');
define('LIST_SUMMARY_REFERRERS','Filtered list of referrers, with hits%s, sorted by number of hits');
define('LIST_SUMMARY_SITES','Filtered list of referring sites, with hits%s, sorted by number of hits');
define('LIST_HEAD_HITS','Hits');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_LIST_REFERRERS','Referrers');
define('LIST_HEAD_SEARCH_TERM', 'Search term');
define('LIST_HEAD_FREQ', 'Frequency');
define('LIST_HEAD_LIST_SITES','Referring hosts');
define('LIST_REF_UNKNOWN','unknown');           # make sure the *exact* same string is used in the whitelist definition (delete_referrer.php)
define('LIST_ACTION_DESC',' and links to blacklist spammers');
define('LIST_ACTION_BLACKLIST','Blacklist');
define('LIST_ACTION_BLACKLIST_TITLE','Blacklist this domain');

define('LOGIN_NOTE','You need to login to display referrers.');

// show result counts for target
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %d referrers matching these criteria');    # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains matching these criteria');      # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
// show 'no result' summary for target
define('NONE_NOTE_REFERRERS','No referrers found matching these criteria');
define('NONE_NOTE_SITES','No domains found matching these criteria');


// -------------------------------------

// fetch and validate parameters

// get query string and comparison method
if (isset($_POST['q']))
{
    $tq = trim(strip_tags($_POST['q']));
    if ('' != $tq)
    {
        $qs = mysql_real_escape_string($tq);
        $qx = $this->htmlspecialchars_ent($tq);
        if (isset($_POST['qo']))
        {
            $qo = ($_POST['qo'] == '1') ? 1 : 0;
            $string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
        }
    }
}
// get hits and min or max criteria
if (isset($_POST['h']))
{
    $h = (is_numeric($_POST['h'])) ? abs((int)$_POST['h']) : HITS_DEFAULT;  # cast to positive integer if numeric
}
if (isset($_POST['ho']))
{
    $ho = ($_POST['ho'] == '1') ? 1 : 0;
    $hits_option = ($ho == 1) ? HITS_MIN_OPTION : HITS_MAX_OPTION;
}
// get period, not longer than purge time
if (isset($_POST['days']))
{
    $days = (is_numeric($_POST['days'])) ? min(abs((int)$_POST['days']),DAYS_MAX) : DAYS_DEFAULT;
}
// get search target: page or site (global)
if (isset($_POST['global']))
{
    $global = (bool)$_POST['global'];
}
elseif (isset($_GET['global']))
{
    $global = (bool)$_GET['global'];
}
$iglobal = (int)$global;
// get precision: URLS (referrers) or referring sites (domains)
if (isset($_POST['sites']))
{
    $sites = (bool)$_POST['sites'];
}
elseif (isset($_GET['sites']))
{
    $sites = (bool)$_GET['sites'];
}
$isites = (int)$sites;
//get reported values (no validation needed, just cast to integer)
if (isset($_GET['refdel']))
{
    $refdel = (int)$_GET['refdel'];
    $bladd  = (isset($_GET['bladd'])) ? $bladd = (int)$_GET['bladd'] : 0;
}

// derive parameters for 'current' links
if (1 == $global)
{
    if ('' != $par) $par .= '&';
    $par .= 'global=1';
}
if (1 == $sites)
{
    if ('' != $par) $par .= '&';
    $par .= 'sites=1';
}

// -------------------------------------

// build query from chunks depending on criteria chosen

if ($loggedin)
{
    $query  = 'SELECT referrer';
    if ($sites)
    {
        // add 'host' = domain extracted from referrring URL using this algorithm:
        // find first char after http:// : LOCATE('//',referrer)+2
        // find first / after this: LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1
        // calculate length: (LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)
        // get host (standard): SUBSTRING(referrer FROM (LOCATE('//',referrer)+2) FOR ((LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)))
        // *or*
        // get host (MySQL-specific): SUBSTRING(SUBSTRING_INDEX(referrer,'/',3) FROM (LOCATE('//',referrer)+1))
        $protocol_host = 'SUBSTRING_INDEX(referrer,"/",3)';     # protocol and host: everything before first single /
        $start_host = 'LOCATE("//",referrer)+2';                # start position of host: after //
        $query .= ', SUBSTRING('.$protocol_host.' FROM ('.$start_host.')) AS host';
        // NOTE: COUNT() cannot use a derived column name but it *can* take an expression
        $query .= ', COUNT(SUBSTRING('.$protocol_host.' FROM ('.$start_host.'))) AS num';
        $query .= ' FROM '.$pre.'referrers';
        if (!$global)
        {
            $query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
        }
        #if ($days != $max_days)
        if ($days != DAYS_MAX)
        {
            $query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
            $query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days;          # filter by period
        }
        $query .= ' GROUP BY host ';
        if (isset($qs))
        {
            $query .= ' HAVING host '.$string_option." '%".$qs."%'";            # filter by string (derived column so we use HAVING)
        }
        if ($hits_option != HITS_MIN_OPTION || $h != 1)
        {
            $query .= (!strpos($query,'HAVING')) ? ' HAVING' : ' AND';
            $query .= ' num '.$hits_option.' '.$h;                          # filter by hits number (derived column so we use HAVING)
        }
    }
    else
    {
        $query  = 'SELECT referrer';
        $query .= ', COUNT(referrer) AS num';
        $query .= ' FROM '.$pre.'referrers';
        if (!$global)
        {
            $query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
        }
        if (isset($qs))
        {
            $query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
            $query .= ' referrer '.$string_option." '%".$qs."%'";           # filter by string
        }
        #if ($days != $max_days)
        if ($days != DAYS_MAX)
        {
            $query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
            $query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days;          # filter by period
        }
        $query .= ' GROUP BY referrer ';
        if ($hits_option != HITS_MIN_OPTION || $h != 1)
        {
            $query .= ' HAVING num '.$hits_option.' '.$h;                   # filter by hits number (derived column so we use HAVING)
        }
    }
    $query .= ' ORDER BY num DESC, referrer ASC';                           # set order

    // get total number of referrers (NOT records!)
    $query_refcount  = 'SELECT COUNT(DISTINCT(referrer)) AS total';         # @@@ referrer column should be indexed to make this really efficient
    $query_refcount .= ' FROM '.$pre.'referrers';
    if (!$global)
    {
        $query_refcount .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
    }
}

// -------------------------------------

// execute query (if logged in)

// @@@ NOTE: we don't use LoadReferrers any more since the query is now completely dynamically built
if ($loggedin)
{
    // execute query
    $referrers = $this->LoadAll($query);
    $totalrefs = $this->LoadSingle($query_refcount);
}

// -------------------------------------

// build UI elements

// define current target
$target = ($global) ? TARGET_GLOBAL : $this->Link(TARGET_PAGE);

// title
$title  = ($sites) ? sprintf(TITLE_SITES,$target) : sprintf(TITLE_REFERRERS,$target);
$title .= ($days <= HOURS_LIMIT) ? sprintf(LIST_PERIOD_HOURS,24*$days) : sprintf(LIST_PERIOD_DAYS,$days);

if ($isAdmin)
{
    if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
}

if ($loggedin)
{
    // results
    $tot = $totalrefs['total'];
    $total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
    $creferrers = count($referrers);
    if ($creferrers > 0)
    {
        $result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers);
    }
    else
    {
        $result = LIST_RESULT_NONE;
    }

    // menu elements: prevent wrapping within element (these *don't* use current target!
    $menu_referrers_page    = str_replace(' ',' ',MENU_REFERRERS_PAGE);
    $menu_sites_page        = str_replace(' ',' ',MENU_SITES_PAGE);
    $menu_referrers_global  = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
    $menu_sites_global      = str_replace(' ',' ',MENU_SITES_GLOBAL);
    $menu_blacklist         = str_replace(' ',' ',MENU_BLACKLIST);

    //menu links
    $m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
    $m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
    $m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
    $m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
    $m_blacklist = '<a href="'.$this->Href('review_blacklist').'">'.$menu_blacklist.'</a>';

    //build menu
    $menu = '<ul class="menu">'."\n";
    $menu .= '<li'.((!$global && !$sites)? ' class="active"' : '').'>'.$m_referrers_page.'</li>'."\n";
    $menu .= '<li'.((!$global && $sites)? ' class="active"' : '').'>'.$m_sites_page.'</li>'."\n";
    $menu .= '<li'.(($global && !$sites)? ' class="active"' : '').'>'.$m_referrers_global.'</li>'."\n";
    $menu .= '<li'.(($global && $sites)? ' class="active"' : '').'>'.$m_sites_global.'</li>'."\n";
    $menu .= '<li>'.$m_blacklist.'</li>'."\n";
    $menu .= '</ul>'."\n";
   
    // days dropdown content
    $daysopts = optionRanges($days_limits,DAYS_MAX);

    // form
    $form  = $this->FormOpen('referrers','','POST');        # @@@ add parameter for id
    $form .= '<fieldset class="hidden">'."\n";
    $form .= '<input type="hidden" name="global" value="'.$iglobal.'" />'."\n";
    $form .= '<input type="hidden" name="sites" value="'.$isites.'" />'."\n";
    $form .= '</fieldset>'."\n";
    $form .= '<fieldset>'."\n";
    $form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";

    $form .= '<label for="qo" class="mainlabel">'.(($sites) ? FORM_URL_OPT_SITES : FORM_URL_OPT_REFERRERS).'</label> '."\n";
    $form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
    $form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
    $form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
    $form .= '</select> '."\n";
    $form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
    $form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$qx.'" />';

    $form .= '<br />'."\n";

    $form .= '<label for="ho" class="mainlabel">'.FORM_HITS_OPT_LABEL.'</label> '."\n";
    $form .= '<select name="ho" id="ho" title="'.FORM_HITS_OPT_TITLE.'">'."\n";
    $form .= '<option value="1"'.(($ho == '1')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_1.'</option>'."\n";
    $form .= '<option value="0"'.(($ho == '0')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_0.'</option>'."\n";
    $form .= '</select> '."\n";
    $form .= '<input type ="text" name="h" id="h" title="'.FORM_HITS_NUM_TITLE.'" size="5" maxlength="5" value="'.$h.'" />'."\n";
    $form .= ' <label for="h">'.FORM_HITS_NUM_LABEL.'</label>';

    $form .= '<br />'."\n";

    $form .= '<label for="days" class="mainlabel">'.FORM_DAYS_OPT_LABEL.'</label> '."\n";
    $form .= '<select name="days" id="days" title="'.FORM_DAYS_OPT_TITLE.'">'."\n";
    // build drop-down
    foreach ($daysopts as $opt)
    {
        $selected = ($opt == $days) ? ' selected="selected"' : '';
        $form .= '<option value="'.$opt.'"'.$selected.'>'.$opt.'</option>';
    }
    $form .= '</select> '."\n";
    $form .= ' <label for="h">'.FORM_DAYS_NUM_LABEL.'</label>'."\n";

    $form .= '</fieldset>'."\n";

    $form .= '<input type="submit" name="'.(($sites) ? FORM_SUBMIT_SITES : FORM_SUBMIT_URLS).'" value="'.(($sites) ? FORM_SUBMIT_SITES : FORM_SUBMIT_URLS).'" accesskey="r" />'."\n";
    $form .= '<input type="submit" name="'.FORM_SUBMIT_SEARCH_TERMS.'" value="'.FORM_SUBMIT_SEARCH_TERMS_LABEL.'" accesskey="r" />'."\n";

    $form .= $this->FormClose();

    // referrers list with admin link for blacklisting
    if ($sites)
    {
        $summary  = ($isAdmin) ? sprintf(LIST_SUMMARY_SITES,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_SITES,'');
        $refshead = LIST_HEAD_LIST_SITES;
    }
    else
    {
        $summary  = ($isAdmin) ? sprintf(LIST_SUMMARY_REFERRERS,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_REFERRERS,'');
        $refshead = LIST_HEAD_LIST_REFERRERS;
    }
    if ($isAdmin && !isset($_POST[FORM_SUBMIT_SEARCH_TERMS]))
    {
        $redir = ($global||$sites) ? $this->GetHandler().'&'.$par : $this->GetHandler();    # ensure we return to the same view
        $par = ($sites) ? 'spam_site' : 'spam_link';
        $blacklisturl = $this->Href('delete_referrer','',$par.'=').'%s&redirect=%s';
        $blacklink = '<a class="keys" href="'.$blacklisturl.'" title="'.LIST_ACTION_BLACKLIST_TITLE.'">'.LIST_ACTION_BLACKLIST.'</a>';
    }

    // ids - use constant for variable-content heading
    $idTotal = $this->makeId('hn','total');
    $idResult = $this->makeId('hn','result');
}
$idTitle = $this->makeId('hn','title');

// -------------------------------------
// show user interface (pre-template)

if (isset($_POST[FORM_SUBMIT_SEARCH_TERMS])) // Modify title
{
    $title .= sprintf(TITLE_SEARCH_TERMS);
}
echo '<div class="page">'."\n";
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
# debug
if (DEBUG)
{
    echo 'Query (ref): '.$query.'<br />';
    echo 'Query (sites): '.$query_sites.'<br />';
    echo ($global) ? 'Global: TRUE<br />' : 'Global: FALSE<br />';
    echo ($sites)  ? 'Sites: TRUE<br />' : 'Sites: FALSE<br />';
}
# debug

if ($loggedin)
{
    if ($isAdmin && isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
    echo $menu."\n";
    echo '<div id="refbody">'."\n";
    echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
    echo '<div id="refform">'.$form.'</div>'."\n";  # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
    if(isset($_POST[FORM_SUBMIT_SEARCH_TERMS]))
    {
        echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
        echo '<table id="reflist" class="data" summary="'.$summary.'">'."\n";
        echo '<thead>';
        echo '<tr><th class="search_term" scope="col">'.LIST_HEAD_SEARCH_TERM.'</th>';
        echo '<th class="freq" scope="col">'.LIST_HEAD_FREQ.'</th></tr>'."\n";
        echo '</thead>'."\n";
        echo '<tbody>'."\n";

        $search_terms = array();
        foreach ($referrers as $referrer)
        {
            $hits   = $referrer['num'];
            if ($sites)
            {
                $ref    = $this->htmlspecialchars_ent($referrer['host']);
            }
            else
            {
                $ref    = $this->htmlspecialchars_ent($referrer['referrer']);
            }
            // Parse q= attributes from Google refs
            //if (0 == preg_match('/http:\/\/.*google.*?\//', $ref))
            if (0 == preg_match('/q=(.*?)[& ]/', $ref))
            {
                continue;
            }
            else
            {
                $results = array();
                $num_results = preg_match('/q=(.*?)[& ]/', $ref, $results);
                if(0 == $num_results)
                {
                    continue;
                }
                else
                {
                    $results2 = explode("+", strtolower($results[1]));
                    foreach($results2 as $result)
                    {
                        $search_terms[$result] += $hits;
                    }
                }
            }
        }
        arsort($search_terms);

        // Output search terms
        foreach($search_terms as $key=>$val)
        {
            echo '<tr'.(($r%2)? '' : ' class="alt"').'>'."\n"; #enable alternate row color          echo '<td class="hits">'.$hits.'</td>';
            echo '<td class="hits">'.$key.'</td>';
            echo '<td class="refs">'.$val.'</td>';
            echo '</tr>'."\n";
            $r++;
        }
        echo '</tbody>'."\n";
        echo '</table>'."\n";
    }
    else if ($creferrers != 0)
    {
        echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
        echo '<table id="reflist" class="data" summary="'.$summary.'">'."\n";
        echo '<thead>';
        echo '<tr><th class="hits" scope="col">'.LIST_HEAD_HITS.'</th>';
        if ($isAdmin) echo '<th class="action c2" scope="col">'.LIST_HEAD_ACTION.'</th>';
        echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
        echo '</thead>'."\n";
        echo '<tbody>'."\n";

        foreach ($referrers as $referrer)
        {
            $hits   = $referrer['num'];
            if ($sites)
            {
                $ref    = $this->htmlspecialchars_ent($referrer['host']);
            }
            else
            {
                $ref    = $this->htmlspecialchars_ent($referrer['referrer']);
            }
            echo '<tr'.(($r%2)? '' : ' class="alt"').'>'."\n"; #enable alternate row color          echo '<td class="hits">'.$hits.'</td>';
            echo '<td class="hits">'.$hits.'</td>';
            if ($isAdmin) echo '<td class="action c2">'.sprintf($blacklink,$ref,$redir).'</td>';
            if ($sites)
            {
                echo '<td class="refs">'.$ref.'</td>';
            }
            else
            {
                echo '<td class="refs"><a href="'.$ref.'">'.$ref.'</a></td>';
            }
            echo '</tr>'."\n";
            $r++;
        }

        echo '</tbody>'."\n";
        echo '</table>'."\n";
    }
    else
    {
        echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
        echo '<p><em class="error">'.(($sites) ? sprintf(NONE_NOTE_SITES) : sprintf(NONE_NOTE_REFERRERS)).'</em></p>'."\n";
    }
}
else
{
    echo '<p><em class="error">'.LOGIN_NOTE.'</em></p>'."\n";
}
echo '</div>'."\n";
echo '</div>'."\n";
?>


Usage
Point your browser to HomePage/referrers.
Select the Referrers to this site tab.
Modify the search parameters to your preference.
Click the Rank Search Terms button for a list of search terms sorted by frequency.