Tags Mod for sNews version 2
Here is the second edition of my tags mod for sNews 1.7, this mod will format your tags in an SEO link, as shown on my own page here, i.e. http://yousite.com/tag/widget/. This version also separates the tags search from the standard search.
Please note, if you have installed my tags mod and want to upgrade to this version, I will write up a separate tutorial on that as well, if you can't figure out the differences from this one. As before, you will need to add your keywords with a single comma and space separating them, i.e.
keyword1, keyword2, keyword3, etc.
So let's get started. BACK-UP your snews.php file and work on a copy.
1. Find the hard coded link items;
$l['cat_listSEF'] = 'archive,contact,sitemap,login,administration,admin_category,admin_article,article_new,extra_new,page_new,snews_categories,snews_articles,extra_contents,snews_pages,snews_settings,snews_files,logout,groupings,admin_groupings';
now we need to add the "tag" page, as in the highlighted code;
$l['cat_listSEF'] = 'archive,contact,sitemap,tag,login,administration,admin_category,admin_article,article_new,extra_new,page_new,snews_categories,snews_articles,extra_contents,snews_pages,snews_settings,snews_files,logout,groupings,admin_groupings';
2. now in the function center(), find the globals and add the code like below, IF YOU HAVE ALREADY ADDED THE url code from the SEO aearch mod, you do not need to add that again.
global $categorySEF, $subcatSEF, $articleSEF;
// begin new code
$url = explode('/',clean(cleanXSS($_GET['category']))); // already done if you have the SEO search mode installed
if ($url[0] == "tag") {
$tags_query = $url[1];
}
// end new code
3. Now around line 545, still within the function center(), find the following code;
case isset($_POST['search_query']): // this may have been changed to $search_query if you have installed the SEO search mod
search(); return; break;
Now ADD the following code below;
case isset($tags_query):
tagsearch($tags_query); return; break;
4. Find the function articles. Look for
if ($_ID || (!$_catID && $frontpage != 0)) {
and update the $query_articles variable by adding the highlighted code
if ($_ID || (!$_catID && $frontpage != 0)) {
if (!$_ID) $_ID = $frontpage;
// article or page, id as indentifier
$query_articles = 'SELECT
a.id AS aid,title,a.seftitle AS asef,a.category AS acat,a.keywords_meta AS keywords,text,a.date,
a.displaytitle,a.displayinfo,a.commentable,a.visible
FROM '._PRE.'articles'.' AS a
WHERE id ='.$_ID.$visible;
} else {
5. Now look for
// get the rows for category
if ($_catID) {
and update the $query_articles variable by adding the highlighted code
// get the rows for category
if ($_catID) {
$query_articles = 'SELECT
a.id AS aid,title,a.seftitle AS asef,a.keywords_meta AS keywords,text,a.date,
a.displaytitle,a.displayinfo,a.commentable,a.visible
FROM '._PRE.'articles'.' AS a
WHERE position = 1
AND a.published =1
AND category = '.$_catID.$visible.'
ORDER BY artorder ASC,date DESC
LIMIT '.($currentPage - 1) * $article_limit.','.$article_limit;
} else {
$query_articles = 'SELECT
a.id AS aid,title,a.seftitle AS asef,a.keywords_meta AS keywords,text,a.date,
displaytitle,displayinfo,commentable,a.visible,
c.name AS name,c.seftitle AS csef,
x.name AS xname,x.seftitle AS xsef
FROM '._PRE.'articles'.' AS a
LEFT OUTER JOIN '._PRE.'categories'.' as c
ON category = c.id
LEFT OUTER JOIN '._PRE.'categories'.' as x
ON c.subcat = x.id AND x.published =\'YES\'
WHERE show_on_home = \'YES\'
AND position = 1
AND a.published =1
AND c.published =\'YES\''.$visible.'
ORDER BY date DESC
LIMIT '.($currentPage - 1) * $article_limit.','.$article_limit;
}
6. That will slurp the keywords into the $r['keywords'] variable. We will now prepare to break the keywords apart and insert them into the article, underneath the "infoline" and admin edit links. Still within the articles function, find the 2 instances of the admin links;
} else if (_ADMIN) {
echo '<p>'.$edit_link.'</p>';
}
then insert the following code below both of the admin edit links, like this;
// insert new code here
if (trim($r['keywords']) != "") { // not empty
$article_tags = explode(', ', $r['keywords']);
$keyCount = count($article_tags);
if ($keyCount > 0) {
echo '<div class="tags">';
for ($i = 0; $i < $keyCount; $i++) {
if ($i == 0) {
$pre = "";
} else {
$pre = ", ";
}
echo $pre.'<a href="'._SITE.'tag/'. urlencode($article_tags[$i]).'/" title="See more articles on '.$article_tags[$i].'">'.$article_tags[$i].'</a>';
}
echo "</div>";
}
}
7. Now add the tags engine, THERE ARE TWO OPTIONS, PICK ONE. The first tagsearch function is for people who want to use MySQL's full-text speed and don't need to use tags under the full-text limit of 4 characters. If that's you, then simply copy and paste the entire function below to just above the closing php tag, if not, skip to step 9 now.
//TAGS ENGINE
function tagsearch($tags_query,$limit = 100) {
$tags_query = clean(cleanXSS($tags_query));
echo '<h2>'.l(tag_results).'</h2>';
if (strlen($tags_query) < 4) {
echo '<div><p>'.l('charerror').'</p>';
} else {
$tags_query = trim($tags_query);
$now = date("Y-m-d H:i:s",time());
$query = 'SELECT a.id,a.title,a.seftitle AS asef,a.date AS date,
c.name AS name,c.seftitle AS csef,
x.name AS xname,x.seftitle AS xsef, MATCH(a.keywords_meta) AGAINST (\'"+'.$tags_query.'"\' IN BOOLEAN MODE) AS score
FROM '._PRE.'articles'.' AS a
LEFT OUTER JOIN '._PRE.'categories'.' as c
ON category = c.id AND c.published =\'YES\'
LEFT OUTER JOIN '._PRE.'categories'.' as x
ON c.subcat = x.id AND x.published =\'YES\'
WHERE MATCH(a.keywords_meta) AGAINST (\'"+'.$tags_query.'"\' IN BOOLEAN MODE) AND position != 2
AND a.published = 1
AND date <= \''.$now.'\'';
if(!_ADMIN){
$query = $query.'AND a.visible = \'YES\'';
}
$query = $query.' GROUP BY a.id HAVING score > \'0\' ORDER BY score DESC LIMIT '.$limit;
$result = mysql_query($query);
$numrows = mysql_num_rows($result);
if (!$numrows) {
echo '<div><p>'.l('noresults').'
<strong>'.stripslashes(entity($tags_query)).'</strong>.</p>';
} else {
echo '<div id="tag_results"><p><strong>'.$numrows.'</strong> '.l('tagresultsfound').' <strong>'.
stripslashes(entity($tags_query)).'</strong>.</p>';
while ($r = mysql_fetch_array($result)) {
$date = date(s('date_format'), strtotime($r['date']));
if ($r['name']) { $name = ' in '.$r['name']; } else { $name = "";}
if (isset($r['xsef'])) $link = $r['xsef'].'/'.$r['csef'].'/';
else $link = isset($r['csef']) ? $r['csef'].'/' : '';
echo '<p><a href="'._SITE.$link.$r['asef'].'/">'.$r['title'].'</a><br /><span class="tag_sub">added on '.$date.$name.'</span></p>';
}
}
}
echo '</div>';
}
8. Now set up a MySQL full-text index on your keywords field in your database
ALTER TABLE articles ADD FULLTEXT(keywords_meta);
9. OK, add this tagsearch function only if you don't want to use MySQL's full-text search;
//TAGS ENGINE
function tagsearch($tags_query,$limit = 100,$min_chars = 2) {
$tags_query = clean(cleanXSS($tags_query));
echo '<h2>'.l(tag_results).'</h2>';
if (strlen($tags_query) < $min_chars) {
echo '<div><p>Tags must be at least '.$min_chars.' characters!</p>';
} else {
$tags_query = trim($tags_query);
$now = date("Y-m-d H:i:s",time());
$query = 'SELECT a.id,a.title,a.seftitle AS asef,a.date AS date,
c.name AS name,c.seftitle AS csef,
x.name AS xname,x.seftitle AS xsef
FROM '._PRE.'articles'.' AS a
LEFT OUTER JOIN '._PRE.'categories'.' as c
ON category = c.id AND c.published =\'YES\'
LEFT OUTER JOIN '._PRE.'categories'.' as x
ON c.subcat = x.id AND x.published =\'YES\'
WHERE (a.keywords_meta LIKE \'%'.$tags_query.'%\' AND a.keywords_meta REGEXP \':<:'.$tags_query.':>:\') AND position != 2
AND a.published = 1
AND date <= \''.$now.'\'';
if(!_ADMIN){
$query = $query.'AND a.visible = \'YES\'';
}
$query = $query.' ORDER BY date DESC LIMIT '.$limit;
$result = mysql_query($query);
$numrows = mysql_num_rows($result);
if (!$numrows) {
echo '<div><p>'.l('noresults').'
<strong>'.stripslashes(entity($tags_query)).'</strong>.</p>';
} else {
echo '<div id="tag_results"><p><strong>'.$numrows.'</strong> '.l('tagresultsfound').' <strong>'.
stripslashes(entity($tags_query)).'</strong>.</p>';
while ($r = mysql_fetch_array($result)) {
$date = date(s('date_format'), strtotime($r['date']));
if ($r['name']) { $name = ' in '.$r['name']; } else { $name = "";}
if (isset($r['xsef'])) $link = $r['xsef'].'/'.$r['csef'].'/';
else $link = isset($r['csef']) ? $r['csef'].'/' : '';
echo '<p><a href="'._SITE.$link.$r['asef'].'/">'.$r['title'].'</a><br /><span class="tag_sub">added on '.$date.$name.'</span></p>';
}
}
}
echo '</div>';
}
10. Now open your language file (EN.php in the lang folder if you're using the default) and add the following lines;
# Tag search $l['tag'] = 'Tags'; $l['tagresultsfound'] = 'item(s) tagged with;'; $l['tag_results'] = 'Tag Search';
10. Now you need an icon, like this one
, save that and drop it into your images folder and then add the following to your style sheet. These are my colors, feel free to create your own.
#tag_results p {
line-height:1.2em;
margin: 0 0 10px 0;
}
#tag_results a {
color: #386E80;
}
.tag_sub {
font-size: 0.9em;
color: #777777;
}
.tags {
background: #fff url('../images/tags.png') left center no-repeat;
font-size: 0.9em;
margin-bottom: 14px;
padding: 0 0 2px 14px;
}
.tags a {
color: #f66363;
text-decoration: none;
}
.tags a:hover {
color: #000;
text-decoration: none;
}
You can change things around to display them only on certain articles like I have done, for example I only show the tags on true "articles", not on "pages". To show only on articles with "infoline" shown and not "pages" like mine, I wrapped the second instance of the tag code in the following;
if ($infoline == true && $_catID != 0) {
//tag code goes here
}
Comments
RSS Comments Feed
Sven
Thanks for sharing Matt :)
Sven
in TAGS ENGINE the word "Here" in front of:
$tags_query = ereg_replace("[^-\+\s0-9a-zA-Z]", " ", $tags_query);
Matt
Let me know how it works for you.
Moz
which tag code goes in the infoline?
if ($infoline == true && $_catID != 0) {
//tag code goes here
}
Matt
That code is just an extra option. If you wrap that around the second occurrence of the the tags code, it'll will include the tags ONLY if it's an article, not a "page".
The tags code I'm referring to is the code you're placing below both of the admin edit links.
So the second instance of the tags would look like this below the admin link;
} else if (_ADMIN) {
echo '<p>'.$edit_link.'</p>';
}
// insert new code here
if ($infoline == true && $_catID != 0) {
if (trim($r['keywords']) != "") { // not empty
$article_tags = explode(', ', $r['keywords']);
$keyCount = count($article_tags);
if ($keyCount > 0) {
echo '<div class="tags">';
for ($i = 0; $i < $keyCount; $i++) {
if ($i == 0) {
$pre = "";
} else {
$pre = ", ";
}
echo $pre.'<a href="'._SITE.'tag/'. urlencode($article_tags[$i]).'" title="See more articles on .$article_tags[$i].'">'.$article_tags[$i].'</a>';
}
echo "</div>";
}
}
}
Does that make sense?
Thanks.
Moz
Thanks Matt. Great job.
Tomaz
Great article, Matt!
Can You please do a little mod to display the tag in the meta title?
Instead of: Tags - mdj.us
to display: "tag" - mdj.us
And like this also for the Search.
Thanks!
Matt
That's easy, look for the function title(), find the line
$title = $_TITLE ? $_TITLE.' - ' : '';
and change it to
$url = explode('/',clean(cleanXSS($_GET['category'])));
if ($url[0] == "tag" || $url[0] == "search") {
$title = $url[1].' - ';
} else {
$title = $_TITLE ? $_TITLE.' - ' : '';
}
that will show the tags and search pages like the standard articles, i.e. if you search for purple widgets, the meta title will be
purple widgets - Search - yoursite.com
Tomaz
Working fine.
Philippe
I see a problem.
The tags URL are being indexed by the search engines, but since there's no specific meta description as "All tags on the sublect blablabla" all the meta description are the same (the website default one).
And searh engines want different meta description.
Do you see what I mean?
Matt
Yeah, this is an inherent issue with all the "predefined" pages within sNews, it's the same thing with the contact page, sitemap, archive, etc.
This happens because sNews looks for the description_meta field in the database, and when it doesn't see it, it will assign the default for the website.
It's actually a fairly easy fix though, you can use this switch statement in the title function
add it below the code I gave above, so the whole thing would look like this;
$url = explode('/',clean(cleanXSS($_GET['category'])));
if ($url[0] == "tag" || $url[0] == "search") {
$title = $url[1].' - ';
} else {
$title = $_TITLE ? $_TITLE.' - ' : '';
}
switch ($url[0]) {
case "tag":
$_DESCR = "All items tagged with; ".$url[1];
break;
case "search":
$_DESCR = "Search results for all items containing the term(s); ".$url[1];
break;
case "archive":
$_DESCR = "View previous entries by date.";
break;
case "contact":
$_DESCR = "Contact the website operator.";
break;
case "sitemap":
$_DESCR = "Sitemap tree of all pages and articles on this site.";
break;
}
Philippe
(except there's no "S" at archive) ;-)
Thanks a lot pal!!!
Matt
I have removed the "s".
serkan
There are no results for query keyword.
??
Matt
You can send it to me through the contact form if you don't want want to publish it here.
If not, what is the tag that's not returning results? Is it all tags, or just one?
Vic
Matt
The part where we output the search term could possibly contain malformed HTML, that should use htmlentities (I'll add that now), but that isn't an XSS or security issue.
Vic
Yes, that was actually about it. :-) Thanks.
Wouldn't it be a problem to add in the section of the website if there are no results for the tag search (this would also apply to SEF/SEO search)? That would be handy in case someone tries to link to you, placing inappropriate words as tags (for example, website.com/tag/some-bad-words/). The tag would prevent search engines from indexing such content.
Vic
Matt
Cool, I'll write up an update on this now.
Shoot me an email via the contact form, thanks a bunch for the input!
Fyner
For me This mod works fine, but I have one question...
I use in my tags character like: "ąśćęół" it's possible change this to "asceol" (automatically)?
Matt
Fyner
Matt
I know a few, if you wanted a php function to do that, it would be something like this;
function removeaccents($string) {
$accented = array('ą','ć','ł','ż','ź','ń','ó','ę','ś');
$stripped = array('a','c','l','z','x','n','o','e','s');
$output = str_replace($accented, $stripped, $string);
return $output;
}
but it will require a more work to put something together in Javascript, but I can take a look.
Fyner
I have function like this:
function deLocalize( inStr ) {
var outStr = inStr;
outStr = outStr.replace(/[Ä…Ä„]/g, 'a');
outStr = outStr.replace(/[ćĆ]/g, 'c');
outStr = outStr.replace(/[ęĘ]/g, 'e');
outStr = outStr.replace(/[Å‚Å]/g, 'l');
outStr = outStr.replace(/[ńŃ]/g, 'n');
outStr = outStr.replace(/[óÓ]/g, 'o');
outStr = outStr.replace(/[śŚ]/g, 's');
outStr = outStr.replace(/[żŻ]/g, 'z');
outStr = outStr.replace(/[źŹ]/g, 'z');
return outStr;
}
but this is not work for tag URLs :/
47 comments, page 1 of 2 [ 1 2 » ]