Custom sitemap entries with SMF and Sitemap

After many people asking for the mod to support other types of mods, I’ve finally implemented the ability for mod authors to plug-in to Sitemap with their own sitemap type items.

First things first, create the file that will house your plug-in. The filename must follow this pattern: sitemap_[your_type].php. The [your_type] should be changed to the name of the type you want to show (ie: ‘boards’ or ‘topics’). In my example, I am showing how to do the ‘topics’ section. I’ve named my file sitemap_topics.php.

The next step is to create the contents of the file. To have a displayable sitemap with content for normal users, you must implement a ‘Display’ method, named with a capitalized first letter of the type, followed by ‘Display’ (ie: ‘TopicsDisplay’). If you want a displayable option, you will also need a text string added to Modifications.english.php in the form of $txt[‘sitemap_[your_type]’] = ‘Text string'; as well (ie: $txt[‘sitemap_topics’] = ‘Topics';). To have XML content, you must implement a ‘XML’ method, named with a capitalized first letter of the type, followed by ‘XML’ (ie: ‘TopicsXML’).

[code lang=”php” smarttabs=”true” wraplines=”false”]<?php
/**
* Functions to handle topics in the Sitemap
*
* @author Matt Zuba
* @website http://www.mattzuba.com
* @mod Core
*/

/**
* This function creates an array of $listOptions which will then be passed
* to the list creator in SMF’s Subs-List createList function.
* The indicies that will be overloaded are ‘id’, ‘title’, ‘base_href’ and
* ‘additional_rows’. You may included any others you like/need.
*
* @return array Compiled array of list options to pass to the list creator
*/
function TopicsDisplay()
{
global $scripturl, $txt, $mbname;

// Create the list
$listOptions = array(
‘items_per_page’ => 100,
‘no_items_label’ => $txt[‘sitemap_topic_none’],
‘get_items’ => array(
‘function’ => ‘list_getTopics’,
),
‘get_count’ => array(
‘function’ => ‘list_getNumTopics’,
),
‘columns’ => array(
‘subject’ => array(
‘header’ => array(
‘value’ => $txt[‘topic’],
),
‘data’ => array(
‘sprintf’ => array(
‘format’ => ‘[<a href="’ . $scripturl . ‘?board=%d.0">%s</a>] <a href="’ . $scripturl . ‘?topic=%d.0">%s</a>’,
‘params’ => array(
‘id_board’ => false,
‘name’ => false,
‘id_topic’ => false,
‘subject’ => false,
),
),
),
),
‘poster’ => array(
‘header’ => array(
‘value’ => $txt[‘started_by’],
),
‘data’ => array(
‘db’ => ‘poster’,
),
),
‘views’ => array(
‘header’ => array(
‘value’ => $txt[‘views’],
),
‘data’ => array(
‘db’ => ‘num_views’,
‘style’ => ‘text-align: center;’,
),
),
‘replies’ => array(
‘header’ => array(
‘value’ => $txt[‘replies’],
),
‘data’ => array(
‘db’ => ‘num_replies’,
‘style’ => ‘text-align: center;’,
),
),
),
);

return $listOptions;
}

/**
* This function creates an array of items which will then be passed
* to the xml output template. Each item of the array returned should
* have the following information:
* array(
* ‘url’ => the URL to the item in question,
* ‘time’ => the last time this was updated in iso8601 date format,
* ‘priority’ => the priority of this item,
* ‘changefreq’ => the frequency this item changes (Optional),
* );
*
* date_iso8601() and priority() both take unix timestamps as arguments
* changefreq() takes a unix timestamp and number of updates as arguments
*
* It is heavily recommended to cache this data. This data should also only
* reflect what a guest would see. $user_info[‘query_see_board’] is already
* set to what a guest would have.
*
* @return array Compiled array of options
*/
function TopicsXML()
{
global $modSettings, $scripturl;

if (($topics = cache_get_data(‘xml_topics’, $modSettings[‘sitemap_cache_ttl’])) == null)
{
$temp_topics = list_getTopics(0, $modSettings[‘sitemap_topic_count’], ‘m.poster_time DESC’);
// Assign it to the array
$topics = array();
foreach ($temp_topics as $row)
{
$topics[] = array(
‘url’ => fix_possible_url($scripturl . ‘?topic=’ . $row[‘id_topic’] . ‘.0′),
‘time’ => date_iso8601($row[‘poster_time’]),
‘priority’ => priority($row[‘poster_time’]),
‘changefreq’ => changefreq($row[‘first_time’], $row[‘num_replies’]),
);
}
cache_put_data(‘xml_topics’, $topics, $modSettings[‘sitemap_cache_ttl’]);
}

return $topics;
}

function list_getTopics($start, $items_per_page, $sort)
{
global $smcFunc;

$query_limit = !empty($items_per_page) ? ‘LIMIT {int:start}, {int:per_page}’ : ”;
$query_limit_params = !empty($items_per_page) ? array(‘start’ => $start, ‘per_page’ => $items_per_page) : array();

$request = $smcFunc[‘db_query’](”,’
SELECT t.id_topic, t.num_replies, t.num_views, t.id_board,
m.subject, IFNULL(mem.real_name, m.poster_name) as poster, b.name,
m.poster_time as first_time, mes.poster_time
FROM {db_prefix}topics as t
INNER JOIN {db_prefix}messages as m ON (m.id_msg = t.id_first_msg)
INNER JOIN {db_prefix}boards as b ON (b.id_board = t.id_board)
INNER JOIN {db_prefix}messages as mes ON (mes.id_msg = t.id_last_msg)
LEFT JOIN {db_prefix}members as mem ON (mem.id_member = t.id_member_started)
WHERE {query_see_board}
ORDER BY {raw:sort}
‘ . $query_limit,
array_merge($query_limit_params, array(
‘sort’ => $sort == ‘1=1′ ? ‘t.id_topic DESC’ : $sort,
))
);

$topics = array();
while ($row = $smcFunc[‘db_fetch_assoc’]($request))
$topics[] = $row;
$smcFunc[‘db_free_result’]($request);

return $topics;
}

function list_getNumTopics()
{
global $smcFunc;

// Get the total topics ($modSettings[‘totalTopics’] isn’t reliable for us) and create the page index
$request = $smcFunc[‘db_query’](”,’
SELECT COUNT(*)
FROM {db_prefix}topics as t
INNER JOIN {db_prefix}boards as b ON (b.id_board = t.id_board)
WHERE {query_see_board}’
);

list($numTopics) = $smcFunc[‘db_fetch_row’]($request);
$smcFunc[‘db_free_result’]($request);

return $numTopics;
}[/code]

The best way to allow users to install these is via SMF’s package manager. Below is a sample package-info.xml file that can be used. If you choose to create your own, or include it with your own mod install, you must at least have the code to invalidate the sitemap_extension cache (see the <code> tag in the sample below). The directory to place the extension into should be $sourcedir/Sitemap-Ext.

[code lang=”xml” smarttabs=”true” wraplines=”false”]<?xml version="1.0"?>
<!DOCTYPE package-info SYSTEM "http://www.simplemachines.org/xml/package-info">

<package-info xmlns="http://www.simplemachines.org/xml/package-info" xmlns:smf="http://www.simplemachines.org/">
<id>slammeddime:sitemap_topics</id>
<name>Sitemap Topics Extension</name>
<version>1.0</version>
<type>modification</type>

<install for="2.0 RC4">
<readme parsebbc="true">readme.txt</readme>
<code type="inline"><![CDATA[cache_put_data(‘sitemap_extensions’, NULL, 3600);]]></code>
<require-file name="sitemap_topics.php" destination="$sourcedir/Sitemap-Ext" />
</install>

<uninstall for="2.0 RC4">
<code type="inline"><![CDATA[cache_put_data(‘sitemap_extensions’, NULL, 3600);]]></code>
<remove-file name="$sourcedir/Sitemap-Ext/sitemap_topics.php" />
</uninstall>
</package-info>
[/code]

Now you just need to package it up into a .zip or .tar.gz file and users can easily install this into their SMF install while using Sitemap.

Keep in mind that you should NOT build your code around this mod. You should already have a functional mod before attempting to create your own custom lists.