JSON call of a structure field

Hello again
I am working on the implementation of an audio player with amplitude.js.
I need to create a JSON with a structure field. I followed the docs about how calling simple field but I don’t know how to do with structure fields…

This is my try

<?php
if(!r::ajax()) go(url('error'));
header('Content-type: application/json; charset=utf-8');
$datastructure = $pages->find('projets')->children()->visible()->addresses()->toStructure();
$data = $datastructure->flip()->paginate(10);
$json = array();
foreach($data as $article) {
    $json[] = array(
        'artist' => (string)$article->artist(),
        'name'  => (string)$article->name(),
        'album'  => (string)$article->album(),
        'url'   => (string)$article->file()->url(),
    );
}
echo json_encode($json);
?>

and my blueprint is

  addresses:
    label: Contributions
    type: structure
    entry: >
      CONTRIBUTEUR : {{album}}<br />
      ARTISTE : {{artist}}<br />
      NOM : {{name}}<br />
      DATE : {{time}}<br />
      FICHIER : {{fichier}}
    fields:
      album:
        label: Contributeur
        type:  text
        icon: user
        width: 1/2
      artist:
        label: Artiste
        type:  text
        icon: microphone
        width: 1/2
      name:
        label: Nom de la chanson
        type:  text
        icon: music
      time:
        label: Date
        type: date
        format: DD/MM/YYYY
        default: today
      fichier:
        label: Fichier audio
        type: select 
        options: files
        icon: file-audio-o

This is not possible, you can only call addresses() on a single page, not a collection.

You can, however, create a new collection from all address items using the following function:

function createNewStructure($pages, $field) {
  $structure = new Structure();
  $key = 0;
  foreach($pages as $p) {
    foreach($p->$field()->toStructure() as $item) {
      $structure->append($key, $item);
      $key++;
    }
  }
  return $structure;
}
$projects = page('projets')->children()->visible();

$items = createNewStructure($projects, 'addresses');
dump($items);

You can then loop through the items as usual.

$json = array();
foreach($items as $item) {
    $json[] = array(
        'artist' => (string)$item->artist(),
        'name'  => (string)$item->name(),
        'album'  => (string)$item->album(),
        'url'   => (string)$item->file()->url(),
    );
}
echo json_encode($json);

If you don’t want the escaped slashes in your URLs, use the JSON_UNESCAPED_SLASHESflag:

$data = json_encode($json, JSON_UNESCAPED_SLASHES);

Thank you for this piece of code, I didn’t think I had to do that !
So, do you tell me to put everything in the same file ? (Currently, my projetsapi.php) Like so :

I tried but it didn’t work (contrary to basic fields). How to do some checks ?

function createNewStructure($pages, $field) {
    $structure = new Structure();
    $key = 0;
    foreach($pages as $p) {
        foreach($p->$field()->toStructure() as $item) {
            $structure->append($key, $item);
            $key++;
        }
    }
    return $structure;
}
$projects = page('projets')->children()->visible();

$items = createNewStructure($projects, 'addresses');
dump($items);



$json = array();
foreach($items as $item) {
    $json[] = array(
        'artist' => (string)$item->artist(),
        'name'  => (string)$item->name(),
        'album'  => (string)$item->album(),
        'url'   => (string)$item->file()->url(),
    );
}

My JS is quite simple

$.getJSON('projets/api', function(getTrack) {
    $.each(getTrack, function(i, songs) {
    });
    Amplitude.init({
        "songs": getTrack
    });
    console.log(getTrack);
});

What exactly does not work? Is there an error in the PHP? Or do you get errors in your JS console? Maybe the json output is not as expected? I’m not familiar with what Amplitude.js expects…

Sorry,
What I wanted to say is that before using your script, the music player was working fine with my previous code, calling the JSON from simple fields.

With your code, the music player doesn’t work, and if I do alert(getTrack); into the JS, I don’t see anything. (I don’t know how to use console.log)

I was expecting to have something like
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object].... as it was previously.

PS : I’m trying to have this kind of structure :

{
                "name": "Song Name 1",
                "artist": "Artist Name",
                "album": "Album Name",
                "url": "myadress../song/url.mp3",
            },
            {
                "name": "Song Name 2",
                "artist": "Artist Name",
                "album": "Album Name",
                "url": "myadress../song/url.mp3"
            },
            {
                "name": "Song Name 3",
                "artist": "Artist Name",
                "album": "Album Name",
                "url": "myadress../song/url.mp3"
            }

I don’t know, from what can see in the amplitude docs, the output is ok:

Amplitude.init({
  "songs": [
    {"artist":"Artist 1","name":"Song 1","album":"Album 1","url":"http://localhost/kirby/content/1-projects/1-project-a/01_flower_of_kilkenny.mp3"},
    {"artist":"Artist 2","name":"Song 2","album":"Album2","url":"http://localhost/kirby/content/1-projects/1-project-a/01_i_wish_i_had_someone_to_love_me.mp3"},
    {"artist":"Artist 3","name":"Song 3","album":"Album3","url":"http://localhost/kirby/content/1-projects/2-project-b/01_working_man.mp3"}
  ]
});

But the URL probably isn’t, try:

'url'   => (string)$item->fichier()->toFile()->url(),

No, (string)$item->fichier()->toFile()->url(), doesn’t work better.

Just to be clear, this is the logic I’m looking for

    {"artist":"Artist 1","name"...},  //From page 1 first structure field entry
    {"artist":"Artist 2","name"...},  //From page 1 second structure field entry
    {"artist":"Artist 3","name"...},  //From page 2 first structure field entry
    // etc...

Please look for errors in your dev tools console, I can’t see these from remote unless your project is online somewhere.

What was your code before that did work (with the single field)?

Anyway, it works for me:

projectsapi.php:

<?php header('Content-type: application/json; charset=utf-8');

function createNewStructure($pages, $field) {
  $structure = new Structure();
  $key = 0;
  foreach($pages as $p) {
    foreach($p->$field()->toStructure() as $item) {
      $structure->append($key, $item);
      $key++;
    }
  }
  return $structure;
}
$projects = page('projects')->children();

$items = createNewStructure($projects, 'addresses');

$json = array();
foreach($items as $item) {
    $json[] = array(
        'artist' => (string)$item->artist(),
        'name'  => (string)$item->name(),
        'album'  => (string)$item->album(),
        'url'   => (string)$item->fichier()->toFile()->url(),
    );
}
$data = json_encode($json, JSON_UNESCAPED_SLASHES);
echo $data;

Script (note that I call the url via PHP here, only possible in the footer)

<?= js('assets/js/jquery.js') ?>
<?= js('assets/js/amplitude.min.js') ?>
<script>
var url = "<?= url('projects/api') ?>";
$.getJSON(url, function(getTrack) {
    $.each(getTrack, function(i, songs) {
    });
    Amplitude.init({
        "songs": getTrack,
        "autoplay": true
    });

});

Note that I’m not using any pagination here, and I don’t quite see the purpose of it in your code above.