Intro
Using ajax can really improve the user experience of your site. In this tutorial, we will see how using the powerful voting API we can create a simple like dislike module and use ajax for that.
The init hook
In hook_init() I have added one js file and an inline js variable “basepath” because I found it really difficult to get the base path in javascript. Finally, I came up with the solution of having a variable declared through inline js.
The hook for permission
Here I have used hook_permission() for checking the access. Although this is not a compulsory step, I feel that having custom permissions will be a good option to easily restrict users based on the role if at any point it is required.
Ok, so after the permissions thing, it is the theme that we will be looking at. This is a very important part.
Implementing the theme
I have two theme variables: like and dislike. Each will have their own tpl which you can easily guess. And they will be using the tpl file which is located in the templates folder. [NOTE: It is very important that the tpl name and the variable in the template are having the same name, or it will not work.
Hook menu
You can see there are four menu items that I have created. Two are for adding like to a node and adding a dislike to the node. And the other two are for adding like and dislike to the comment. Here in the menu items, you can see that I am checking the permissions that I have created in access arguments.
Hook comment load
Now using hook_comment_load() to load the elements to the comment when the comment is getting loaded through Drupal.
In comment->like you can see I have passed likes which is calculating the total likes of the comment entity. And the second is like status which is actually to check if the current user has any like or dislike to the current comment/entity. I have done almost the same thing to the node in hook_node_load() in the code below.
In both codes, you can see a function _get_entity_vote_count that I have used. This is one function to get the vote status where I am using voting API to get the desired results. Here is the function:
Here votingapi_selecte_votes is the voting API function which does the magic for us. $criteria are the array of arguments that are required for the function. For more details about Voting API, you need to check the documentation for Voting API.
After this the only thing that remains on the module is the adding and removing the likes based on the entity.
Here we are using the data which will be coming from ajax post GET method. You can also use POST method which is a bit safer. But as I was developing this module I kept it in GET to test things out. Once I am happy with the testing, I would change it to POST. It really does not make a difference in the way that you code.
When I want to add a like, I need to check if the user has already disliked the same entity. If yes, first we need to remove it. We don’t want a situation where a user can like and even dislike the same entity.
Then we are adding the like to the following entity. The print thing has a “/” to it. Yes, the thing is when using ajax, you cannot return anything. You need to print it. And I failed to find a way to pass both the data expect this way. (If there is a better way, please let me know).
So, now all the code inside my module file is done. Let’s see how we are going to handle the ajax and what code will go inside the js file. As I have told before, the js file code is very much depended on the way the markup is generated. I am using jQuery instead of javascript and so any change in the tpl may result in a change in DOM hierarchy and that might break our jQuery code.
This is just the basic check that I have seen in most of the drupal js files, so just followed the convention. I guess checking Drupal.jsEnabled is a good thing to do anyway.
[NOTE: If you don’t know, Drupal core comes with jquery. It might not show any of the js files at the start if you are not using anything related to jquery. But as soon as you start using it, the required js file with the jquery library is enabled and included.]
This is the javascript which will take care of handling the like to the node. I am just passing the node id as a parameter to this function. The entity type is hardcoded here. (Although that can also be made generic, right now I have found functions which do the job for me.
- Add like to node.
- Add dislike to node.
- Add like to comment.
- Add dislike to comment.
What is it doing? Well, first is the thing about method: GET. Yes, as mentioned earlier, I am using GET here for the data from the page. As I am still testing, the GET is still there. Once I am comfortable with the code, will change these to POST (anyways, its just a node id).
URL here is the menu item that we have added to the hook_menu which has a page callback to _add_entity_like function. Here I used the basepath variable which I have already defined as an inline variable in hook_init. It is a js file and so the famous base_path() will not work. And hardcoding the path is out of question, so this is what I came up with.
Data is like the variables that I will be passing to the function through the url. Here the entity variable is hardcoded and that is why I have four different functions. Will try and eliminate the two functions and make it generic.
The success part is like what will happen once the vote is added to the entity. Right now, in the success part, I am using arrLikeCount which is nothing but the print at the end of the _add_entity_like function. Because we cannot return anything through ajax, I passed a string with data separated by slash and then used split to get the desired data. Rest: its simple jquery where I am changing the data inside the div containers. Basically, if someone clicks on like, then a green thumbs-up icon will come. If he had already disliked it, the red icon will turn grey and the green icon will then get disable-status.
This is the function which handles the click on the like button and triggers the event – the four different functions.
Although the rest four functions are same, still I would add it here just for reference.
Ok, now that all the coding part is done, let’s have a look at the like tpl.
The styling and all is supported by the css file that I have already added in hook_init.
When all these are done, you need to do print the variables in the tpl. Yes, right now they will not be visible automatically. So for the node tpl, you need to print the variables where you want them to be displayed. For example in my bartik theme, I have the following code just after render($content).
Once done, you need to clear the performance cache and then like and dislike links would be visible.
Transforming ideas into impactful solutions, one project at a time. For me, software engineering isn't just about writing code; it's about building tools that make lives better.