Jump to content
Brmm

Doing additional logic after saving a new page.

Recommended Posts

Hi, I have a simple question.

I need to do additional logic right after a new page has been created/saved, to be more specific I need to call an API with the value of some of its fields, is this possible in process wire?

Thank you!

  • Like 1

Share this post


Link to post
Share on other sites

You'd want to hook after $pages->save(); If you want your function to execute on every page save, any time, then you'd want to create an autoload module. http://wiki.processwire.com/index.php/Module_Creation

If you want to capture newly added pages separately, then you'd also want to hook $pages->added(), which is called after a new page has been added. This example shows both:

/site/modules/HelloWorld.module

class HelloWorld extends WireData implements Module {
 public static function getModuleInfo() {
   return array(
     'title' => 'Hello World',
     'summary' => 'Just an example module class.',
     'version' => 1 
     'autoload' => true,
   );
 }
 public function init() {
   $this->pages->addHookAfter('save', $this, 'hookSave'); 
   $this->pages->addHookAfter('added', $this, 'hookAdded'); 
 }
 public function hookSave(HookEvent $event) {
   // this function called any time a page is saved (whether new or not)
   $page = $event->object; 
   // now you can access anything from the $page
 }
 public function hookAdded(HookEvent $event) {
   // this function only called after a new page added
   $page = $event->object; 
 }
}
  • Like 4

Share this post


Link to post
Share on other sites

I'm working on a small project which happens to be a photographer portfolio.

I have template which represents an album containing image field with unlimited items with some additional description fields.

Is it possible to automatically create an unpublished blog post (announcing new photos) every time an album is saved with new images added?

Share this post


Link to post
Share on other sites
Is it possible to automatically create an unpublished blog post (announcing new photos) every time an album is saved with new images added?

This should be possible. You'd use a Pages::saveReady hook. You'll want to have your hook do something along these lines:

if($page->template == 'album' && $page->isChanged('images')) {
 $newItems = $page->images->getItemsAdded(); 
 if(count($newItems)) {
   // images were added, create your new unpublished blog post
   // the $newItems WireArray contains the images that were added
 }
}
  • Like 3

Share this post


Link to post
Share on other sites

Greetings,

Glad to find this! I was searching for an answer to a similar question.

Would this same technique be effective in a ProcessWire-based e-commerce application? I'm looking to use ProcessWire to build product pages, and allow customers to place orders as pages, then send the details of that order to FoxyCart.

I'm looking at other techniques as well.

Thanks,

Matthew

Share this post


Link to post
Share on other sites

How do you wanna solve this Matthew?

By module or by template file?

If (by template)

echo 'Luis got code snippet'

  • Like 1

Share this post


Link to post
Share on other sites

Is it possible to manipulate the fieldgroup of an template before it's saved?

Like so:

public function addProcessField(HookEvent $event) {
	$template = $event->object;
	$template->fields->add('process');
}

Share this post


Link to post
Share on other sites
Is it possible to manipulate the fieldgroup of an template before it's saved?

You can hook before Fieldgroups::save or Templates::save. 

public function init() {
  $fieldgroups->addHookBefore('Fieldgroups::save', $this, 'addProcessField'); 
}
public function addProcessField(HookEvent $event) {
  $fieldgroup = $event->arguments[0];
  if(!$fieldgroup->hasField('process')) $fieldgroup->add('process'); 
} 
  • Like 4

Share this post


Link to post
Share on other sites

How about if you wan't to add logic before saving new page?

I'd like to prefill page title and name fields when new product page is added. I've tried hook it to ProcessPageAdd::execute but don't know how to set field values here before form is rendered. If I hook before Inputfield::render I'm able to pre-set values for both title and _pw_page_name but this doesn't look right...

public function createItem(HookEvent $event) {
	
	// limit action to admin pages only
	if (wire('page')->template->flags & Template::flagSystem) {
		
		// get parent page
		$parent = isset($_GET['parent_id']) ? wire('pages')->get($_GET['parent_id']) : null; 

		// add this to item pages only
		if ($parent && $parent->template == 'items') {

			// get the current field
			$field = $event->object;

			// proceed on (empty) title and page name fields only
			if (($field->name == 'title' || $field->name == '_pw_page_name') && $field->value == '' ) {

				// finally, set the value
				$field->set('value', 'some_val');
			}
		}
	}
}

Share this post


Link to post
Share on other sites

I think what you want is to hook after ProcessPageAdd::buildForm. That returns an InputfieldForm object, that you could manipulate with an 'after' hook. The only problem is that method isn't currently hookable. But you can make it hookable by editing the file and prepending 3 underscores to it, i.e. "buildForm" => "___buildForm". I will make this same change in the core source and you'll see it in the next batch of dev commits. 

  • Like 2

Share this post


Link to post
Share on other sites

Muchas gracias Ryan! I'm just bit lost how to continue from here.. How can I get fields from this specific form:

public function createItem(HookEvent $event) {
	$form = $event->object;
	die(var_dump($form->fields));
}

I get data from all existing fields. I've also tried:

// to get from
$form = $event->object;
$form = $event->arguments(0);

// to get fields
$fields = $form->getInputfieldsForm();
$fields = $form->processor()->getInputfieldsForm();

Share this post


Link to post
Share on other sites

OK, had some time to get hands dirty and here's what came up:

module init:

public function init() {
	$this->addHookAfter('ProcessPageAdd::buildForm', $this, 'newItem');
}

function to prefill values on new items:

public function newItem(HookEvent $event) {
			
	// get parent page
	$parent = wire('pages')->get((int)$_GET['parent_id']);
	
	// continue only if new item page
	if ($parent->template->name != 'items') return;
			
	// hook to page inputfields
	$this->addHookBefore('Inputfield::render', function($event) {
		
		$field = $event->object; // current field
		$fields = array('title','_pw_page_name'); // fields to modify
		
		if (in_array($field->name, $fields) && empty($field->value)) {
			$field->set('value', 'some_val');
		}
		
	});
	
}

Looks much better now - doesn't it?

  • Like 1

Share this post


Link to post
Share on other sites

What I did in the past is to hook on InputfieldForm::render and check for if the form is the add page form. Works fine.

  • Like 1

Share this post


Link to post
Share on other sites

I'm trying to add a hook which manipulates a particular page's name on save(). When I save the page using the admin, this works as expected. When creating or saving a page from the API, however, it doesn't seem to work. Why is that?

Share this post


Link to post
Share on other sites

Sorry, I didn't make it clear: My question is whether this is the intended behavior. If it's not the intended behavior, I'll be happy to post some code.

Share this post


Link to post
Share on other sites

The hook should work whether it's in the admin or via the API, but if the code that sets up the hook is in a module that isn't autoloaded or called via the API then it won't work. So it would really help to see exactly how you have things set up.

Share this post


Link to post
Share on other sites
class AbcDatabase extends WireData implements Module {
	
	public static function getModuleInfo() {
		return array(
		        'title' => 'ABC Database', 
		        'version' => 001,
		        'summary' => 'Base module for the Database features',
		        'singular' => true,
		        'autoload' => true,
		        'installs' => array(),
		        'requires' => array(),
		        );
	}
	public function __construct() {
	}
	public function init() {
		$this->pages->addHookBefore('Pages::save', $this, "hookAutoPageName");
	}
	
	public function ready() { // PW API is ready
		// Controllers go here		
	}
	
	public function hookAutoPageName(HookEvent $event) {
	  $pageid = $this->sanitizer->selectorValue($this->input->get->id);
	  $page = $this->pages->get($pageid);
	  
	  // Bases the name of the company template off of the company_name field and keeps them in sync
	  if($page->template == 'company') {
	  	if($page->company_name != '') {
			  $newName = wire('sanitizer')->pageName($page->company_name, true);
			  if($page->name == $newName) return;
			  
			  $pageMatch = $page->parent->child("name=$newName,include=all") ?: '';
			  if($pageMatch->id && $page->id != $pageMatch->id) { //This is a duplicate name, so we have to add an increment to avoid throwing error
			  	
				  while($pageMatch->id) {
				  	$newName = $pageMatch->name . "-1";
				  	$pageMatch = $page->parent->child("name=$newName,include=all") ?: '';
				  }
				  
				  $page->name = $newName;
				}
			  else {
			  	$page->name = $newName;
			  }
			}
		}
	}

Below that is the install and uninstall functions and closing brace.

 

Share this post


Link to post
Share on other sites

Replace:

$pageid = $this->sanitizer->selectorValue($this->input->get->id);
$page = $this->pages->get($pageid);

with:

$page = $event->arguments[0];

Remember the id get variable won't be available on the front-end via the API.

EDIT: Actually, better yet, don't use $page at all, use $p instead - you don't want to overwrite the current $page with the one being saved.

  • Like 2

Share this post


Link to post
Share on other sites

There's also this:

$this->pages->addHookBefore('Pages::save', $this, "hookAutoPageName");
// to either/or
$this->addHookBefore('Pages::save', $this, "hookAutoPageName");
$this->pages->addHookBefore('save', $this, "hookAutoPageName");
  • Like 1

Share this post


Link to post
Share on other sites

Sorry if this is mentioned well elsewhere, but just in case not and in case someone else might find it handy, this example helped me, in a few minutes, get emails sent out, with custom messages, when certain pages were saved.

https://processwire-recipes.com/recipes/extending-page-save-process/

I am repeatedly amazed by the elegance and power of ProcessWire... To Ryan and all fellow PWers—THANK YOU.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By EyeDentify
      Hello dear PW gurus.

      I have stumbled over a strange error that i all of sudden got when trying to upload an image to a images field on a page.
      There where images allready stored in the field that i wanted to keep, but during the upload the error apear and after that all images are gone from the field and i can´t upload any, i just get the error every time.
      I am running ProcessWire 3.0.153 dev.
      Update:
      After looking in the assets folder i find the folder for the page and the image files seems to be there including the ones i tried to upload when the error occured.
      But they don´t show up in the images field in the page editor.
       
      The error reported:
       
      SQLSTATE[01000]: Warning: 1265 Data truncated for column 'ratio' at row 1 And here is a screenshot of the event:

      The TracyDebugger Error reporting:

      I hope you fine folks could point me in a direction.
      But it seems our old pal set_time_limit() is back.

      Regards, EyeDentify
    • By quickjeff
      Hi Guys, 
      I have been debugging a site for the last 2 hours and cannot solve the issue. 
      I have a site running on 3.0.148. 
      I installed the Kongondo Blog module and was updating the templates to include the website style. 
      Once everything was set and done, I checked the page tree to see an error appear. 
      Template must be assigned a name before 'filename' can be accessed
      The same error appears in templates. 
      Debugging Steps
      I checked the templates in the server to ensure I didnt accidentally delete the namespace.  Deleted cache in browser and server under assets Still no go. 
      Any help is appreciated. 
      Thanks! 
    • By Spyros
      Hello
      I'm having a strange issue with the $page->find(), for some reason I'm missing some of the pages from the results. I found then that I was missing all the pages with the same "PAGE NAME". Is it a bug or am I missing something?
      PS 
      If I change the "PAGE NAME" of one of the missing ones then I'm retrieving the page without any problem.
      Thank you
    • By benbyf
      Hi, Looking to create form elements on a page–some input with a colection of form inputs and the appropriate labels and variables for that input. I've used ProForms in the past and rolled out my own when creating simply one off forms, but I wonder if anyone has found a good way of allowing form creation on page editing so that clients can adhocly make and edit forms?
      Thanks
×
×
  • Create New...