*NOTE* these are just some notes i wrote down - maybe they are useful for you - i don't claim these to be 100% correct *NOTE*

this little tutorial/round up on tagging is probably not the only way to handle this in MODx, it's just the way i figured out works best for me . So, suggestions, improvements & notes are welcome.

this article will cover following topics:

  • 1. Tagging of articles
  • 2. ManagerManager Tagging Widget
  • 3. Tag Cloud
  • 4. Virtual categories
  • 5. Managing your categories from a configuration ressource (page)

below you see a screenshot of what we are going to do the next few minutes. All posts are stored within the folder "Blog", whereas "Categories" will display the more general belonging of an article, and "Tags" the more specific.

image

Maybe it would be more appropriate to store articles within folders reflecting the different categories for clarity reasons, but the virtual approach we are covering here, is more or less a proof of concept and will hopefully answer some questions about handling blogposts the WP-way with MODx.

*note: This setup uses an MODx Evolution 1.0.2 installation ( no sample content, but Snippets that are shipped with it + some others ). See related links below for reference:

1. Tagging of articles

step by step instruction of setting up tagging features for your MODx site using Ditto 2.1. Okay here we go:

1.1 First of all we need to create a new TV, e.g. name it "MyTags" / [*MyTags*], which will hold our Tags that are associated with each article.
I choose "Input Type: Text" which is best when you want to add new Tags to an article individually; other than having a *predefined list of Tags to choose from ( * btw. you would do that by setting "Input Option Values" for your TV, e.g. Tag1==Tag1||Tag2==Tag2 ... etc. and using an Input Type of Check Box or Multi-Select Listbox ). Check the associated template we want to have access to that TV → "Template Access".

1.2 Now we need a Ditto template Chunk that will display our articles on the "Blog" ressource. I name it "blog-overview" / {{blog-overview}} and it looks like that:

<div class="overview">
<h3>[+longtitle+]</h3>
[+summary+]
[+link+]<br />
<div class="tagsoverview">Tags: [+tagLinks+]</div>
</div>

[+tagLinks+]: this placeholder will be displaying our clickable list of Tags.
The other placeholders are just standard Ditto ones, which are actually not relevant for our setup. I only use them in order to create a more convincing demo.

1.3 Setup a ressource / folder structure like in the screenshot shown below ( marked orange ):

image

Check "Published" for all, and for the articles uncheck "Show in menu".

The ressources "taglanding" & "categories" will be explained later.

1.4 On the ressource "Blog" we place a Ditto call in the content field ( disable "Rich Text" under the "Settings" tab ). The call looks like this:

[!Ditto? &parents=`2` &filter=`id,7,2||id,8,2` &extenders=`summary` &truncLen=`140` &orderBy=`menuindex ASC` &tpl=`blog-overview` &tagData=`MyTags` &tagSort=`0` &tagDelimiter=`,` &tagDisplayDelimiter=`, ` !]

*note: We don't need to reference the "tagging" extender to "&extenders=`summary`", since tagging will be automatically be triggered when "&tagData=``" appears in the call. + Ditto needs to be called uncached ( needs to be uncached anyways, because otherwise pagination wouldn't work ).

&tpl=`blog-overview`: is the Ditto template we created in step 1.2
&tagData=`MyTags`: the TV we created in step 1.1
&tagSort=`0`: will either turn alphanumerically sort order of our Tags on, or off. I chose "0" which means off, so our Tags will be displayed in the order we type them in our TV. Default would be "1" - on.
&tagDelimiter=`,`: this declares the character which will trigger the separation of our tags in the Tag source ( MyTags ). Default would be an empty space. When we enter our Tags in the TV, we will separate them with a comma and a space between each: tag1, tag2, tag3, etc.

*note: the space after the comma when entering our Tags is actually only necessary for the correct display of our Tags in the ManagerManager widget.

&tagDisplayDelimiter=`, `: this parameter is reponsible for the dividing of the Tags on the frontend. We use a comma with a space behind it.

1.5 Fill our articles with some dummy content: Title, Long title, Menu title, Content + a comma separated list of Tags in our "Tags" TV. If you preview the site now and click on "Blog", you should see a list of articles with their belonging Tags. Clicking on one of those will filter the article overview according to their Tags.

Additional information & notes

/// [+tags+] this placeholder actually doesn't just display "Raw tags separated by tagDelimiter" as i wrongly assumed ( no, not entirely ... it will, if you add "&tags=``" to your call ), but instead it's particularly used to display the currently selected Tag when you filter your posts. try adding [+tags+] to your "Long title" field, and you'll see the currently selected Tag being displayed. / needs [*longtitle*] in your template ).

[+tags+] will also display Tags if you got the parameter "&tags=`tagname`" in your Ditto call. This parameter is used to filter a certain Tag on the initial call and not dynamically ( clicking through Tag links ).

Reading through forum posts, i saw some people having problems getting [+tags+] to display anything. If this is the case, you could also use a little Snippet. e.g. [[selectedtag]] with the following code ( from the forum ):

   <?php
   $tag = preg_replace('/[^A-Za-z0-9 ]/', '', $_GET['tags']);
   $selectTag = (isset($tag)) ? $tag : "";
   if(strlen($selectTag)>0){
   $output = "selected Tag: ".$selectTag." ";
   return $output;
   }
   ?>

/// Displaying Tags on the article ressource ( non clickable / no links / see screenshot below ):

image

In order to display our Tags on the actual article page not as links, simply place our Tag TV on that page ( instead of [+tagLinks+] ):

[*MyTags*]

...on the other hand, if you do want them to be displayed as clickable list, add this Ditto call to the article page:

Tags: [!Ditto? &documents=`[*id*]` &tagData=`MyTags` &tpl=`ressource-tags` &tagSort=`0` &tagDelimiter=`,` &tagDisplayDelimiter=`, ` !]

*note: The call needs to be uncached, otherwise it will result in an parsing error ( maybe someone does know why and maybe a workaround ).

&documents=`[*id*]`: will select the current ressource as source of data.

the template Chunk for "&tpl=`ressource-tags`", {{ressource-tags}} could be e.g.:

Tags: [+tagLinks+]

/// Custom [+tagLinks+] template:

the default output of the [+tagLinks+] placeholder will be a clickable list of Tags and looks like this:

<a href="[+url+]" class="ditto_tag" rel="tag">[+tag+]</a>

If you add the parameter "&tplTagLinks=``" to your call you can customize it by creating an extra template Chunk, e.g. make the list from step 1.2 non clickable and wrap the Tags in spans:

<span class="customstyle">[+tag+]</span>

/// *tip: In order to create a link back to your "Blog" overview page, you could create a new Snippet, call it "linkback":

Snippte code [[linkback]]:

<?php
return $_SERVER['HTTP_REFERER'];
?>

and place it on your article page like this:

<a href="[[linkback]]">go Back</a>

/// Using a custom "Landing" page / ressource in order to filter your Tags:

In order to use a separate page / ressource when filtering articles via Tags, we need to add the parameter "&tagDocumentID=``" to our Ditto call ( → "Blog" ressource ), which will let you select an extra ressource with it's own Ditto call. This is handy if you want to use a custom template for the filtered ressource presentation.

Take care that the "Landing" page Ditto call uses the same set of documents/folders as source of data, as well as the same &tagData=`` value as the original call on the "blog" ressource.

/// Additional parameters / taken from ditto.modxcms.com:

there are some more Ditto parameters concerning tagging, since we haven't used them in this tutorial, i just list them below:

&caseSensitive=``
Purpose: Determine whether or not tag matching and duplicate tag removal are case sensitive.
Options:
0 off
1 on
default:
0 off

&tagMode=``
Purpose: Filtering method to remove tags
Options:
onlyAllTags show documents that have all of the tags
onlyTags show documents that have any of the tags
removeAllTags remove documents that have all of the tags
removeTags documents that have any of the tags
Default:
"onlyTags"

&tagDisplayMode=``
Purpose: How to display the tags in [+tagLinks+]
Options:
1 string of links &tagDisplayDelimiter separated
2 ul/li list
Note:
Output of individual items can be customized by tplTagLinks
Default:
1 string of links &tagDisplayDelimiter separated

&tagCallback=``
Purpose: Allow the user to modify both where the tags come from and how they are parsed.
Options: Any valid function name
Default: [NULL]
Notes:
The function should expect to receive the following three parameters: tagData - the provided source of the tags resource - the resource array for the document being parsed array - return the results in an array if true

2. ManagerManager Tagging Widget

The ManagerManager Tagging Widget truly is a jewel amongst all the other awesome stuff this plugin is capable of. Just take a look at the screenshot below...it will display all available Tags, and simply by clicking on them, you either select, or delete them from the TV input field - wooohooo:

image

ManagerManager is shipped with the standard MODx Evolution 1.0.2 ( if you choose to install it during the installation routine )

If it is installed, you'll find a Chunk called "mm_demo_rules", where you can activate the Tagging Widget by adding:

mm_widget_tags('MyTags',' ');

"MyTags" reflects your TV as source for the Tag data.

btw. you can do a lot of other great stuff with ManagerManager, just take a look at its' documentation files, which you'll find in assets ? plugins ? managermanager ? docs.
The ManagerManager part of the MODx forum can be found here: http://modxcms.com/forums/index.php/board,349.0.html

3. Using the Tag Cloud Snippet

The TvTagCloud 2.1.4 Snippet can be downloaded here:
http://modxcms.com/extras/package/473 and the according support thread:
http://www.modxcms.com/forums/index.php?topic=5814

*note: There are some other Tag Cloud Snippets for MODx, but i haven't tested those and this one works just great.

It got various setup options, which are explained at the top of the Snippet code. My TvTagCloud call in the sidebar looks as follows:

[!TvTagCloud? &parent=`2` &depth=`2` &landing=`7`  &tvTags=`MyTags` &showCount=`1` &displayType=`list` !]

...this will create a nice list of all Tags on your site as you can see here ( marked orange ):

image

Important is the &landing=`7` parameter which sets the ID of the "landing" page. You can use the same "landing" page that i explained further up under "Using a custom "Landing" page".

And you can see, i use the same source of Tag data: &tvTags=`MyTags` as we used in our other examples.

Depending on the amount of ressources tagged with a keyword, different CSS classes will be applied to the Tag Cloud list. This allows you to add different font-sizes for each class in order to make them appear bigger or smaller depending on the amount of occurances on your site ( i use the same size for every Tag, as you can see in the screenshot ).

*note: If you want to add an "active" css class to the selected tag in the tag cloud, add this code to the snippet: active state selected Tag.

4. Virtual categories

Now that we've got the tagging functions up and running, we'll be setting up our categories ( marked orange in the screenshot below )

image

First of all we need a TV as source of categories for each ressource.
4.1 Let's name the TV "category",
4.2 Input Type: Check Box
and Input Option Values ( the categories are just examples ):

Web Design==Web Design||Web Developement==Web Developement||Programming==Programming||MODx==MODx

4.3 Widget: Delimeted List
4.4 Delimiter: ,
4.5 assign the TV to your template,

In order to create a list of all available categories in the sidebar, dev_cw provided this little Snippet found in the forums here: Category List & Tagging ...i added highlighting of the selected category to the snippet:

<?php
// ID for target landing page
$target = (isset($target) && is_numeric($target)) ? $target : '';

// name of TV for source of menu
$tv = isset($tv) ? $tv : '';

// tpl for the output
$tpl = '<li><a class="[+active+]" href="[+url+]" title="[+category+]">[+category+]</a></li>' .PHP_EOL;

// placeholder array
$placeholder = array("[+active+]", "[+url+]", "[+category+]");

if(($tv != '') && ($tpl != '') && ($target != '')){

// get input value options from the tv
$table = $modx->getFullTableName("site_tmplvars");
$catQuery = $modx->db->query( 'SELECT elements FROM '.$table.' WHERE `name` = "'.$tv.'" LIMIT 1' );
$tvVal = $modx->db->getRow( $catQuery );
$catVal = $tvVal['elements'];

// make array from catVal
$catArray = explode('||', $catVal);
// print_r($catArray);

// build target link
$targetUrl = $modx->makeUrl($target).'?cat=';

//iterate through the array and build the menu
foreach($catArray as $c){
$cVal = explode('==', $c);
$cLabel = $cVal[0];
$cTag = urlencode($cVal[1]);
$tagLink = $targetUrl.$cTag;

//check if the selected category is equal to the Label
$category = preg_replace('/[^A-Za-z0-9 ]/', '', $_GET['cat']);
$currentTags = (isset($category)) ? $category : "";
   if($currentTags == $cLabel) {
      $classActive = 'active';
      } else {
$classActive = "";
}

// parse tpl
$placeholder = array("[+active+]", "[+url+]", "[+category+]");
$plh_replace  = array("$classActive", "$tagLink", "$cLabel");
$tplOut  = str_replace($placeholder, $plh_replace , $tpl);

$output .= $tplOut;
}

return '<ul>'.PHP_EOL.$output.'</ul>'.PHP_EOL; 
}
?>

Create a new Snippet, name it e.g. "categories" and copy & paste the code above.
call the Snippet in your sidebar like this:

[!categories? &tv=`category` &target=`8`!]

&tv=`category` defines the TV as source of available categories
&target=`` defines the landing page which will show all ressources of a selected category.

on your landing page you need another Ditto call in order to filter the categories. My call looks like this:

[!Ditto? &parents=`2` &config=`categoryfilter` &tpl=`blog-overview` &filter=`id,7,2||id,8,2` &extenders=`summary` &truncLen=`140` &orderBy=`menuindex ASC` &tpl=`blog-overview` &tagData=`MyTags` &tagSort=`0` &tagDelimiter=`,` &tagDisplayDelimiter=`, ` !]

Important is the parameter: &config=`categoryfilter` which is necessary to filter the ressources according to the selcted category. Create a php file "categoryfilter.config.php" with the following content:

<?php
$category = preg_replace('/[^A-Za-z0-9 ]/', '', $_GET['cat']);
$filter='category,' . $category . ',7';
?>

place that file in assets → snippets → ditto → configs.

Filtering should work now. If not, try different caching options of the Snippet & the ressource.

*note: Another approach of categories would be a second instance of the TagCloud Snippet ( with another TV as source of categories ) twice on that site, which could be customized to look like a list of categories. You would need to change "tags=" to "cat=" in the TvTagCloud Snippet code line 278 and 281 otherwise the same query variable "tags" would be in use.

/// Displaying the selcted categories on the article page:

In order to display the selected categories of each ressource, we need to add the placeholder [+category+] to our "blog-overview" Ditto Template from step 1.2:

<div class="overview">
<h3>[+longtitle+]</h3>
[+summary+]
[+link+]<br />
<div class="tagsoverview">Tags: [+tagLinks+]</div>
<p>Categrories: [+category+]</p>
</div>

btw. i noticed that the categories TV will output a delimeted list in the frontend without a space after the comma. Although i managed to add a space in the delimeter field of the widget properties and save it once, i couldn't reproduce this behaviour ( if someone knows how to add a space to the delimeted list, let me know :) ).

As a workaround, i wrote a little Snippet which would then be placed instead of the [+category+] placeholder. Snippet [[categorylist? &id=`[+id+]`]]:

   <?php
   $output="";
   $document_tvs=$modx->getTemplateVarOutput(true, $id);
   $TVvalue=$document_tvs['category'];
   $TVarray=explode( ",", $TVvalue );

   $tagnum=count($TVarray);
   $lasttag=($tagnum)-1;

   for ($i=0; $i<=($tagnum)-2; $i++) {
   $firsttags .= "$TVarray[$i]".","." ";
   }

   $output="$firsttags" . "$TVarray[$lasttag]";
   return $output;
   ?>

On the article page itself, you would call the Snippet: [[categorylist? &id=`[*id*]`]]

now your category TV output should look like this:

image

/// Snippet - display the selected category:

<?php
$output='';
   if (isset($_GET['cat'])) {
   $category = $_GET['cat'];
   $output= htmlspecialchars($category, ENT_QUOTES, "UTF-8"); 
   } else {
$output='';
}
return $output;
?>

5. Managing the category list from a config page / without editing the TV

If you want to manage your category list without actually editing the TV ( client friendly ), i found this solution by ganeshXL on the forum: How to set up a doc category list that is easily maintained by manager users

5.1 create a new ressource and name it e.g. "categorymanager". Turn Off "Rich Text" for that ressource.
5.2 a new TV name it "TVdummyList"
Input Type: Check Box
Input Option Values ( change "10" to the ID of your "categorymanager" ressource ):

@EVAL $doc = $modx->getDocumentObject('id', 10); $list = $doc['content']; $listTV = str_replace("\r\n", "||", $list); return $listTV;

Widget: Delimeted List
Delimiter: ,
assign it to your template

5.3 On the "categorymanager" ressource you enter the categories with a return after each entry:

image

...this will display a list of categories for each ressource to choose from accordingly.

/// *tip: furthermore you could use the config ressource for other settings of your site. See these posts by Greg Smart:
Create a User Config Page in MODx
Using the Config Page with eForm
Create a Dynamic CSS File in MODx

...as i mentioned earlier, this won't be the only way to setup your MODx site with categories and tagging, it's just the way i found out works best for me.

*note: If something's not working, try different caching options of Snippet calls and ressources.

Julie Webb
Gravatar Image
Reply #10 on : Sat January 07, 2012, 06:54:37
Thank you for the tutorial! I implemented just the categories part and I have most of it working.

The categories are showing in each article summery on the blog page
The categories are showing up in the sidebar category list.

on my categories page -- /categories?cat=+Cat2
I get the "no documents found" message even though there is one article published with the "Cat2" category

I just have a couple of questions:

1) When you instructed: "on your landing page you need another Ditto call in order to filter the categories. My call looks like this:"

Was I suppose to create an resource "categories" within the blog resource container? or was I suppose to add or replace this Ditto call to the blog resource container?



and can you explain the what the &filter 7 was for? --I figured out what page id 8 was from but not 7.

Thanks for your time and detailed instructions!
Jules
admin
Gravatar Image
Reply #9 on : Mon February 21, 2011, 11:05:25
Hi Eliot,

check the ManagerManager docs. you need to specify the delimeter in your MM rule e.g.:
mm_widget_tags('myTags', ',', '', '', '', '');
admin
Gravatar Image
Reply #8 on : Sat February 19, 2011, 08:39:43
Hi Eliot,

i'll look into this. j (MM Tagging-Widget)
Eliot
Gravatar Image
Reply #7 on : Fri February 18, 2011, 19:38:11
Is it possible to have more than one word as a tag via ManagerManager's Tagging widget? For example I'd like to have keywords like New York Real Estate as one tag not 4.

Thanks!
admin
Gravatar Image
Reply #6 on : Thu February 17, 2011, 11:35:23
Hi Anonymous,

you need to look into Regex. The following code will allow Umlauts, ß and dashes: http://pastie.org/1574008

cheers, j
admin
Gravatar Image
Reply #5 on : Wed February 02, 2011, 08:01:40
Hi Anonymous,

i'll look into it, when i got some time

j
Anonymous
Gravatar Image
Reply #4 on : Fri January 28, 2011, 23:51:31
J

I'm sorry to impose on you again. Perhaps there's an easy answer for us.

Is there anyway to use commas within in the category name? I realize the categories themselves are comma separated, so I assume commas within the category name would have to be escaped somehow. Is there some way we can do this? How about other characters? We tried slashes as well, no luck.

Thank you!
Terry Barth
Gravatar Image
Reply #3 on : Tue January 25, 2011, 16:10:49
That worked beautifully! Thank you!
admin
Gravatar Image
Reply #2 on : Tue January 25, 2011, 08:10:55
Hi Terry,

glad you like the tut :)

added "Snippet - display the selected category" (right above 5.), something like this should work

j
Terry Barth
Gravatar Image
Reply #1 on : Tue January 25, 2011, 00:19:21
Fantastic tutorial! Exactly what we need for a project.

Is there a way to display a category bar above the filtered results that shows which category was selected from the list of categories?
  • Required fields are marked with *.

If you have trouble reading the code, click on the code itself to generate a new random code.