`$parent->createChild()` returns `null` instead of a new `Page` object

Hi all,

I have a script where I query an external API and import the contents into Kirby via $page->createChild() calls. I remember trying to use virtual pages at first, but found it was much slower to parse my API request on each page load versus creating the pages outright. There’s a lot of content.

The API response is cached for 12 hours and is checked for expiry on every page load. It works a bit like WordPress’ pseudo-cron jobs. Once the cache is expired, we do a new API request, cache the response and update the pages with the new content. This has worked perfectly 99% of the time, except today.

In my API response parsing function, we check if the page already exists. If the page already exists, pipe the content to a $page->update($content) call. If its a new page, pipe it to $parent->createChild($props).

Like I said, this has worked so far, but I have this new piece of content that isn’t being saved. Usually when content failed to be saved, an exception of some kind would be thrown. Often times being permission related. This time its different. The page isn’t created, and the function returns null.

Here’s the gist of the function with some extra comments:

$kirby = kirby();
$cache = $kirby->cache(self::$cache);

// $shows is a large array containing all the shows from the cached API response
// $cache is used further down the script in a part that works
$kirby->impersonate('kirby', function () use ($shows, $cache) {

    // balados is french for podcast
	$podcasts = page('balados')->childrenAndDrafts();

	foreach ($shows['data'] as $key => $show) {
		$podcast_slug =  $show['attributes']['slug'];

		$podcast = $podcasts->find($podcast_slug);

        //processShowContent function returns an array of content for the update and createChild calls  below
		$podcast_content = TransistorFmApiHandler::processShowContent($show, $key, $shows);

        // Create a new page if it doesn't already exist
		if ($podcast === null) {

			$foo = $podcasts->createChild([
				'slug'     => $podcast_slug,

				'template' => 'podcast',
				'model'    => 'podcast',
				'content' => $podcast_content

            // If I print out `$foo` here, it is equal to `null`

			$podcast = $foo;
		} else {

			$podcast = $podcast->update($podcast_content);

		// $podcast should be a page here regardless of which path it took, right?

This snipped has worked with the other 28 pages, but is failing with this new one. No exceptions are thrown. I had a try...catch block originally, but I wanted to keep it unhandled to have Whoops come in while debugging.

Any ideas?

createChild() is a page or site method, not a collection method.

1 Like

Ahhhh, you’re right! Thank you so much. I really needed a second set of eyes to take a look at this.

So my original problem is resolved, however I have a new one.

The docs state:

The properties are the same as for Page::create . However, num , parent , site and url are pre-defined by the parent $page and cannot be changed.

However, when I create a page with draft => false, the page gets created without an order number. It’s unlisted and I can’t set num since it’s suposedly set by the parent. Am I using this wrong or is there a bug?

You should be able to set a number…

It seems to be ignored. No matter what number I set, the page is created either as draft or unlisted. Never as listed.

What have you set in your blueprint?

In any case, you should be able to change the number after the page has been created.

In my podcast.yml blueprint, I set statuses to either draft or listed. Technically, unlisted isn’t allowed for this template.

changeNum() works though!