Testing a json content representation of my article template

I want to create a JSON representation of my articles so that I can pull the content dynamically with AJAX. I followed this documentation Content Representations . How can I now test the JSON output?

What do you mean by “test”? If you call the URL with the JSON extension, you can see the output, as explained in the docs?

Thanks, I added the JSON extension. I’ve done something wrong. In debugging I got “Error
Call to a member function value() on null”. Do you happen to know what the problem could be?

I lost my crystal ball, but obviously you are calling a method on something that does not exist :wink: So if you provide some code context, that would make things easier.

Sorry about that. in my article.json.php

I have

<?php
 $data = [
  'title' => $article->title()->value(),
  'intro'  => $article->text()->kirbytext(),
  'text'  => $article->text()->kirbytext(),
  'images'  => $article->images()->kirbytext(),
  'date'  => $article->date()->kirbytext()
];

echo json_encode($data);
?>

In my controller I have:

<?php

return function($site, $pages, $page) {
  $article = $site->page('blog')->children()->visible()->flip();

return [
    'articles'  => $articles,
  ];
};
?>
`

Somehow, the controller and the template do not fit together.
In your controller, you use $articles then in the template $article, which is not defined. But if it is a single article, then the controller does not make sense anyway. The controller is rather made for an article overview. For a single articles template, you would use $page and the controller is not necessary.

I want to make a template JSON template of each article so that I can dynamically call each article separately through AJAX on the homepage. In that case I’ve changed it all to:

<?php
$data = [
  'title' => $articles->title()->value(),
  'intro'  => $articles->text()->kirbytext(),
  'text'  => $articles->text()->kirbytext(),
  'images'  => $articles->images()->kirbytext(),
  'date'  => $articles->date()->kirbytext()
];

echo json_encode($data);
?>

and

<?php
return function($site, $pages, $page) {
   $articles = $site->page('blog')->children()->visible()->flip();
return [
    'articles'   => $articles,
  ];
 };
?>

and I still get the initial error.

For my case would it be better to use this method? Getting JSON

As I said above, it doesn’t make sense. Your controller is for an overview page, so you are using a collection. Then you try to call a field on a collection, which does not work.

Your single article template should look like this:

<?php
$data = [
  'title' => $page->title()->value(),
  'intro'  => $page->text()->kirbytext(),
  'text'  => $page->text()->kirbytext(),
  'images'  => $page->images()->kirbytext(),
  'date'  => $page->date()->kirbytext()
];

echo json_encode($data);
?>

And the controller is superfluous.

Ok, I understand that code makes JSON template for a single article.

But say I want to get JSON data of any article from a list of article links on the homepage. How would I go about setting that up?

If you have a list of all articles with a link to that article, you would then intercept the link via a Javascript Ajax call. In your Ajax call, get the URL of the page from the href attribute and add the json extension.

Ok thank you, that’s made it much clearer. Two things, I would like every article in that list to have a json output, so is it still the same set up. And also, when I go to the blog/article-a.json I can’t see the output.

You have to pass strings:

<?php
$data = [
  'title' => $page->title()->value(),
  'intro'  => $page->text()->kirbytext()->value(),

];

echo json_encode($data);

Alternatively, you can use a snippet like in this cookbook recipe: https://getkirby.com/docs/cookbook/ajax-load-more#the-json-template

Say I have images uploaded in the file section, how would I encode that in the JOSN

Would it be
'images' => $page->images() with ->html or ->url or ->image() at the moment it is returning null for either

As I suggested above, your best be is to create a snippet, which generates your html code for the article, then you echo the snippet code. Otherwise, you would have to create the html for the images within a foreach loop and then pass that as string.

Thank you for your help again. I can’t seem to get it to work. I apologise my coding knowledge is very limited.

I’ve tried to define $article in the controller, perhaps there lies my problem.

My JSON:

<?php

$html = '';
$html .= snippet('article', compact('article'), true);

echo json_encode($html);

?>

My controller:

<?php

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

  $article = $page->visible()->flip();

  return array(
    'article'   => $article,
  );
};

The snippet:

<div class="article-title">
    <h3><?php echo html($article->title()) ?></h3>
</div>
<div class="article-body">
    <p><?php echo kirbytext($article->text()) ?></p>
</div>
<div class="article-images">
    <?php if($image = $article->image()): ?>
        <img src="<?= $image->url() ?>" alt="<?= $image->alt_text()->html() ?>" />
    <?php endif ?>
</div>
<div class="article-date">
    <time><?php echo $article->date('d/m/Y') ?></time>
</div>

Your template should look like this:

<?php

$html = '';
$html .= snippet('article', array('article' => $page), true);

echo json_encode($html);

Please remove the controller, it does not make sense.

I’d also change the snippet slightly (note the position of the if-statement):

<div class="article-title">
    <h3><?php echo html($article->title()) ?></h3>
</div>
<div class="article-body">
    <p><?php echo kirbytext($article->text()) ?></p>
</div>
<?php if($image = $article->image()): ?>
  <div class="article-images">
        <img src="<?= $image->url() ?>" alt="<?= $image->alt_text()->html() ?>" />    
  </div>
<?php endif ?>
<div class="article-date">
    <time><?php echo $article->date('d/m/Y') ?></time>
</div>

Thank you @texnixe, you’re a saviour. I just managed to get the AJAX working but it’s only showing one article’s content for each of my links.

My html is:

<a class="load" href="<?= $article->url() ?>" data-page="<?= $article->url() ?>">
  <h3 ><?php echo html($article->title()) ?></h3>
</a>
<div class="article-container">

</div>

My Javascript is

$(function(){

var element = $('.load');
var url     = element.data('page') + '.json';
var target  = $('.article-container');

$(".load").on('click', function(e) {
  e.preventDefault();
  $.get(url, function(data) {
      $(target).append(data);
    });
  });
});

Can you update the documentation accordingly? There seems to be a mistake on https://getkirby.com/docs/developer-guide/advanced/representations#creating-a-representation

It should be like this

$data = [
  'title' => $page->title()->value(),
  'text'  => $page->text()->kirbytext()->value()
];

Thanks for reporting, I’ve fixed it in the repo.