1

I need to make a "keywords" field on a front-end entry form that can create tags in the cms (Craft 2). I am fully aware of existing tickets regarding this issue like Brandon Kelly's but they're a little too ambiguous for me.

This is the classic tag field where you type a word, press spacebar, and a new tag appears, etc. I am aware that when my form submits, despite what's visual on the page, the submitted html needs to look something like this:

<input type="hidden" name="fields[fieldName]">
<input type="hidden" name="fields[fieldName][]" value="{tag 1 id}">
<input type="hidden" name="fields[fieldName][]" value="{tag 2 id}">
<input type="hidden" name="fields[fieldName][]" value="{tag 3 id}">
// etc

I've looked into many jquery plugins and they don't output this html pattern. Instead, they all basically create a single hidden input field with all your tags entered in the value attribute separated by commas like value="tag1, tag2, tag3, etc", (tag-it is one exception but it is outdated, buggy, and it always prints the tag's text in the value).

I'm not entirely sure how this all should work, but I'm guessing I need to write custom ajax so that when a tag is created, an ajax call uses the createTag action to create the tag in the database before the form submits, since the saveEntry form submission itself won't create the tag but merely link an existing tag to that entry.

Then, just as it's shown in Brandon's original answer, my js adds the hidden input formatted correctly in the successful response. If the user deletes a tag, I have to use the jquery plugin's removeTag callback (or whatever the callback is) to then remove that hidden input.


However, where I'm getting confused is on these points:

  1. When a user deletes a tag on the front-end (let's say they made a typo), the js deletes the hidden input in the html, but the tag is already created in the database. Do I need to then somehow delete that tag in the database via ajax or just let my db rack up a bunch of unusable tags?
  2. Is it better to just do away with the hidden input approach, use a plugin to accept the comma-separated tags from one hidden input and do all the creating/checking for existing tags/etc on a entries.onBeforeSaveEntry as Ben seems to suggest in this ticket?

Can anyone offer up actual examples of what they did to handle tags on the front end? Maybe also some suggestions of solid jquery plugins in 2018 (many seem janky and not up to date)? And is my process of thinking outlined above incorrect in any way (I have very little idea what I'm doing)?

Current examples online are either for listing out existing tags the user can choose from with checkboxes or a multiselect (which is usually not the case on a form), or just showing some basic ajax. Any help and clarification would be greatly appreciated (and hopefully help someone else down the line).

2

First of all generally it's a really good idea to check how Pixel and Tonic has handled all the things. I know many people tend to dislike this hint but it's the best thing you can do. The developers are really good, they make good and useful comments and - at least for Craft 3 - they take care of the PHP Doc (in Craft 2 too but not as well)

When I run into issues/trouble the first thing I usually do is do dig into the well documented source code and check what they did. As far as I can see in your question you already started to do that too which is great.

Maybe I'm just too paranoid but you should never delete or insert something without checking it and of course you should not leave tags in your DB either. Your page could become slow if you don't remove them. The best thing to do: check if the tag is used in your controller and delete it if it has no relations/uses after the jQuery remove callback. That leads me to my next hint: many people try to avoid a custom controller but mostly it's so much easier to use Crafts/Yiis power instead of trying to avoid work.

Like you already stated you could spend multiple hours to search for a good jQuery plugin to avoid 2-3 lines of php code or you can just extend the EntriesController, copy the save function and include a few lines to deserialize the tag input. I don't really use jQuery (only angular) so I can't suggest you a plugin for that but as soon as you create a custom controller you are free enough to use the plugin you like and not the one that avoids php.

However - what I would suggest is the following.

  1. Find a jQuery plugin that has the following callbacks afterInsert to upload the tag via ajax, afterRemove so you can delete tags and maybe something that allows autocomplete
  2. Create a function to search for tags in your controller, this is for autocomplete. You'll want to return an array of possible tags that match your users input
  3. Create a saveTag function in your controller, check if the tag already exists, if so return the ID if not create a new one and return the ID. If the tag is created via autocomplete you won't need an additional Ajax request since you'll fetch the ID with the tag name
  4. Insert the ID in a hidden input
  5. Create a deleteTag function and check if the tag is used somewhere. This part is mostly copy paste. You want to take a look how Pixel and Tonic did it and copy the functionality with minor changes here and there to fit your needs
  6. Copy the entries save function and insert it in your controller. At the beginning of this function you could explode the single, comma sparated hidden input into an array and that's basically it.

That's the way I handled it the last time - only with angularjs instead of jQuery

  • Thanks for the feedback Robin. I'm definitely not looking for a quick js solution but instead just clearer direction online, and this was very helpful. Autocomplete aside, it sounds like you suggest posting a single input's string of tag terms into a custom controller for evaluation and then saving the entry from there, which involves zero ajax (I like this). After more researching, it appears I can push my data to Craft's saveEntry controller with Yii's forward() controller method from my own custom controller after evaluating the tags, which saves me copy/pasting P&T's saveEntry code. – Ryan Feb 13 '18 at 5:01
  • yiiframework.com/doc/api/1.1/CController#forward-detail I'm not sure if it will work, and perhaps it's overcomplicating things, but I'd like to see if I can just post to my own controller, sort out the tags there, add them to the rest of the post data, then pass that all off to the Craft's saveEntry controller method to finish it. If you know a better way to do this than just repeating their code in my own controller, I'm all ears! – Ryan Feb 13 '18 at 5:06
2

I don't have any example code to offer, as I've never had a need to do something like this, but the way I see it there are 2 basic approaches:

  1. Use Javascript on form submission to first create the tags with an AJAX call.

  2. Use a custom plugin controller to handle the tag creation before passing the call on to it to the entry controller.

Either way I would use Javascript to manipulate the tag field before submitting, for example by converting fieldName="tag1, tag2, tag3" to fields[fieldName][]=tag1&fields[fieldName][]=tag2&fields[fieldName][]=tag3 That way regardless which jQuery plugin you use, you're guaranteed to receive the right fields in the controller.

In case you want to handle deletion of unused tags, you can simply do that with a custom plugin listening for the entry.onAfterSave event.

I'm not sure that I've said anything that is new to you here, but you're not really asking a concrete question either. If you need to use tags then this is the process that I would follow, otherwise you might consider a simpler solution to whatever problem it is that you're trying to solve using tags, as my feeling is that they were intended for use in the CP rather than the front-end.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.