Go Ahead... Choose Your Parent!
Although wikis tend to have a flat web-like structure, it would still be nice if we could specify an "official parent" on a per-page basis. However, rather than building from the bottom up, which would require parents to choose their "most favorite" child, we'll let a child choose its parent instead.
Since we want this to run on versions of MySQL that don't support subqueries, we'll have to figure out a way to cache each page's "family tree," rebuilding only when it becomes necessary. I think the current solution works well enough, but it hasn't been tested much and I don't know how well it will hold up on a busy wiki.
The Data Model
CREATE TABLE `wikka_parents` (
`page_tag` varchar(75) NOT NULL default '',
`parents` mediumtext NOT NULL,
`time` datetime NOT NULL default '0000-00-00 00:00:00',
KEY `page_tag` (`page_tag`)
) TYPE=MyISAM;
`page_tag` varchar(75) NOT NULL default '',
`parents` mediumtext NOT NULL,
`time` datetime NOT NULL default '0000-00-00 00:00:00',
KEY `page_tag` (`page_tag`)
) TYPE=MyISAM;
The Code
Save as "parent.php" in the actions directory...
<?php
// Examples
// {{parent page="HomePage"}} - set HomePage as the parent
// {{parent page="HomePage" label="<b>Current Location:</b>"}} -- add a prefix to the output
// Return a div with the id set to parent
global $table_pages, $table_parents;
$table_pages = $this->config['table_prefix'] . 'pages';
$table_parents = $this->config['table_prefix'] . 'parents';
function update_parents(&$wikka, $tag)
{
static $children = array();
global $table_pages, $table_parents;
if ($row = $wikka->LoadSingle("SELECT parents, time FROM $table_parents WHERE page_tag = '$tag'"))
{
$parents = $row['parents'];
$last_updated = $row['time'];
}
else
{
$parents = $last_updated = false;
}
// check to see if pages have changed since the last time we updated the parent info
// if so, we'll have to update any parent tags we encounter
// including this page's parent's parents and so on
if ($last_updated) $updated_pages = $wikka->LoadAll("SELECT tag FROM $table_pages WHERE time > '$last_updated'");
if ($updated_pages || !$last_updated)
{
// fetch the body of this page and check it for a parent action
// ignore the action if it specifies a child item as its parent
$row = $wikka->LoadSingle("SELECT body FROM $table_pages WHERE tag = '$tag' AND latest = 'Y'");
$wikka_body = $row['body'];
$parent_tag = preg_match('/{{.*parent[^}]+page="(.+)"/iU', $wikka_body, $match) ? $match[1] : false;
array_unshift($children, $tag);
if ($parent_tag && !in_array($parent_tag, $children))
{
// remove circular references from the tree
$parents = preg_replace("/.*$tag:/", '', update_parents($wikka, $parent_tag));
$retval = "$parents:$tag";
$wikka->Query("UPDATE $table_parents SET parents = '$retval', time = NOW() WHERE page_tag = '$tag'");
if (!mysql_affected_rows()) $wikka->Query("INSERT INTO $table_parents (page_tag, parents, time) VALUES ('$tag', '$retval', NOW())");
}
else
{
$retval = $tag;
}
array_shift($children);
}
elseif ($last_updated && !$updated_pages)
{
$retval = ($row = $wikka->LoadSingle("SELECT parents FROM $table_parents WHERE page_tag = '$tag'")) ? $row['parents'] : '';
}
else
{
$retval = '';
}
return $retval;
}
$label = isset($vars['label']) ? $vars['label'] : '';
$parents = update_parents($this, $this->tag);
$parents = split(':', $parents);
foreach ($parents as $tag)
{
$url = $this->Href('', $tag);
$links[] = $tag == $this->tag ? $tag : "<a href=\"$url\">$tag</a>";
}
echo '<div id="parent">' . $label . join(' » ', $links) . '</div>';
?>
// Examples
// {{parent page="HomePage"}} - set HomePage as the parent
// {{parent page="HomePage" label="<b>Current Location:</b>"}} -- add a prefix to the output
// Return a div with the id set to parent
global $table_pages, $table_parents;
$table_pages = $this->config['table_prefix'] . 'pages';
$table_parents = $this->config['table_prefix'] . 'parents';
function update_parents(&$wikka, $tag)
{
static $children = array();
global $table_pages, $table_parents;
if ($row = $wikka->LoadSingle("SELECT parents, time FROM $table_parents WHERE page_tag = '$tag'"))
{
$parents = $row['parents'];
$last_updated = $row['time'];
}
else
{
$parents = $last_updated = false;
}
// check to see if pages have changed since the last time we updated the parent info
// if so, we'll have to update any parent tags we encounter
// including this page's parent's parents and so on
if ($last_updated) $updated_pages = $wikka->LoadAll("SELECT tag FROM $table_pages WHERE time > '$last_updated'");
if ($updated_pages || !$last_updated)
{
// fetch the body of this page and check it for a parent action
// ignore the action if it specifies a child item as its parent
$row = $wikka->LoadSingle("SELECT body FROM $table_pages WHERE tag = '$tag' AND latest = 'Y'");
$wikka_body = $row['body'];
$parent_tag = preg_match('/{{.*parent[^}]+page="(.+)"/iU', $wikka_body, $match) ? $match[1] : false;
array_unshift($children, $tag);
if ($parent_tag && !in_array($parent_tag, $children))
{
// remove circular references from the tree
$parents = preg_replace("/.*$tag:/", '', update_parents($wikka, $parent_tag));
$retval = "$parents:$tag";
$wikka->Query("UPDATE $table_parents SET parents = '$retval', time = NOW() WHERE page_tag = '$tag'");
if (!mysql_affected_rows()) $wikka->Query("INSERT INTO $table_parents (page_tag, parents, time) VALUES ('$tag', '$retval', NOW())");
}
else
{
$retval = $tag;
}
array_shift($children);
}
elseif ($last_updated && !$updated_pages)
{
$retval = ($row = $wikka->LoadSingle("SELECT parents FROM $table_parents WHERE page_tag = '$tag'")) ? $row['parents'] : '';
}
else
{
$retval = '';
}
return $retval;
}
$label = isset($vars['label']) ? $vars['label'] : '';
$parents = update_parents($this, $this->tag);
$parents = split(':', $parents);
foreach ($parents as $tag)
{
$url = $this->Href('', $tag);
$links[] = $tag == $this->tag ? $tag : "<a href=\"$url\">$tag</a>";
}
echo '<div id="parent">' . $label . join(' » ', $links) . '</div>';
?>
The Examples
{{parent page="HomePage"}} - set HomePage as the parent {{parent page="HomePage" label="<b>Current Location:</b>"}} -- add a prefix to the output
The Screenshot
In case you're wondering why the links don't look like standard wiki links, it's because I'm using the UncamelAction in my setup.
Authors
DennyShimkoski
CategoryUserContributions