Simple "Like"-feature

Good morning everyone! I was wondering if it was easy to build a simple “Like”-feature with Kirby? Basically I have a blog and on the blogpost-page a user should be able to click a “Like”-button that increments a field in blogpost.txt by 1. I’m not worried about multiple clicks for now. I’ll take care of that later.

Is that possible? Any tips that point me in the right direction would be greatly appreciated!

Hello @rppld, there’s a plugin for Kirby called Kudos, you should check it out.

Hey, thanks! I’ve already looked into that, but I wanted to check if there’s an easy way to get by without jQuery first :slightly_smiling: If it turns out to be too much effort I’ll go for the plugin.

A very basic approach is to just call a script that updates the field on every click with the $page->update() method.

Ah, nice! Thanks for that. Didn’t know about the update()-method. I’ll just wrap it in a form and post via ajax then. Hope it’s really that easy, hehe.

@texnixe Would you suggest it’s best to put this update function in a plugin? E.g. like so:

site/plugins/like/like.php

<?php

  function like() {
    // Update function
  }

?>

How do I call the like() function via the form in the template then?

Since you are using ajax, you could register a route in your plugin and call the like function from there passing the uri as argument:

kirby()->routes(array(  
    array(
        'pattern' => '(:all)/like',
        'method'  => 'POST',
        'action'  => function($uri) {
            // check if page exists

            like($uri);

            // ...
        }
    )
));
1 Like

Oh, that would be elegant, you’re right @pedroborges, thanks! Let me see if I can make this work!

Alright, I feel like I’m almost there, but it doesn’t work yet.

site/plugins/like/like.php

<?php

kirby()->routes([

  [
    'pattern' => "/like:(:any)",
    'method'  => 'POST',
    'action'  => function($uid) {
      $post = page('blog/' + $uid);
      try {
        $post->update(array(
          'likes' => 1000
        ));
        echo 'The page has been updated';
      } catch(Exception $e) {
        echo $e->getMessage();
      }
    }
  ]

]);

I’m making the Ajax call like that:

const btnLike = document.querySelector('.js-like');
if (btnLike) {
  btnLike.addEventListener('click', function() {
    console.log('like clicked');
    request
      .post('/like:super-t')
      .end(function(err, res) {
        if (!err) console.log('liked');
        else console.log('error');
      });
  });
}

and it’s logging “liked” in the console, so that should be fine. “super-t” is the uid of a blog post. Any idea what I’m missing here?

You are using the + operator instead of . (probably because you wrote JS before, happens to me all the time :smiley:):

$post = page('blog/' . $uid);

If it still doesn’t work, could you please request the URL directly in your browser without AJAX and check if there is any output?

Ah, true! Fixed the operator, still no luck with updating the likes count though. If I access http://localhost:3000/like:super-t in the browser it shows the homepage. I’ve set the blog-page to be the homepage and I’m omitting “blog” in the URLs of post-pages as explained here. Just in case that’s relevant.

Ah, I think Kirby parses that URL as a param.
The pattern "/like/(:any)" should work.

Ah okay, I’ve changed that accordingly, but now when I open http://localhost:3000/like/super-t in the browser it redirects to the error page. I also get a 404 in the AJAX request.

Well, that probably depends on your other route that redirects blog URLs. Make sure to add the new route before that.

Hmm, okay strange. I removed all other routes, but still no luck unfortunately. I still get the 404 when I access http://localhost:3000/blog/like/super-t and in the AJAX call. Here’s the current plugin file:

site/plugins/like/like.php

<?php

kirby()->routes([

  [
    'pattern' => "/blog/like/(:any)",
    'method'  => 'POST',
    'action'  => function($uid) {
      $post = page('blog/' . $uid);
      try {
        $post->update(array(
          'likes' => 1000
        ));
        echo 'The page has been updated';
      } catch(Exception $e) {
        echo $e->getMessage();
      }
    }
  ]

]);

and this the AJAX call:

const btnLike = document.querySelector('.js-like');
if (btnLike) {
  btnLike.addEventListener('click', function() {
    console.log('like clicked');
    request
      .post('/blog/like/super-t')
      .end(function(err, res) {
        if (!err) console.log('liked');
        else console.log('error');
      });
  });
}

If things worked correctly, what am I supposed to see instead of the 404 error?

Have you tried to remove the post method and also the slash before ‘blog’ in your pattern?

Nice, that was it! It works! Removed the method in the plugin and changed the AJAX call from POST to GET also. So it successfully updates the likes count if I pass a static value (e.g. 20) in the update function, but if I attempt to increment the count on each page reload, it doesn’t update at all. This is my current attempt:

site/plugins/like/like.php

<?php

kirby()->routes([

  [
    'pattern' => "blog/like/(:any)",
    'action'  => function($uid) {
      $post = page('blog/' . $uid);
      $likesCount = $post->likes();
      $likesCount++;
      try {
        $post->update(array(
          'likes' => $likesCount
        ));
        echo 'The page has been updated';
        echo $likesCount;
      } catch(Exception $e) {
        echo $e->getMessage();
      }
    }
  ]

]);

I’m sure I’m overlooking something super easy, but I’m having the hardest time with this, haha.

Does the following work?

$likesCount = $post->likes()->int();
$likesCount++;

No, unfortunately not. I’ve also tried something like

$post->update(array(
  'likes' => function($likesCount) {
    return $likesCount++;
  }
));

but that breaks the whole thing.

No, functions are not currently supported (but that’s a great idea, I have created a feature request issue).

We unfortunately can’t really help with line-by-line debugging. You need to test it yourself by adding dump statements here and there to check what the value is and where it gets wrong.