Pimcore hidden gems: Tags
Tags: pimcore, symfony, php, learning
Published: 2020-02-27 12:57:18

Pimcore is the leading Product Information Management solution on the market, and it has a bunch of features implemented. It can sometimes be difficult to see all of them, or in fact, use all of them. This article aims to showcase one particular feature developers might use in their arsenal when developing a quality solution using Pimcore as a platform.

The [documentation](https://pimcore.com/docs/6.x/index.html) is definitely the first stop every aspiring developer should visit. It has a description of all the available features and tools. So when I first started working in Pimcore, the documentation was a powerful ally. And among other tools and cool features presented there, I stumbled upon the [Tags](https://pimcore.com/docs/6.x/Development_Documentation/Tools_and_Features/Tags.html) functionality. So, let’s dive into this particular feature, shall we?

# What are Tags, anyway?

The docs tell us that:

> Tags provide a way to create additional taxonomies and classifications for documents, assets and objects.

> By using tags you are able to easily filter Pimcore elements (documents, objects, assets) and keep the additional search criteria to the application.


Not really a clear definition, huh? Basically, if you’ve ever run into Tags prior to working with Pimcore, you’d know what Tags are, but if you’re new to the term, the documentation doesn’t really give you a lot to go on.

So, let’s put it this way: A Tag is a small content object, connected to a Document, Object, or an Asset which helps you group data into categories not already in your object tree.

OK, that’s a bit more on the nose, but still not what we’re looking for.
Even more simplified: A Tag is a keyword which you add to a Document, Object or an Asset which you can then use to easily search and group that content in your application.

When presented like that, I hope you get a clear idea of what a Pimcore Tag is. In this article, you’ll see:

* how Tags are structured
* how they’re added
* some common usages of Pimcore Tags

We’re also explaining when **not** to use Tags, as well as giving you some more reading material in case you need to brush up your knowledge. So, read on!

# Structure

Let’s look at the structure of tags in Pimcore. In your database, Tags are primarily used via two tables, **tags** and **tags_assignment**.

The **tags** table defines the keyword itself, and the position of the tag in the tag subtree.

The **tags_assignment** table defines which tag is assigned to which content object and whether it’s an asset, object, or document.
Simple enough.

How does it look in the Administration?

![Tags menu](https://dev-to-uploads.s3.amazonaws.com/i/qovpg6dvfuhj2axsyqtq.png)

Your user needs to have the Tag configuration permission checked to view this screen. It shows all the tags available throughout your installation. The tags can have a tree-like structure for better organization so that you can find them more easily when assigning to an object.

To be able to assign tags in the administration, your user needs to have the Tag Assignment permission checked.

![Tags assignment](https://dev-to-uploads.s3.amazonaws.com/i/94jbr9g087tz8gpw7a5j.png)

Tag assignment is done on a content object level. So, basically, open the object you need, and assign tags you wish associated with the object itself.

OK, now that we familiarized ourselves with the structure and assignment, let’s see how we can do it programmatically.

# PHP API

Let’s say we’d like to list all of the tags for a single object in that object view.

```php
$tags = \Pimcore\Model\Element\Tag::getTagsForElement('document', 4);

$availableKeywords = [];

foreach ($tags as $tag) {
    $availableKeywords[$tag->getId()] = $tag->getName();
}

$this->view->$availableKeywords;

```

As you can see, we’re using the **getTagsForElement** method from the **\Pimcore\Model\Element\Tag** class. We’re passing the type of object to it (in this case ‘document’), and the id of the element for which we need to display tags. Then, we’re adding the tag ID and tag keyword to the **$availableKeywords** array which we can then pass to the view to display a keyword on the page.

How about listing all objects of a single tag?

```php
$objects = \Pimcore\Model\Element\Tag::getElementsForTag($tag, ‘object’);

$availableObjects = [];

foreach ($objects as $object) {
    $availableObjects[] = $object;
}

```

Here, we’re using the **getElementsForTag** method from the **\Pimcore\Model\Element\Tag** class to get all objects of a single tag which we then add to the **$availableObjects** array for further manipulation.

What if we need to add a tag to an object? Let’s say we have a new tag with keyword ‘keyword’:

```php
$tag = new \Pimcore\Model\Element\Tag();

$tag->setName(‘keyword’)->save();

\Pimcore\Model\Element\Tag::addTagToElement(‘object’, 156, $tag);

```
We just created a new Tag, and then used the public method **addTagToElement** from the **\Pimcore\model\Element\Tag** class to assign that tag to an object with an ID of 156.

As you can see, programmatically, it’s really easy to retrieve tags, create tags, and assign them to objects.

# Usage examples

“Sure”, I already hear you say, “but you haven’t told us anything that we couldn’t get from the official documentation”. Ah, but this is the part of the article where the real fun starts.
So, where can we use Tags?

Easily enough, one of the answers is - search. If you need to get a list of all the objects using the same keyword, the chunk of code can be the following:

```php
$tagListing = new \Pimcore\Model\Element\Tag\Listing();

$tagListing->addConditionParam(‘name LIKE :term’, [‘term’ => ‘%’ . $term . ’%’]);

$objectList = [];

foreach ($tagListing as $tag) {
    $taggedObjects = \Pimcore\Model\Element\Tag::getElementsForTag($tag, ‘object’);

    foreach ($taggedObjects as $taggedObject) {
        $objectList[$taggedObject->getId()] = $object->getKey();
    }
}

dump($taggedObjects);

```
Here, we’re searching for all Tags similar to the term a user has input in a search form. Then, we’re merging all the objects found in a single array which we can then manipulate further by displaying, for example, a dynamically generated URL for each object, along with some sort of unique identifier for each object.

Now you have your search for objects using keywords. How about other usages?

You can use tags as sub-categories. For example, you created a subtree of Data Objects in Pimcore in the following manner:

```flow
Products
	|-> Shoes
		|-> Sneakers
			|-> Maxxx Power by Sneakerzilla
			|-> Running Supreme by Sneaker Fanatic
	|-> Clothing
		|-> Sweatpants
			|-> Maxxx Stretch by Sneakerzilla
			|-> Maxxx Comfort by Sneakerzilla
			|-> Running Extreme by Sneaker Fanatic
```

Now say you want to have a single view where you’ll just select a brand, and all of your products for that brand would show, no matter if they’re Sneakers or Sweatpants.

We’ll create a Tag called Brand, and underneath it, we’ll have “Sneakerzilla” and “Sneaker Fanatic”, respectively.

So, when we assign “Sneakerzilla” to “Maxxx Power”, ”Maxxx Stretch” and “Maxxx Comfort”, the next time a user visits the page for Brand selection, and they select “Sneakerzilla” as their preferred brand, they’ll get exactly what we need them to get without a big change to the Data Model or the Subtree we already established previously.

The code for this is largely the same as the code for the search, only you’re required to create a simple route which will then only display the single tag by passing it a tag id. For example:

```php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

// …

/*
* @Route(“/tag/show/{id}”, name=”show_tag”)
* @param Request $request
* @param $id
*/
public action showTag(
    Request $request,
    $id
)
{
    $tag = \Pimcore\Model\Element\Tag::getById($id);

    $taggedObjects = \Pimcore\Model\Element\Tag::getElementsForTag($tag, ‘object’);

    $this->view->tag = $tag;
    $this->view->taggedObjects = $taggedObjects;
}

```

So, we fetched a single Tag by its ID, we extracted all of the tagged objects and passed them to the view for display on the page. We also passed the Tag to the view since we’ll need some stuff from the Tag itself to display (for example, name).

##Let’s take things to an extreme

Say you need to create a customer feedback functionality in your Pimcore installation. You already have a form with input fields which stores some sort of a message into your database. And now, you need to categorize all of the user requests a certain way. For example, Support, Sales, and, let’s say, Employment.  And you need to create a mailing feature to send mail to one of those based on what was selected.

You can easily create three tags, which you can then display as a Select in the Feedback form. When the Feedback form is submitted, after the form object itself has been created, assign it the selected Tag. After a Tag has been assigned, you can trigger an event in which you can send mail to the office responsible for handling such requests. Read the [Addendum](#addendum) to this article for more on Tag events.

Later, when the office in question asks for a list of all messages received, you can easily create an export of such messages using Tags to filter them out quickly.

How about matching user behavior with their most viewed pages?
You could create a Targeting rule which takes into consideration how many times a Customer visited a single page tagged with a certain Tag, then assign the same Tag to that Customer. When the Customer visits the page next time, you can show all of the documents and objects tagged with that term.

As you can see, Tags, even though they’re small and unassuming, can be a powerful tool in your toolbox while you develop.

# When not to use Tags

Of course, one should always keep in mind the paradigm we so often use: “Use the right tool for the right job”. In the previous usage examples, we’ve hopefully shown that Tags can be powerful, but they have their limitations.

Always keep in mind that a Tag is nothing more than a keyword, and it can only go so far. It’s limited in its usage since there is only ever three key pieces of information you actually store in it:

1. Its position in the Subtree
2. The relation to different content (Data Objects, Assets and Documents)
3. The keyword itself

The position in the Subtree is important for more complex Tag structures since we can then divulge the siblings of a Tag (for example, when you need to show Tags similar to the current one).

Also, Tags cannot be expanded upon using conventional methods, and they actually **shouldn’t** be. We need to use them carefully since the Data Model is an ever-changing thing.

So, if at any point during the development of your project you might find that you need more from a Tag besides these three key pieces of information, maybe it's better to use a Data Object instead.

One more thing to consider is that a Tag in Pimcore is not easily translatable to other languages. For different languages, you might need to open up a new subtree of keywords.

This, however, should not discourage you from trying Tags in your project. You might actually find that, by using Tags, your whole Data Model becomes less cluttered and more accessible to others.

# Addendum: Tag Events <a name="addendum"></a>

As of the time of the writing of this article, there are no Events available for adding or removing Tags. The Events exist only for copying content (to add the copied content the same tag), and for removing assets (to remove all tags from the removed asset).

But, adding such an Event shouldn’t be too difficult.

You would want to create an Event, which would then trigger any time you create a Tag in a particular place of your installation. Then, a designated event dispatcher would dispatch such an Event, on which you can then hook your Event Listener. The Listener would then send an email.
For further information, I suggest you read more about [Symfony’s Event Dispatcher](https://symfony.com/doc/current/components/event_dispatcher.html).

I hope that this article has been of use to you and that you might find yourself using Tags more in the future.

Until next time,

Tomislav Buljević

(Images courtesy of [Pimcore documentation](https://pimcore.com/docs/6.x/Development_Documentation/Tools_and_Features/Tags.html))

*article originally published at https://factory.hr/blog/pimcore-hidden-gems-tags*