Virtual to Physical

Hello,

I have a collection of 400 or so entries. I pulled in the content from a spreadsheet, making them virtual pages in the panel. Is there a tweak to this method that would create physical pages instead? Essentially I want to import my entries. I do notice that If I edit any given virtual page it’ll create a physical page (folder, etc.).

So maybe there’s a way to either make all my virtual pages physical using some magic OR maybe I start over and tweak the model (as seen in the how-to-article) so it creates physical pages from the start.

Any insight would be appreciated. Thanks.

To create real instead of virtual pages, you can still use the csv() function to read the spreadsheet, and the inner part of the children function from the example (apart from the last line), and put that in a template or in a route, for example:

[
			'pattern' => 'csv',
			'action' => function() {
				if ( kirby()->user() ) {
					$csv      = csv(kirby()->root('index') . '/animals.csv', ';');
					$children = array_map(function ($animal) {
						return [
							'slug'     => Str::slug($animal['Scientific Name']),
							'template' => 'animal',
							'model'    => 'animal',
							'num'      => 0,
							'content'  => [
								'title'       => $animal['Scientific Name'],
								'commonName'  => $animal['Common Name'],
								'description' => $animal['Description'],
							]
						];
					}, $csv);
					foreach ( $children as $child ) {
						page('animals')->createChild($child);
					}
				}
			
				
			}

		],

Then as logged in user, open yourdomain.com/csv and the pages will be created in the given parent page. Make sure the remove the page model once the children are created.

Since this sounds like a one time thing, remove the route again afterwards.
In the example above, the csv file sits in the root of the Kirby installation, but you can of course change this.

1 Like

Yes, that is because you have not overridden Kirby’s writeContent() method in a model, like in this Database example: Content from a database | Kirby CMS

But to to the same for a spreadsheet is not that easy, you would need an external library that can write csv data.

Excellent. This worked great. Now I need to change the status of all these pages. Why doesn’t the following work (this is on the parent template and I am logged in as an admin).

foreach ( $children as $child ) {
  $child->changeStatus("listed");
}

Because $child is not a page object. You have to store the new page in a variable, then call changeStatus()

foreach ( $children as $child ) {
  $newChild = page('animals')->createChild($child);
  $newChild->changeStatus('listed');
}
1 Like

I was running my changeStatus script after all the drafts were created. I should have showed you a bit more of my code. I tried the following (which didn’t work).

$children = $page->children();
foreach ( $children as $child ) {
  $child->changeStatus('listed');
}

Then realized, after your comment, they’re drafts, not pages so I ran the following and it worked.

$children = $page->drafts();
foreach ( $children as $child ) {
  $child->changeStatus('listed');
}
1 Like