How to Programatically Override Page Blueprint Options?

Hi all!

I’m building a site where the client will be able to create Landing Pages at will. Each Landing Page is made up of:

  • a Hero Banner section
  • (optional) Information Sections
  • a Contact Section

So, the Hero and the Contact sections are compulsory: every page must have one. The Information Sections are optional, and the client may create a Landing page with none, and another with several. I’ve set this up as a ‘one-pager’: the Landing Page is the parent, and the sections are child pages.

As suggested by @texnixe in another post, I followed the migration docs - “Remove Blueprint-based subpage builder” section - to create a page.create:after hook, so the Landing Page auto-creates the Hero Banner and the Contact Section when it’s created. But, I’m finding that this solution has a couple of issues I’m not being able to work through.

First, I’d like these sections to always show up in the parent page with a ‘listed’ status. The hook is supposed to automatically add a sorting num on the pages when it creates them, but it can only do that IF the pages have changeStatus set to true. This means, unfortunately, that the user will be able to change the status as well, which I don’t want to allow.

Second, I also don’t want to allow the user to delete these 2 sections - they should always be present on the Landing Page. So, I set the delete: option in their blueprints to false. This, however, stops the parent Landing Page from being deleted altogether, because when it tries to delete its children, it can’t, and so the whole delete operation fails. I’ve tried setting up a page.delete:before hook, but cannot seem to be able to delete the subpages programatically while their delete is set to false - even if trying to force-delete using $page->delete(true).

What is the proper way to do this? Is there a way to override these page options programatically? Any guidance is most welcome.

I think there is no way to do things programmatically if the blueprint options are set. However, instead of using blueprint options, you could set the correspondingpage.delete.before and page.changeStatus.before hooks to prevent those actions. The downside is that these options are then not disabled in the interface, but probably better than nothing.

I’m trying to find a workaround - don’t want to give up… I thought that maybe I could try getting the result I want by swapping templates in the page.create:after hook.

I started by creating an empty ‘temp.yml’ template:

title: Temporary Template

Then, in the page.create hook I do this:

  1. create the subpage using the ‘temp’ template (which has no option constrains), and
  2. once the subpage is created and the sort number added, use changeTemplate(), to apply a template that has the options with the restrictions I want.

The config.php code looks like this:

<?php
return [
  'hooks' => [
    'page.create:after' => function ($page) {
      $builder = $page->blueprint()->autobuild();
      if(!empty($builder)) {

        foreach($builder as $build) {
          $missing = a::missing($build, array('title', 'template', 'uid'));
          if(!empty($missing)) continue;
          try {
            $subPage = $page->createChild([
              'content'  => ['title' => $build['title']],
              'slug'     => $build['uid'],
              'template' => 'temp' // use template with no restrictions
            ]);

          } catch (Exception $error) {
            throw new Exception($error);
          }
          if($subPage) {
            $subPage->publish();
            if(isset($build['num'])) $subPage->sort($build['num']);
            // apply correct template:
            $subPage->changeTemplate($build['template']); 
          }
        }

      }
    }
  ]
];

What happens, however, is very strange: the child page for the Hero Banner is created, but then it cannot change the template, and an error quickly flashes on the screen:

So, I tried to alter my ‘temp.yml’ template, like this:

title: Temporary Template
options:
  changeTemplate: true

And then, I get this error:

In both cases, the Hero Banner subpage does get created with the ‘temp’ content file, but the hook is unable to changeTemplate().

Should I give up, or am I close?..