add('name', PLUGIN_EVENT_FREETAG_TITLE);
$propbag->add('description', PLUGIN_EVENT_FREETAG_DESC);
$propbag->add('stackable', false);
$propbag->add('author', 'Garvin Hicking, Jonathan Arkell, Grischa Brockhaus, Lars Strojny, Malte Paskuda');
$propbag->add('requirements', array(
'serendipity' => '0.8',
'smarty' => '2.6.7',
'php' => '4.1.0'
));
$propbag->add('version', '3.46');
$propbag->add('event_hooks', array(
'frontend_fetchentries' => true,
'frontend_fetchentry' => true,
'frontend_display:rss-2.0:per_entry' => true,
'frontend_header' => true,
// 'frontend_display:rss-0.92:per_entry' => true,
'frontend_display:rss-1.0:per_entry' => true,
// 'frontend_display:rss-0.91:per_entry' => true,
'frontend_display:atom-0.3:per_entry' => true,
'frontend_display:atom-1.0:per_entry' => true,
'frontend_entryproperties' => true,
'frontend_rss' => true,
'entry_display' => true,
'entries_header' => true,
'backend_publish' => true,
'backend_save' => true,
'backend_display' => true,
'backend_sidebar_entries' => true,
'backend_sidebar_entries_event_display_managetags' => true,
'backend_delete_entry' => true,
'external_plugin' => true,
'xmlrpc_updertEntry' => true,
'xmlrpc_fetchEntry' => true,
'xmlrpc_deleteEntry' => true,
'css' => true,
));
$propbag->add('groups', array('BACKEND_EDITOR'));
$this->supported_properties = array('freetag_name', 'freetag_tagList');
$this->dependencies = array('serendipity_plugin_freetag' => 'keep');
$propbag->add('configuration', array('cat2tag', 'keyword2tag', 'taglink', 'embed_footer', 'extended_smarty', 'show_tagcloud', 'min_percent', 'max_percent', 'max_tags', 'use_flash', 'flash_tag_color', 'flash_bg_trans', 'flash_bg_color', 'flash_width', 'flash_speed', 'meta_keywords', 'show_related', 'show_related_count', 'lowercase_tags', 'collation', 'send_http_header', 'admin_show_taglist', 'admin_ftayt', 'technorati_tag_link', 'technorati_tag_image'));
}
function introspect_config_item($name, &$propbag) {
global $serendipity;
switch($name) {
case 'show_tagcloud':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_SHOW_TAGCLOUD);
$propbag->add('description', '');
$propbag->add('default', true);
break;
case 'cat2tag':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_CAT2TAG);
$propbag->add('description', PLUGIN_EVENT_FREETAG_CAT2TAG_DESC);
$propbag->add('default', false);
break;
case 'keyword2tag':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_KEYWORD2TAG);
$propbag->add('description', PLUGIN_EVENT_FREETAG_KEYWORD2TAG_DESC);
$propbag->add('default', false);
break;
case 'embed_footer':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_FREETAG_EMBED_FOOTER);
$propbag->add('description', PLUGIN_EVENT_FREETAG_EMBED_FOOTER_DESC . ' ' . PLUGIN_EVENT_FREETAG_EMBED_FOOTER_DESC2);
$propbag->add('select_values', array(
'yes' => YES,
'no' => NO,
'smarty' => 'Smarty'
));
$propbag->add('default', 'true');
break;
case 'extended_smarty':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_EXTENDED_SMARTY);
$propbag->add('description', PLUGIN_EVENT_FREETAG_EXTENDED_SMARTY_DESC);
$propbag->add('default', false);
break;
case 'taglink':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_TAGLINK);
$propbag->add('description', '');
$propbag->add('default', $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/tag/');
break;
case 'min_percent':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_TAGCLOUD_MIN);
$propbag->add('description', '');
$propbag->add('default', '100');
break;
case 'max_percent':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_TAGCLOUD_MAX);
$propbag->add('description', '');
$propbag->add('default', '300');
break;
case 'collation':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_COLLATION);
$propbag->add('description', '');
$propbag->add('default', '');
break;
case 'max_tags':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_FREETAG_MAX_TAGS);
$propbag->add('description', '');
$propbag->add('default', '45');
break;
case 'meta_keywords':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_FREETAG_META_KEYWORDS);
$propbag->add('description', '');
$propbag->add('default', '0');
break;
case 'show_related':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_SHOW_RELATED);
$propbag->add('description', '');
$propbag->add('default', true);
break;
case 'show_related_count':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_SHOW_RELATED_COUNT);
$propbag->add('description', '');
$propbag->add('default', '5');
break;
case 'lowercase_tags':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_LOWERCASE_TAGS);
$propbag->add('description', '');
$propbag->add('default', true);
break;
case 'send_http_header':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_SEND_HTTP_HEADER);
$propbag->add('description', '');
$propbag->add('default', true);
break;
case 'admin_show_taglist':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_ADMIN_TAGLIST);
$propbag->add('description', '');
$propbag->add('default', true);
break;
case 'admin_ftayt':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_ADMIN_FTAYT);
$propbag->add('description', '');
$propbag->add('default', false);
break;
case 'technorati_tag_link':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_TECHNORATI_TAGLINK);
$propbag->add('description', PLUGIN_EVENT_FREETAG_TECHNORATI_TAGLINK_DESC);
$propbag->add('default', false);
break;
case 'technorati_tag_image':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_TECHNORATI_TAGLINK_IMG);
$propbag->add('description', '');
$propbag->add('default', 'http://static.technorati.com/static/img/pub/icon-utag-16x13.png');
break;
case 'use_flash':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_USE_FLASH);
$propbag->add('description', '');
$propbag->add('default', false);
break;
case 'flash_bg_trans':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_FREETAG_FLASH_TRANSPARENT);
$propbag->add('description', '');
$propbag->add('default', false);
break;
case 'flash_tag_color':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_FLASH_TAG_COLOR);
$propbag->add('description', '');
$propbag->add('default', 'ff6600');
break;
case 'flash_bg_color':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_FLASH_BG_COLOR);
$propbag->add('description', '');
$propbag->add('default', 'ffffff');
break;
case 'flash_width':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_FLASH_WIDTH);
$propbag->add('description', '');
$propbag->add('default', '500');
break;
case 'flash_speed':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_FREETAG_FLASH_SPEED);
$propbag->add('description', '');
$propbag->add('default', '100');
break;
}
return true;
}
function generate_content(&$title) {
$title = $this->title;
}
static function tableCreated($table = 'entrytags') {
global $serendipity;
$q = "select count(tag) from {$serendipity['dbPrefix']}" . $table;
$row = serendipity_db_query($q, true, 'num');
if (!is_numeric($row[0])) { // if the response we got back was an SQL error.. :P
return false;
} else {
return true;
}
}
static function upgradeFromVersion1() {
global $serendipity;
$q = "select count(*) from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
$result = serendipity_db_query($q);
if ((int)$result[0] > 0) {
return true;
} else {
return false;
}
}
static function convertEntryPropertiesTags() {
global $serendipity;
$q = "select entryid, value from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
$result = serendipity_db_query($q);
if (!is_array($result)) {
return false;
}
foreach($result as $entry) {
$tags = serendipity_event_freetag::makeTagsFromTaglist($entry['value']);
serendipity_event_freetag::addTagsToEntry($entry['entryid'], $tags);
printf(PLUGIN_FREETAG_UPGRADE1_2, count($tags), $entry['entryid']);
echo '
';
}
$q = "delete from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
$result = serendipity_db_query($q);
}
function cleanup() {
global $serendipity;
serendipity_event_freetag::static_install();
}
function install() {
serendipity_event_freetag::static_install();
}
static function static_install() {
global $serendipity;
if (!serendipity_event_freetag::tableCreated('entrytags')) {
$q = "create table {$serendipity['dbPrefix']}entrytags (" .
"entryid int(10) not null, " .
"tag varchar(50) not null, " .
"primary key (entryid, tag)" .
")";
$result = serendipity_db_schema_import($q);
if ($result !== true) {
return;
}
serendipity_db_schema_import("CREATE INDEX tagsentryindex ON {$serendipity['dbPrefix']}entrytags (entryid)");
serendipity_db_schema_import("CREATE INDEX tagsTagIndex ON {$serendipity['dbPrefix']}entrytags (tag)");
}
if (!serendipity_event_freetag::tableCreated('tagkeywords')) {
$q = "create table {$serendipity['dbPrefix']}tagkeywords (" .
"keywords text, " .
"tag varchar(50) not null, " .
"primary key (tag)" .
")";
$result = serendipity_db_schema_import($q);
}
if (serendipity_event_freetag::upgradeFromVersion1()) {
serendipity_event_freetag::convertEntryPropertiesTags();
} else {
echo "NOT UPGRADING!";
}
}
static function makeURLTag($tag) {
return str_replace('.', '%FF', urlencode($tag));
}
function getTagHtmlFromCSV($tagString) {
global $serendipity;
static $taglink = null;
if ($taglink == null) {
$taglink = $this->get_config('taglink');
}
$links = array();
if (empty($tagString)) {
return array();
}
$tags = explode(',', $tagString);
foreach($tags as $tag) {
$tag = trim($tag);
if (empty($tag)) {
continue;
}
$links[] = '' . htmlspecialchars($tag) . '';
}
return implode(', ', $links);
}
function getTagHtml($tags, $extended_smarty = false) {
global $serendipity;
static $taglink = null;
$links = array();
if ($taglink == null) {
$taglink = $this->get_config('taglink');
}
if (!is_array($tags)) {
return '';
}
$technorati = $this->get_config('technorati_tag_link');
$technorati_img = $this->get_config('technorati_tag_image');
$img_url = $this->get_config('path_img',$serendipity['serendipityHTTPPath'] . 'plugins/serendipity_event_freetag/img/');
foreach($tags as $tag) {
$tag = trim($tag);
if (empty($tag)) {
continue;
}
$links[] = '' . htmlspecialchars($tag) . '' .
($technorati?'':'');
}
if ($extended_smarty) {
return $links;
} else {
return implode(', ', $links);
}
}
function getRelatedEntries($tags, $postID) {
global $serendipity;
if (!is_array($tags)) {
return false;
}
foreach($tags AS $idx => $tag) {
$tags[$idx] = serendipity_db_escape_string($tag);
}
$q = "SELECT DISTINCT e1.entryid,
e2.title,
e2.timestamp
FROM {$serendipity['dbPrefix']}entrytags AS e1
LEFT JOIN {$serendipity['dbPrefix']}entries AS e2
ON e1.entryid = e2.id
WHERE e1.tag IN ('" . implode("', '", $tags) . "')
AND e1.entryid != " . (int)$postID . "
AND e2.isdraft = 'false'
" . (!serendipity_db_bool($serendipity['showFutureEntries']) ? " AND e2.timestamp <= " . time() : '') . "
ORDER BY e2.timestamp DESC
LIMIT " . $this->get_config('show_related_count', 10);
$result = serendipity_db_query($q, false, 'assoc', false, 'entryid', 'title');
if (!is_array($result)) {
return false;
}
return $result;
}
function getRelatedEntriesHtml(&$entries, $extended_smarty = false) {
global $serendipity;
if (!is_array($entries)) {
return false;
}
$entrylink = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '/');
if ($extended_smarty) {
$return = array();
$return['description'] = PLUGIN_EVENT_FREETAG_RELATED_ENTRIES;
foreach($entries AS $entryid => $title) {
$return['entries'][] = '' . htmlspecialchars($title) . '';
}
} else {
$return = '
';
}
return $return;
}
/* This method can be called statically.
Tags should be an array with the key being the tag name, and val being
the number of occurances. */
static function displayTags($tags, $xml, $nl, $scaling, $maxSize = 200, $minSize = 100, $useFlash = false, $flashbgtrans = true, $flashtagcolor = 'ff6600', $flashbgcolor = 'ffffff', $flashwidth = 190, $flashspeed = 100, $cfg_taglink, $cfg_template, $xml_image = 'img/xml.gif')
{
global $serendipity;
if (!is_array($tags)) {
return false;
}
static $taglink = null;
if ($taglink == null) {
$taglink = $cfg_taglink;
}
$template = $cfg_template;
if (!$template) {
serendipity_event_freetag::renderTags($tags, $xml, $nl, $scaling, $maxSize, $minSize, $useFlash, $flashbgtrans, $flashtagcolor, $flashbgcolor, $flashwidth, $flashspeed, $taglink, $xml_image);
} else {
arsort($tags);
$tagsWithLinks = array();
foreach ($tags as $tag => $count) {
$tagsWithLinks[$tag] = array(
'count' => $count,
'href' => $taglink . serendipity_event_freetag::makeUrlTag($tag),
);
}
$serendipity['smarty']->assign('tags', $tagsWithLinks);
$template = serendipity_getTemplateFile($template, 'serendipityPath');
$serendipity['smarty']->display($template);
}
return true;
}
static function renderTags($tags, $xml, $nl, $scaling, $maxSize, $minSize, $useFlash, $flashbgtrans, $flashtagcolor, $flashbgcolor, $flashwidth, $flashspeed, $taglink, $xml_image = 'img/xml.gif')
{
global $serendipity;
$rsslink = $serendipity['serendipityHTTPPath'] . 'rss.php?serendipity%5Btag%5D=';
$xmlImg = serendipity_getTemplateFile($xml_image);
$first = true;
$biggest = max($tags);
$smallest= min($tags);
$scale = $biggest - $smallest;
if ($scale < 0) {
$scale = 1;
}
$key = uniqid(rand());
if ($useFlash) {
echo ''. "\n";
echo "\n". '
'. "\n";
echo '
'. "\n";
}
}
function event_hook($event, &$bag, &$eventData, $addData = null) {
global $serendipity;
$hooks = &$bag->get('event_hooks');
if (isset($hooks[$event])) {
switch($event) {
case 'backend_delete_entry':
$this->deleteTagsForEntry((int)$eventData);
return true;
case 'frontend_header':
if (serendipity_db_bool($this->get_config('use_flash'))) {
echo ''. "\n";
echo ''. "\n";
}
$this->displayMetaKeywords($serendipity['GET']['id'], $this->displayTag );
return true;
case 'frontend_display:rss-2.0:per_entry':
case 'frontend_display:rss-0.91:per_entry':
$eventData['display_dat'] .= $this->getFeedXmlForTags('category', $eventData['properties']['freetag_tags']);
return true;
case 'frontend_display:rss-1.0:per_entry':
case 'frontend_display:rss-0.91:per_entry':
case 'frontend_display:atom-0.3:per_entry':
case 'frontend_display:atom-1.0:per_entry':
$eventData['display_dat'] .= $this->getFeedXmlForTags('dc:subject', $eventData['properties']['freetag_tags']);
return true;
case 'external_plugin':
$uri_parts = explode('?', str_replace(array('&', '%FF'), array('&', '.'), $eventData));
$param = explode('/', $uri_parts[0]);
$plugincode = array_shift($param);
if (($plugincode == "tag") || ($plugincode == "tags") || ($plugincode == "freetag")) {
/* Attempt to locate hidden variables within the URI */
foreach ($serendipity['uriArguments'] as $k => $v) {
if ($v[0] == 'P') { /* Page */
$page = substr($v, 1);
if (is_numeric($page)) {
$serendipity['GET']['page'] = $page;
unset($serendipity['uriArguments'][$k]);
if ($param[count($param)-1] == "P{$page}.html") {
array_pop($param); // knock it off of the param array as well
}
}
}
}
if (count($param) == 0 || empty($param[0])) {
$serendipity['head_subtitle'] = PLUGIN_EVENT_FREETAG_ALLTAGS;
$this->displayTag = true;
$param = null;
} else if (count($param) == 1) {
$param = urldecode($param[0]);
$serendipity['head_subtitle'] = sprintf(PLUGIN_EVENT_FREETAG_USING, htmlspecialchars($param));
$emit_404 = true;
} else {
$serendipity['head_subtitle'] = sprintf(PLUGIN_EVENT_FREETAG_USING, implode(' + ', array_map('htmlspecialchars', $param)));
$param = array_map('urldecode', $param);
$emit_404 = true;
}
$this->tags['show'] = $param;
$serendipity['plugin_vars']['tag'] = $param;
if (is_array($param)) {
@define('PLUGIN_VARS_TAG', implode(',', $param));
} else {
@define('PLUGIN_VARS_TAG', $param);
}
$serendipity['GET']['subpage'] = $eventData;
unset($serendipity['GET']['category']); // No restriction should be enforced here.
include_once(S9Y_INCLUDE_PATH . 'include/genpage.inc.php');
if ($emit_404 && $this->TaggedEntries !== null && $this->TaggedEntries < 1) {
@header('HTTP/1.0 404 Not found');
@header('Status: 404 Not found');
if (serendipity_db_bool($this->get_config('send_http_header', true))) {
@header('X-FreeTag: not found');
}
} else {
if (serendipity_db_bool($this->get_config('send_http_header', true))) {
@header('X-FreeTag: ' . $this->TaggedEntries);
}
}
$raw_data = ob_get_contents();
ob_end_clean();
$serendipity['smarty']->assign('raw_data', $raw_data);
serendipity_gzCompression();
$serendipity['smarty']->display(serendipity_getTemplateFile($serendipity['smarty_file'], 'serendipityPath'));
@define('NO_EXIT', true);
}
break;
case 'backend_sidebar_entries':
?>
eventData = $eventData;
$this->displayManageTags($event, $bag, $eventData, $addData);
return true;
break;
case 'backend_publish':
case 'backend_save':
if (function_exists('mb_internal_encoding')) {
mb_internal_encoding(LANG_CHARSET);
}
if (!isset($eventData['id'])) {
return true;
}
$to_lower = serendipity_db_bool($this->get_config('lowercase_tags'));
$keylist = serendipity_db_query("SELECT tag, keywords FROM {$serendipity['dbPrefix']}tagkeywords", false, 'assoc');
$automatted = array(array());
if (is_array($keylist)) {
foreach($keylist AS $key) {
$keywords = explode(',', $key['keywords']);
foreach($keywords AS $keyword) {
$automatted[trim($keyword)][$key['tag']] = true;
}
}
}
$tags = $this->makeTagsFromTagList($serendipity['POST']['properties']['freetag_tagList']);
if (serendipity_db_bool($this->get_config('keyword2tag'))) {
$searchtext = strip_tags($eventData['body'] . $eventData['extended']);
foreach($automatted AS $keyword => $ktags) {
$keyword = trim($keyword);
if (empty($keyword)) continue;
if (!is_array($ktags) || count($ktags) < 1) continue;
$regex = sprintf("/((\s+|[\(\[-]+)%s([-\/,\.\?!'\";\)\]]*+|[\/-]+))/i", $keyword);
if (preg_match($regex, $searchtext) > 0) {
foreach($ktags AS $tag => $is_assigned) {
if (!is_array($tags) || (!in_array(strtolower($tag), $tags) && !in_array($tag, $tags))) {
if ($to_lower) {
if (function_exists("mb_strtolower")) {
$tag = mb_strtolower($tag);
} else {
$tag = strtolower($tag);
}
}
$tags[] = $tag;
printf(PLUGIN_EVENT_FREETAG_KEYWORDS_ADD, htmlspecialchars($keyword), htmlspecialchars($tag));
}
}
}
}
}
if (empty($tags)) {
$tags = array();
}
if (serendipity_db_bool($this->get_config('cat2tag'))) {
if (is_array($cats = serendipity_fetchCategories())) {
$cats = serendipity_walkRecursive($cats, 'categoryid', 'parentid', VIEWMODE_THREADED);
foreach ($cats as $cat) {
if ($to_lower) {
if (function_exists("mb_strtolower")) {
$cat['category_name'] = mb_strtolower($cat['category_name']);
} else {
$cat['category_name'] = strtolower($cat['category_name']);
}
}
$names = explode(',', $cat['category_name']);
foreach($names AS $name) {
$name = trim($name);
if (in_array($cat['categoryid'], $eventData['categories']) && !in_array($name, $tags)) {
$tags[] = $name;
}
}
}
}
}
$serendipity['POST']['properties']['freetag_tagList'] = implode(',', $tags);
$this->deleteTagsForEntry($eventData['id']);
$this->addTagsToEntry($eventData['id'], $tags);
if ($serendipity['POST']['properties']['freetag_kill']) {
$this->deleteTagsForEntry($eventData['id']);
}
return true;
break;
case 'backend_display':
if (function_exists('mb_internal_encoding')) {
mb_internal_encoding(LANG_CHARSET);
}
if (!empty($serendipity['POST']['properties']['freetag_tagList'])) {
$tagList = $serendipity['POST']['properties']['freetag_tagList'];
} else if (isset($eventData['id'])) {
$tagList = implode(',', $this->getTagsForEntry($eventData['id']));
} else {
$tagList = '';
}
if (serendipity_db_bool($this->get_config('lowercase_tags', true))) {
if (function_exists("mb_strtolower")) {
$tagList = mb_strtolower($tagList);
} else {
$tagList = strtolower($tagList);
}
}
$freetags = $this->makeTagsFromTagList($tagList);
if (!empty($freetags)) {
$tagList = implode(',', $freetags);
}
$taglist = (array)$this->getAllTags();
if ($this->get_config('admin_ftayt')) {
foreach ($taglist as $k => $v) {
$wicktags[] = '\'' . addslashes($k) . '\'';
}
echo '
';
}
if ($this->get_config('admin_show_taglist')) {
?>