Jump to content

Accessing previous version of page before/after page save


Pete
 Share

Recommended Posts

Is it possible to do this inside a module?

I tried before page save to get the page using something like $previousVersion = wire('pages')->get($page->id); but that didn't work (and certainly wouldn't work after page save ;)).

It's probably something simple like $_POST vars I bet, but just wanted to check.

Link to comment
Share on other sites

ProcessWire keeps a memory cache of pages loaded, so when you retrieve a page, its going to be the same instance of that page when you retrieve it elsewhere. But once you save a page (in the API) that memory cache gets cleared. If you wanted to keep an in-memory copy of it before it was saved, you'd want to clone it sometime before the page is saved:

$pageCopy = clone $page; 

From that point forward, any changes to $page won't be seen in $pageCopy. This clone will cease to exist once it is out of memory scope.

For obvious reasons, file-based assets aren't cloned here. So if your clone depends on file/image assets, then you have to create a new page not just in memory, but on database/disk too. Here's how you do that:

$pageCopy = $pages->clone($page); 

That does a recursive clone, cloning not just that page, but any children too. See the parameters to the $pages->clone() function for additional options to control this. You can also specify that you want it to clone to a different parent. Be careful with the cloning as it's something you probably don't want to do on every page save. It can be an expensive operation if there are lots of files or subpages associated with the cloned page.

  • Like 1
Link to comment
Share on other sites

So is there no way when you click Save on a page to have a module access the page's field contents as they were before you hit Save or are you saying that even before save the copy of that page in the memory would be the new one even if it's not saved yet? Surely the old copy in the database should be accessible somehow since we're hookig before page save without the need to clone it?

Literally all I want to do is compare the value of a field before the person hit Save and what the value is after they click Save by using a beforePageSave hook if that makes sense.

Link to comment
Share on other sites

Okay I think I understand what you are saying. So you want to just load a fresh copy from the database, not keep an existing copy at some state in memory. Do this to load a fresh copy from the database:

wire('pages')->uncacheAll();
$oldPage = wire('pages')->get($page->id); 
  • Like 2
Link to comment
Share on other sites

  • 10 years later...
On 3/16/2012 at 4:06 PM, ryan said:

Okay I think I understand what you are saying. So you want to just load a fresh copy from the database, not keep an existing copy at some state in memory. Do this to load a fresh copy from the database:

wire('pages')->uncacheAll();
$oldPage = wire('pages')->get($page->id); 
 

I have the same request like Pete and the autor of Hooks, compare page before and after save , I need the unchanged page in the state like it was before the page was saved.

Before reading this post, I tried to implement a hook before Pages::save, but I always get the changed page there.
I tried to add your code to get the old page, but 1. it still gives me the already changed page, and 2. adding this code reverts the changes after saving.

I mean, I change something in the page, save this page, (my hook is triggered), when the saved page in backend is reloaded, my changes are gone.

That is my code:

$this->addHookBefore('Pages::save', function (HookEvent $event) {
 $page = $event->arguments(0);
 if ($page->hasField('my_questions')) {
  wire('pages')->uncacheAll();
  $oldPage = wire('pages')->get($page->id);

  $this->log("Questions before: " . $page->my_questions);
  $this->log("Questions after : " . $oldPage->my_questions);
 }
});

Any ideas how I can get the "oldPage" that realy works?

p.s. I am working in ProcessWire 3.0.184

 

Link to comment
Share on other sites

Finally after a half day if searching an testing I think I have found a solution that works in

how-to-get-a-list-of-all-changes-on-page-save#comment-203833
if anyone needs this, use this code:

$oldPage = $this->pages->getById($page->id, array(
 'cache' => false,    // don't let it write to cache
 'getFromCache' => false,// don't let it read from cache
 'getOne' => true,    // return a Page instead of a PageArray
));

it gives the unsaved page and works in the current master version.

Link to comment
Share on other sites

12 hours ago, Zeka said:

Not sure, but probably getFresh method is applicable in such a case. 

https://processwire.com/api/ref/pages/get-fresh/

Intern it seems that getFresh() works similar like my example above, in my tests both methods work exacly identical.

I would prefer getFresh(), because it looks more understandable in code.

 

But I still discovered one issue with both methods...

When I remove an item from my field, it works like expected, and the "oldPage" still contains the the removed item, while the current page doesn`t contain it.
But in the oposide way, when I add a new Item, BOTH variables oldPage AND current page already contain the new item (no matter if I use getFresh() or the code from my post).

I think the reason is, because the field is a repeater and repeater items are created as separate page.
Maybe the creation of the Repeater Item comes even before my hook, and already adds the item to the page.

Any ideas how to fix this ?

 

Link to comment
Share on other sites

I discovered that new items in $oldPage have the status 3073 (what matches Page::statusHidden, Page::statusUnpublished).

So my way to detect new pages to check

if($item->isHidden() && $item->isUnpublished()) $newItem = true;
Link to comment
Share on other sites

On 4/21/2022 at 9:35 AM, Radon said:

I think the reason is, because the field is a repeater and repeater items are created as separate page.
Maybe the creation of the Repeater Item comes even before my hook, and already adds the item to the page.

For those who do no have access to the Pro fields support forum, Ryan expains a similar issue like this:

"One thing about repeaters is that they sometimes have extra pages in them called "ready pages", which are basically abandoned new items that are saved for the next time you need to add an item to the repeater. So in your loop that iterates the repeater items, you'll want to check that the items are published and/or not hidden before considering them valid for your calculations. if($child->isUnpublished() || $child->isHidden()) continue."

see: https://processwire.com/talk/topic/24967-hook-says-there-are-twice-as-much-repeater-items/?do=findComment&comment=210451

 

 

 

 

  • Thanks 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...