Write JSON file of site index

Im integrating Tipue search into my site, and I need to write JSON file which is a list of all the pages on the site. I will eventually put this into a hook so it runs on page save, but for now i just want to get it working in a page template before porting it into a hook.

My problem is i dont know how to format the json output. Its working but i need it formatted a certain way.

heres what ive got:

<?php
$items = $site->index()->filterBy('template', 'not in', ['search', 'error']);
$last  = $items->last();
$sitepages = array($items);

// Write the file
$json_data = json_encode($sitepages);
file_put_contents('site-search.json', $json_data)
?>

and heres the how i need the json file structured:

// json format
{"pages": [
 <?php foreach ($items as $searchlist): ?>
  {"title": "<?= $searchlist->title()->html() ?>", "text": "<?= $searchlist->pageintro()->html() ?>", "tags": "<?php foreach($searchlist->seokeywords()->split(',') as $tag): ?><?= $tag ?> <?php endforeach ?>", "url": "<?= $searchlist->url() ?>"}<?php if($searchlist !== $last) echo ',' ?>
 <?php endforeach ?>
]}

Any ideas how i can do this?

1 Like
<?php
$items = $site->index();
foreach($items as $item) {
  $data[] = [
  'title' => $item->title()->value(),
  'text' => $item->text()->html()->value()
  // more fields here
];
}
$sitepages = array('pages' => $data);

// Write the file
$json_data = json_encode($sitepages);
file_put_contents('site-search.json', $json_data)
?>
1 Like

Thanks @novacanye but i don’t think that helps. I need to write a json file, and it needs to be in a particular structure, not as RSS feed.

@texnixe Brilliant! Thats very close, thank you. Just two small minor tweaks needed. This is working:

<?php
$items = $site->index()->filterBy('template', 'not in', ['search', 'error']);

foreach($items as $item) {
  $data[] = [
    'title' => $item->title()->value(),
    'text' => $item->pageintro()->html()->value(),
    'tags' =>  $item->seokeywords()->split(','),
    'url' => $item->url(),
];
}

$sitepages = array('pages' => $data);

// Write the file
$json_data = json_encode($sitepages);
file_put_contents('site-search.json', $json_data);

var_dump($json_data);
?> 

However i need the tags item to strip the comma and not be wrapped in [], like this:

"tags": "Home Sweet Home",

And the URL item needs to be unescaped like this:

"url": "http://minerva.dev/projects"

The tags are no problem:

'tags' =>  str_replace(',', ' ', $item->seokeywords()),

or, if you prefer:

'tags' =>  implode(' ', $item->seokeywords()->split(',')),

URL, use the JSON_UNESCAPED_SLASHES flag:

$json_data = json_encode($sitepages, JSON_UNESCAPED_SLASHES);
1 Like

Ok so i have moved this code into a hook, but the file is not getting generated…do i have to do something different with the destination path in a hook?

kirby()->hook(['panel.page.create', 'panel.page.update', 'panel.page.hide'], function($page) {

$site  = site();

$items = $site->index()->visible()->filterBy('template', 'not in', ['search', 'error']);

  foreach($items as $item) {
    $data[] = [
      'title' => $item->title()->value(),
      'text' => $item->pageintro()->html()->value(),
      'tags' =>  str_replace(',', '', $item->seokeywords()),
      'url' => $item->url(),
  ];
  }

$sitepages = array('pages' => $data);

// Write the file
$json_data = json_encode($sitepages, JSON_UNESCAPED_SLASHES);
file_put_contents('site-search.json', $json_data);


});

The problem is your use of the $site variable that is not defined in that context. Replace with site().

And you probably have to give it a path:

f::write(kirby()->roots()->index() . '/site-search.json', $json_data);

I fixed it with this…

$fileoutput = kirby()->roots()->index() . '/search.json';
file_put_contents($fileoutput, $json_data);

Oh but @texnixe your way might be better

and it was better… this works great… thanks for the help…

kirby()->hook(['panel.page.create', 'panel.page.update', 'panel.page.hide'], function($page) {
$items = site()->index()->visible()->filterBy('template', 'not in', ['search', 'error']);
  foreach($items as $item) {
    $data[] = [
      'title' => $item->title()->value(),
      'text' => $item->pageintro()->html()->value(),
      'tags' =>  str_replace(',', '', $item->seokeywords()),
      'url' => $item->url(),
  ];
  }
$sitepages = array('pages' => $data);

// Write the file
$json_data = json_encode($sitepages, JSON_UNESCAPED_SLASHES);
$fileoutput = kirby()->roots()->index() . '/site-search.json';
f::write($fileoutput, $json_data);

});

I have cleaned this up a little and set some variables. However when i try to set the names of the fields to get data from in the array, it breaks.

c::set('ktipuefilename', 'search.json');
c::set('ktipuetempignoretype', 'template');
c::set('ktipuetempignore', ['search', 'error']);

kirby()->hook(['panel.page.create', 'panel.page.update', 'panel.page.hide'], function($page) {
$items = site()->index()->visible()->filterBy(c::get('ktipuetempignoretype'), 'not in', c::get('ktipuetempignore'));
  foreach($items as $item) {
    $data[] = [
      'title' => $item->title()->value(),
      'text' => $item->pageintro()->html()->value(),
      'tags' =>  str_replace(',', '', $item->seokeywords()),
      'url' => $item->url(),
  ];
  }
$sitepages = array('pages' => $data);

// Write the file
$json_data = json_encode($sitepages, JSON_UNESCAPED_SLASHES);
$fileoutput = kirby()->roots()->index() . '/' . c::get('ktipuefilename');
f::write($fileoutput, $json_data);

});

Should I be able to do something like:

c::set('ktipuetitle', title());

and get it back with

'title' => $item->c::get('ktipuetitle')->html()->value(),

Is that possible?

:astonished:

Yes, but not as horrible as above:

// you have to use a string or a boolean or an array as argument
c::set('ktipuetitle', 'title');
// use a fallback here in case the option is not set
'title' => $item->{c::get('ktipuetitle', 'title')}()->html()->value(),

Wow. I have been told off…lol… Thanks :slight_smile:

I actually tried that first bit but what i wasn’t aware of was the currly braces in the second part.

Sorry, didn’t want to be rude… :peace:

No worries, you would have to really go some to offend me :slight_smile:

I think i might turn this into my first Kirby plugin… stay tuned…