Jump to content

[Solved] First PW cron job--tips on getting started?


MarcC
 Share

Recommended Posts

I would like to make a cron job that moves pages from one parent to another parent, if a given page field has ID == n. It's kind of a cleanup function--somebody can mark a "project" page as "complete" and it is auto-archived.

I'm new to this sort of scripting, so I looked at the API to see if I could figure out how to move a page. Would I clone the page with the different parent, then delete the page? That seems like one option that stood out as I browsed the cheat sheet.

Thanks for any tips.

Link to comment
Share on other sites

Basically do what these chaps are saying - add a checkbox field like Soma says, then as Apeisa says have a module look for the checkbox before the page is saved and if it's checked then change the parent and continue saving as normal.

If I had more time this morning there actually is very little code to this but I've got to go to work - I'm 100% certain someone will be here with some code soon though :D

The actual code that does the page "moving" in amongst the other module code is actually as simple as this:

// ...Module code above to intercept page save, check for correct template and a ticked checkbox
 
$page->parent = $pages->get('/path/to/archive/page/');
 
// ...Rest of module code. No need to $page->save(); since we're going to hook before page save so the save routine will continue as normal after this
Link to comment
Share on other sites

Thanks guys. Do I really have to use the checkbox? (And write a module?) My client is already using a drop-down menu for "In Progress," "Waiting for Customer," "Completed," etc. So a checkbox would actually make the design more complex for the client. They just want to set the item to "Completed" and see it archived sometime in the next day. :-) They are using a front end that already hides an item if it is marked as Completed.

$page->parent = $pages->get('/path/to/archive/page/');

Ah, of course. Seems so simple compared to what I was thinking.  :-[

Link to comment
Share on other sites

They want to archive it so it doesn't appear in the same list as all the other projects in the back end. First I said, "just unpublish it" but now they have items that are crossed out next to all the normal items. Since some staff are more comfortable using the back end, this is kind of a visual clutter problem. They even offered to move items back out of the archive by themselves if they ever need to reuse.

What do I need to know to make this work in a cron job? Do I need to do $page->save after I change the parent?

Link to comment
Share on other sites

You could do this via LazyCron, but since you probably want to archive it right away you save the page, I think most logical place would be just hook into page save process. This should get you pretty close (written in browser):

class MovePage extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Move page after saving it with certain value',
      'summary' => 'Modules are easy and fun.',
      'version' => 1 
      'autoload' => true,
    );
  }
  public function init() {
    $this->pages->addHookAfter('save', $this, 'hookSave'); 
  }

  public function hookSave(HookEvent $event) {
    $page = $event->object; 
   
    // No need to to anything, if field isn't archived
    if ($page->my_page_field->id != 1234) return;

    // If it is archived, then we remove the archived (this avoids pagesave loop
    $page->my_page_field->remove(1234);
    $page->parent = $this->pages->get("/archived/");
    $page->save();
  }
}
Link to comment
Share on other sites

It gives you the page that is being saved. wire('page') would give you the admin page (page edit -page).

That event stuff feels little mysterious when you're starting with autoload modules, and it you will grok it soon. Lots of information here on forums about it.

  • Like 1
Link to comment
Share on other sites

I don't know, but would guess that it would just throw error when you save archived page in admin. You don't have to remove it though, you might check the parent also (if page is already in archive, don't move and save).

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

Hey apeisa, I installed the module but it's not archiving. Any ideas? Error logs are clean and I've adjusted the code to fit the corresponding field.

<?php

class AutoArchive extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Move page to archive after saving it with certain value',
      'summary' => 'It can\'t be this simple.',
      'version' => 1,
      'autoload' => true
    );
  }
  public function init() {
    $this->pages->addHookAfter('save', $this, 'hookSave'); 
  }

  public function hookSave(HookEvent $event) {
    $page = $event->object; 
   
    // No need to to anything if project is not marked as complete.
    // I checked my sample project and its ID returns 1157.
    // But it doesn't get archived (placed under the projects-archive parent) when saved.
    if ($page->project_status->id != 1157) return;

    // If it is marked as complete / 1157, then we remove the marked as complete part (this avoids pagesave loop)
    $page->project_status->remove(1157);
    $page->parent = $this->pages->get("/projects-archive/");
    $page->save();
  }
}

?>
 

Not sure how to use breakpoints or something similar for modules, or I would have tried that. Thanks.

Link to comment
Share on other sites

Is project_status an Array if there can be only one page selected?

Can you try this:

$statusPage = wire('pages')->get(1157);
$page->project_status->remove($statusPage);

Also for testing if your hook really gets executed:

if ($page->project_status->id == 1157) die("Hook gets executed...");

This should give you an ugly white page if you save a project marked as 'complete'.

Link to comment
Share on other sites

Thanks Wanze--that results in:

Error    Call to a member function remove() on a non-object

And no white page. So it does seem like it is trying to work. Field type is single page or boolean false when none selected.

Code so far:

<?php

class AutoArchive extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Move page to archive after saving it with certain value',
      'summary' => 'It can\'t be this simple.',
      'version' => 1,
      'autoload' => true
    );
  }
  public function init() {
    $this->pages->addHookAfter('save', $this, 'hookSave'); 
  }

  public function hookSave(HookEvent $event) {
    $page = $event->object; 
   
    // No need to to anything if project is not marked as complete.
    // I checked my sample project and its ID returns 1157.
    if ($page->project_status->id == 1157) die("Hook gets executed...");

    // If it is marked as complete / 1157, then we remove the marked as complete part (this avoids pagesave loop)
    $statusPage = wire('pages')->get(1157);
    $page->project_status->remove($statusPage);
    $page->parent = $this->pages->get("/projects-archive/");
    $page->save();
  }
}

?>
 
Link to comment
Share on other sites

Actually it looks like the test is failing:

if ($page->project_status->id == 1157)

...is returning false. But that is the ID that the field contains. Weird. And when I echo that variable elsewhere (just as a test), it comes up as 1157. Help! :D

Link to comment
Share on other sites

Well, solved it by trying something I found in Ryan's docs.

I noticed that $event->object didn't seem to be storing any ID or name data. So instead of using $page = $event->object, I tried $page = $event->arguments[0] and it worked.

ProcessWire's save message still says it's saved under the old parent, which is kind of weird since it's just been moved under a different parent, so if anybody knows a workaround, let me know. (Edit: Added a $this->message, which helps but they still see 2 separate save messages)

Final changes: (Would love any feedback you have)


    $page = $event->arguments[0]; 
   
    // No need to to anything if project is not marked as complete.
    // I checked my sample project and its ID returns 1157.
    if ($page->project_status->id != 1157 && $page->parent->name == 'projects-archive') {
	    //not completed and it's in the archive. Get it back to the projects page.
    	$page->project_status->remove();
    	$page->parent = $this->pages->get(1131); //projects page
    	$page->save();
	    
    } elseif ($page->project_status->id != 1157) {
    	//just a normal page.
	    return;
    }

    // If it is marked as complete / 1157, then we remove the marked as complete part (this avoids pagesave loop)
    if ($page->project_status->id == 1157 && $page->parent->name != 'projects-archive') {
    	//completed and not in archive. move to archive.
    	$page->project_status->remove(1157);
    	$page->parent = $this->pages->get(1322); //projects archive page
    	$page->save();
    }
Link to comment
Share on other sites

At the top, I'm thinking you want to add something to avoid acting on pages that aren't of your defined type. Something like this: 

if(!$page->template != 'project') return; 

Because this is a single-page reference field (from what I can tell above), I don't think this line would work:

$page->project_status->remove(1157);

That's calling the remove() method of $page, which just unset a value. Since the page likely doesn't have a variable named "1157", the line above essentially does nothing. What you would want to do instead is set project_status to be a blank value, or another page. 

$page->project_status = null; // this
$page->project_status = $pages->get('some other page'); // or this
  • Like 1
Link to comment
Share on other sites

Ha ha, awesome Ryan. I wondered about both of those things. Actually I think I should probably just remove the remove() part anyway. I can't see why it's necessary now to null out the page field, when I have added new logic to test whether the page is already in the archive or not.

//This has nothing to do with you, non-project pages.
    if(!$page->template != 'project') return; 
   
    // No need to to anything if project is not marked as complete.
    // I checked my sample project and its ID returns 1157.
    if ($page->project_status->id != 1157 && $page->parent->name == 'projects-archive') {
	    //marked as incomplete and it's in the archive. Get it back to the projects page.
    	//$page->project_status = null; // remove the status
    	$page->parent = $this->pages->get(1131); //projects page
    	$page->save();
    	$this->message("Moved out of archive. New page location: {$page->url}");
	    
    }

    // If it is marked as complete / 1157, then we remove the marked as complete part (this avoids pagesave loop)
    if ($page->project_status->id == 1157 && $page->parent->name != 'projects-archive') {
    	//completed and not in archive. move to archive.
        //$page->project_status = null; // remove the status    	
        $page->parent = $this->pages->get(1322); //projects archive page
    	$page->save(); 
    	$this->message("Archived. New page location: {$page->url}");
    } 

Is there something I can (or should) do about the "Saved" message that shows an incorrect parent after the module just changed the parent? I have two messages now, the Saved Page message and my own message saying there's a new parent. Thanks!

Link to comment
Share on other sites

This is the current module code after more changes:

<?php

class AutoArchive extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Project Auto-Archiver',
      'summary' => 'If the page is saved and the project_status field is set to completed, archive it. If the project is in the archive and has its status changed away from completed, unarchive it.',
      'version' => 1,
      'autoload' => true
    );
  }
  public function init() {
    $this->pages->addHookAfter('save', $this, 'hookSave'); 
  }

  public function hookSave(HookEvent $event) {
    $page = $event->arguments[0]; 
    
    //This has nothing to do with you, non-project pages.
    if($page->template->name != 'projects') return;
   
    // If the project is not marked as complete and it's already archived, move it back to the normal projects area.
    if ($page->project_status->id != 1157 && $page->parent->name == 'projects-archive') {
    	$page->parent = $this->pages->get(1131); //projects page
    	$page->save();
    	$this->message("Moved out of archive. New page location: {$page->url}");
	    
    }

    // If it is marked as complete, and not in the archive yet, archive it.
    if ($page->project_status->id == 1157 && $page->parent->name != 'projects-archive') {
    	$page->parent = $this->pages->get(1322); //move under projects archive page
    	$page->save(); 
    	$this->message("Archived. New page location: {$page->url}");
    }
  }
}

?>
Link to comment
Share on other sites

Marc, you may want to change your hook from "save" to "saveReady" or "saved". 

If you use "saveReady", then you won't have to perform your own $page->save(); since you'd be hooking in right before $pages does it's own save. This is the same as a before "save" hook, except that it's been confirmed that a save will definitely occur, so a little safer. However, you'll probably want to add something at the top of your hookSave() function like: if(!$page->id) return; so that it doesn't get involved with pages that are about to be saved for the first time. 

If you use the "saved" hook (available in the dev branch of PW), this is essentially the same as what you are already doing, just a little safer, since it wouldn't get called if an error occurred in save(). Though for most practical purposes it's equivalent. I would probably look into using "saveReady" just because that could reduce what's currently happening in 2 saves to just 1. 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...