=====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==== %%(mysql) 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; %% ====The Code==== Save as "parent.php" in the actions directory... %%(php) Current Location:"}} -- 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 : "$tag"; } echo '
' . $label . join(' » ', $links) . '
'; ?> %% ====The Examples==== %% {{parent page="HomePage"}} - set HomePage as the parent {{parent page="HomePage" label="Current Location:"}} -- add a prefix to the output %% ====The Screenshot==== {{image alt="Screenshot of the Parent action's output" url="http://bytebrite.com/img/pss.gif"}} 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