Create a new page from php or?


#1

Hi everyone, Im doing something a little weird with grav, and its working out amazing so far. Basically a 3D development system in WebGL using Grav.
What I have been wanting to do (currently doing it with separate data) is to be able to create a page dynamically and fill it with some data (in yaml and in content). But Id like to do this from php ideally when I save a scene.

For example: Create a new page in /scenes/generated/mynewscene01

Am I correct in thinking that this can be done via php API? If so, some tips/hints on how this might happen so as not to break Grav :slight_smile: Ive tried a few things, and it hasnt been overly successful.
Any help would be greatly appreciated.
Cheers,
David


#2

@dlannan Would you mind sharing what you have tried so far? You might have been on the right track and only need some finger-pointing to get you going.

Folders/files, frontmatter (yaml) and content can all be created/updated dynamically using PHP with some help of Grav’s API.

What could be handy to know is:

  • The folder structure.
  • Grav’s Lifecycle gives you insight in the process when a url is requested.
  • Event hooks gives your insight as to where in the process your plugin may add logic.
  • Paragraph Page inside the Grav’s API docs shows the api of the page itself. Eg. its getter/setter content() and frontmatter().

As a small example, if you call the following bare PHP function during the onPluginsInitialized event in a plugin…

private function createPage()
{
    $folder = __DIR__.'/../../pages/03.dynamic';
    $file = $folder . '/default.md';

    if (!file_exists($folder)) {
        mkdir($folder);
    }
    file_put_contents($file, "---\nmy-variable: my-value\n---\nThis is dynamic content");
}

… the page user/pages/03.dynamic/default.md will be created and will also immediately be visible in the menu. That’s because onPluginsInitialized is being called before all pages are collected in Grav’s Lifecycle. They become available in the onPagesInitialized event.


#3

@pamtbaau I was just using some php from the suggested samples in the grav docs.
https://learn.getgrav.org/cookbook/plugin-recipes#how-do-i-read-from-and-write-data-to-the-file-system
I ended up using simple file data reading/writing, but thats not really where I wanted to go.

In your example above, this will make a page 03.dynamic in the pages parent folder?
The file_put_contents function - this is a php call, so this is effectively manually making a page?
I guess what I was wondering is if I could call something similar to what the admin “new page” call does so that it works well within the grav environment. Im probably going to need to write that :wink:

I really appreciate taking the time for the sample. I’ll post my solution once I build it.
Thanks again.


#4

@dlannan Uhhh, do you want it all to happen inside the Admin panel?

I think not, but if so, the Admin plugin has its own event hooks. You can write your own plugin and respond to, for example, the onAdminAfterSave event and add your own logic to manipulate the frontmatter and content.

To give you an idea:

public function onAdminAfterSave(Event $e)
{
    // Get the page just saved
    $page = $e->offsetGet('object');

    // Add text to the content
    $content = $page->content();
    $page->content($content . "Add this text to end of file");

    // Add new frontmatter variable and value
    $header = $page->header();
    $header = new \Grav\Common\Page\Header((array) $header);
    $header->set('my-variables.my-variable', 'my-value');
    $page->header($header->items);
    $page->save();
}

#5

Sorry to confuse you. I want it to work like the admin one :slight_smile:
So have a form on client side that has: Scene Name, Some scene settings and some object information.
When I submit that it would be good to “Create Page” in the same way the admin does. And the form data can go into the page (yaml preferably). Your initial example is probably closest to what I will do. I’ll be trying it out in the next few hours. So I’ll let you know how it goes.
Thanks again for your help.


#6

@dlannan The plugin Add Page By Form might be doing something you’re aiming for.

It allows users to add a new page by filling in a form.


#7

@pamtbaau - Excellent suggestion! I had not seen that plugin before. I didnt manage to get to try out the php yesterday. Hopefully tomorrow. But I will definitely try this form first.
I currently have a special page with a hidden form - so this sounds like its a perfect fit. If not I’ll examine the plugin, Im sure it has all I need anyway.
Many thanks pamtbaau - awesome help!


#8

@pamtbaau - Thanks for you suggestions. It took me a couple of days to get the Add Page By Form to work the way I wanted it to. It turns out some of my requirements for submitting data to save was a little tricky to do using it. However, it ended up being quite brilliant, so I really want to thank you for your assistance.

For people interested. I used the above plugin and made a “hidden” form that submits all the data I needed to the plugin. I packed quite a bit of data into the form - be wary about this, there can be issues with sizes and data types. My 3d scene data was very high level.
Then when I access the scene pages I can use twig methods like:

page = page.find(“generated/scenes/scene-01”)

And then access the data in the yaml files where I save it like:

{{ page.header.data }}

So if you are using webGL tools like threejs I can use grav as an asset manager and the webpage can load assets based on page location into the 3D world. Its quite nice and all the assets live in the normal media area of the grav page.

Thanks again for the help.