'Load more' on home.php

Hello!

I’m building a blog based on the Starterkit. Initially, I want to show 7 articles. Clicking on ‘load more’ should load more.
Of course I followed the cookbook tutorial but ran into some trouble. I also saw this but it didn’t help much: Load more with ajax example on the default page

The problem at the moment is that absolutely nothing happens when ‘load more’ is clicked. I know it goes into the script.js (verified with a console.log), but that’s it.

When I go to http://localhost:8888/betweenracinglines/.json (it runs locally at the moment), I get the debugger saying:
“Undefined variable: more” (that’s referring to the home.json.php)

Here’s how the code looks:

templates/home.php

<?php $articles = page('blog')->children()->visible()->sortBy('date', 'desc'); ?>

<?php snippet('header') ?>

    <ul id="articles" data-page="<?= $page->url() ?>" data-limit="<?= $limit ?>">
      <div class="container">
        <?php foreach($articles as $article): ?>
          <?php snippet('article', compact('article')) ?>
        <?php endforeach ?>

        <button class="load-more">Load More</button>
      </div>
    </ul>

  <?php
    echo js([
      'assets/js/jquery-3.2.1.min.js',
      'assets/js/script.js'
    ]);
  ?>

controllers/home.php

<?php

// This is a controller file that contains the logic for the blog template.
// It consists of a single function that returns an associative array with
// template variables.
//
// Learn more about controllers at:
// https://getkirby.com/docs/developer-guide/advanced/controllers

return function($site, $pages, $page) {

  $articles = $page->children()->visible();
  $count    = $articles->count();

  // check if the request is an Ajax request and if the limit and offset keys are set
  if(r::ajax() && get('offset') && get('limit')) {

    // convert limit and offset values to integer
    $offset = intval(get('offset'));
    $limit  = intval(get('limit'));

    // limit projects using offset and limit values
    $articles = $articles->offset($offset)->limit($limit);

    // check if there are more projects left
    $more = $count > $offset + 1;

  // otherwise set the number of projects initially displayed
  } else {

    $offset   = 0;
    $limit    = 7;
    $articles = $articles->limit($limit);

  }

  return compact('offset', 'limit', 'articles', 'more');

};

templates/home.json.php

<!-- /site/templates/blog.json.php -->
<?php

$html = '';

foreach($articles as $article) {

  // reuse the project snippet to create the HTML for each project
  // we need to set the third parameter to true, to return the
  // snippet content instead of echoing it
  $html .= snippet('article', compact('article'), true);

}

// add $html and $more to the $data array
$data['html'] = $html;
$data['more'] = $more;

// JSON encode the $data array
echo json_encode($data);

script.js

// assets/js/script.js
$(function(){

  var element = $('#articles');
  var url     = element.data('page') + '/.json';
  var limit   = parseInt(element.data('limit'));
  var offset  = limit;

  $('.load-more').on('click', function(e) {

    console.log('Test')

    $.get(url, {limit: limit, offset: offset}, function(data) {

      if(data.more === false) {
        $('.load-more').hide();
      }

      element.children().last().after(data.html);

      offset += limit;

    });

  });

});

Hope you can help me out! Thanks!

You are redefining your articles in your template, that doesn’t make sense. Where do you want to get the articles from? As children of the home page (as you define them in the controller) or as children of the blog page (as in your template)? Make sure you are fetching the right children.

When directly accessing the .json template, the $more variable is not defined, it is only defined if the request is an Ajax request, so this is correct.

Hey!

No, the articles are children of page(‘blog’), so the definition in the template is okay. When I take it out of the templates, it won’t actually load the articles.
How should I define this in the controller? When I put the line you quoted in there, it doesn’t do anything.

Thanks

This line in the controller is obviously not correct, if the articles are children of the blog page. You have to change this to

 $articles = page('blog')->children()->visible();

and remove your article definition form the template. Otherwise your controller can’t work as expected.

Oh, of course! Sorry, I didn’t see that line in the code :slight_smile:

What you said works in the sense that now 7 ($limit) articles get displayed instead of all of them. The ‘load more’ button still does nothing, though. :frowning:
Could it be because the script.js calls the wrong URL?

var url     = element.data('page') + '/.json';

No, the URL should be correct. What does your console say?

Nothing at all. Neither before (no 404’s or anything) nor when I click the button.

So it doesn’t even log your “Test” to console if you click the button? Have you cleared the cache?

‘Test’ works, but nothing else. Yep, cleared cache.

Then I suggest you add some more log commands to see how far it works, log the element, url, offset and limit; and then log the data response.

I managed to get a bit closer to the error…

$('.load-more').on('click', function(e) {

    $.get(url, {limit: limit, offset: offset}, function(data) {

      if(data.more === false) {
        $('.load-more').hide();
      }

      element.children().last().after(data.html);

      offset += limit;

    });

If I debug url, limit and offset before the $.get, it’s fine. If I try to log anything inside the $.get, nothing happens. So I assume he doesn’t do the $.get part. But I wonder why because the parameters are fine. I also tried to copy/paste it again from the cookbook, but that didn’t change, so there were no typos or so.

url returns http://localhost:8888/betweenracinglines/.json
limit and offset return 7

Have you removed the html comment from your home.json.php template like I said in the documentation?

1 Like

No :man_facepalming:t2:

It works now! Thank you so much!