How to implement a download counter


I want to implement a download counter, that’s my page structure:

  - child1 >
  - child2 >

On the parent page, all its children are displayed, with text, images etc and more importantly, they all contain a link to, which is attached to each child page:

<?php foreach($page->children() as $article) : ?>
<a class="download" href="<?= $article->zip()->url() ?>">Download me</a>
<?php endforeach ?>

Now, inside the children’s template, let’s call it article.php, there’s the AJAX php code mentioned above, but with $page->update():

if(r::ajax()) {
    'clicks' => function($clicks) {
      return $clicks++;
  ], null, $kirby->impersonate('kirby'));

… and since clicking is client-side and PHP is server-side, we’d have to make an AJAX call from, say, parent.js:

// jQuery version
  $('.download').on('click', function(e) {
    var url = $(this).attr('href');

… whereas a non-jQuery version probably would look something like this.


Counting clicks on article links

First, you need to actually access the zip file in your loop to be able to call its url() method (with toFile).
Remember that the href attribute now contains a link to the file itself, not its parent page, so you can’t expect to use that as url param in your ajax call. You need to add another reference to the url of the page itself, for example in a data-parent attribute:

<?php foreach($page->children() as $article) : ?>
    <?php if($zip = $article->zip()->toFile()): ?>
        <a class="download" href="<?= $zip->url() ?>" data-parent="<?= $article->url() ?>">Download me</a>
    <?php endif; ?>
<?php endforeach ?>

Then your jquery call. The appropriate method would be post (get requests data, post submits data), and you could instead of listening to every ajax call, explicitely state the action you want to make :

$('.download').on('click', function(e) {
    var url = $(this).attr('data-parent');
    $.post(url, { increment: true });

Later in your controller, you check if there is an increment param given, and there’s actually a handy helper for what you want to achieve:

if(get('increment')) {


Not completely knowing your use case, but I wouldn’t save this kind of info as “content” in my Kirby setup.

I’ld rather use Google Analytics or Matomo for this kind of purpose. Usually those kind of “analytics” softwares have api’s for these kinds of purposes, and this can be visualised in their dashboards then.