Jump to content

Recommended Posts

Posted

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
Posted

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
  • 5 weeks later...
Posted

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?

Posted
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
Posted

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

Posted

How do you wanna solve this Matthew?

By module or by template file?

If (by template)

echo 'Luis got code snippet'

  • Like 1
Posted

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');
}
Posted
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 5
  • 9 months later...
Posted

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');
			}
		}
	}
}
Posted

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
Posted

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();
Posted

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
Posted

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
  • 1 year later...
Posted

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?

Posted

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.

Posted
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.

 
Posted

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
Posted

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
  • 5 months later...
Posted

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

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
×
×
  • Create New...