mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 08:17:12 +02:00
Add new $pages moveReady(), restoreReady(), and renameReady() hooks. Add option for callback hook on $pages->save(). Improvements to PagesTrash class. Update $pages class so restored() hook does not ever need to be called manually, and update ProcessPageEdit to reflect that.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* This is the most used object in the ProcessWire API.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @link http://processwire.com/api/variables/pages/ Offical $pages Documentation
|
||||
@@ -62,10 +62,12 @@
|
||||
* @method saveReady(Page $page) Hook called just before a page is saved.
|
||||
* @method saved(Page $page, array $changes = array(), $values = array()) Hook called after a page is successfully saved.
|
||||
* @method added(Page $page) Hook called when a new page has been added.
|
||||
* @method moveReady(Page $page) Hook called when a page is about to be moved to another parent.
|
||||
* @method moved(Page $page) Hook called when a page has been moved from one parent to another.
|
||||
* @method templateChanged(Page $page) Hook called when a page template has been changed.
|
||||
* @method trashReady(Page $page) Hook called when a page is about to be moved to the trash.
|
||||
* @method trashed(Page $page) Hook called when a page has been moved to the trash.
|
||||
* @method restoreReady(Page $page) Hook called when a page is about to be restored out of the trash.
|
||||
* @method restored(Page $page) Hook called when a page has been moved OUT of the trash.
|
||||
* @method deleteReady(Page $page, array $options) Hook called just before a page is deleted.
|
||||
* @method deleted(Page $page, array $options) Hook called after a page has been deleted.
|
||||
@@ -73,6 +75,7 @@
|
||||
* @method deletedBranch(Page $page, array $options, $numDeleted) Hook called after branch of pages deleted, on initiating page only.
|
||||
* @method cloneReady(Page $page, Page $copy) Hook called just before a page is cloned.
|
||||
* @method cloned(Page $page, Page $copy) Hook called after a page has been successfully cloned.
|
||||
* @method renameReady(Page $page) Hook called when a page is about to be renamed.
|
||||
* @method renamed(Page $page) Hook called after a page has been successfully renamed.
|
||||
* @method sorted(Page $page, $children = false, $total = 0) Hook called after $page has been sorted.
|
||||
* @method statusChangeReady(Page $page) Hook called when a page's status has changed and is about to be saved.
|
||||
@@ -2198,6 +2201,20 @@ class Pages extends Wire {
|
||||
$page->setQuietly('_added', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page is about to be moved to another parent
|
||||
*
|
||||
* Note the previous parent is accessible in the `$page->parentPrevious` property.
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Page $page Page that is about to be moved.
|
||||
* @since 3.0.235
|
||||
*
|
||||
*/
|
||||
public function ___moveReady(Page $page) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page has been moved from one parent to another
|
||||
*
|
||||
@@ -2258,6 +2275,18 @@ class Pages extends Wire {
|
||||
public function ___trashed(Page $page) {
|
||||
$this->log("Trashed page", $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page is about to be moved OUT of the trash (restored)
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Page $page Page that is about to be restored
|
||||
* @since 3.0.235
|
||||
*
|
||||
*/
|
||||
public function ___restoreReady(Page $page) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page has been moved OUT of the trash (restored)
|
||||
@@ -2387,6 +2416,29 @@ class Pages extends Wire {
|
||||
public function ___cloned(Page $page, Page $copy) {
|
||||
$this->log("Cloned page to $copy->path", $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page is about to be renamed i.e. had its name field change)
|
||||
*
|
||||
* The previous name can be accessed at `$page->namePrevious`.
|
||||
* The new name can be accessed at `$page->name`.
|
||||
*
|
||||
* This hook is only called when a page's name changes. It is not called when
|
||||
* a page is moved unless the name was changed at the same time.
|
||||
*
|
||||
* **Multi-language note:**
|
||||
* Also note this hook may be called if a page's multi-language name changes.
|
||||
* In those cases the language-specific name is stored in "name123" while the
|
||||
* previous value is stored in "-name123" (where 123 is the language ID).
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Page $page The $page that was renamed
|
||||
* @since 3.0.235
|
||||
*
|
||||
*/
|
||||
public function ___renameReady(Page $page) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a page has been renamed (i.e. had its name field change)
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Implements page manipulation methods of the $pages API variable
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -424,6 +424,9 @@ class PagesEditor extends Wire {
|
||||
* - `ignoreFamily` (boolean): Bypass check of allowed family/parent settings when saving (default=false)
|
||||
* - `noHooks` (boolean): Prevent before/after save hooks from being called (default=false)
|
||||
* - `noFields` (boolean): Bypass saving of custom fields (default=false)
|
||||
* - `caller` (string): Optional name of calling function (i.e. 'pages.trash'), for internal use (default='') 3.0.235+
|
||||
* - `callback` (string|callable): Hook method name from $pages or callable to trigger after save.
|
||||
* It receives a single $page argument. For internal use. (default='') 3.0.235+
|
||||
* @return bool True on success, false on failure
|
||||
* @throws WireException
|
||||
*
|
||||
@@ -438,6 +441,8 @@ class PagesEditor extends Wire {
|
||||
'ignoreFamily' => false,
|
||||
'noHooks' => false,
|
||||
'noFields' => false,
|
||||
'caller' => '',
|
||||
'callback' => '',
|
||||
);
|
||||
|
||||
if(is_string($options)) $options = Selectors::keyValueStringToArray($options);
|
||||
@@ -445,6 +450,10 @@ class PagesEditor extends Wire {
|
||||
$user = $this->wire()->user;
|
||||
$languages = $this->wire()->languages;
|
||||
$language = null;
|
||||
$parentPrevious = $page->parentPrevious;
|
||||
$caller = $options['caller'];
|
||||
$callback = $options['callback'];
|
||||
$useHooks = empty($options['noHooks']);
|
||||
|
||||
// if language support active, switch to default language so that saved fields and hooks don't need to be aware of language
|
||||
if($languages && $page->id != $user->id && "$user->language") {
|
||||
@@ -465,19 +474,35 @@ class PagesEditor extends Wire {
|
||||
$page->removeStatus(Page::statusUnpublished);
|
||||
}
|
||||
|
||||
if($page->parentPrevious && !$isNew) {
|
||||
if($page->isTrash() && !$page->parentPrevious->isTrash()) {
|
||||
$this->pages->trash($page, false);
|
||||
} else if($page->parentPrevious->isTrash() && !$page->parent->isTrash()) {
|
||||
$this->pages->restore($page, false);
|
||||
if($parentPrevious && !$isNew) {
|
||||
if($useHooks) $this->pages->moveReady($page);
|
||||
if($caller !== 'pages.trash' && $caller !== 'pages.restore') {
|
||||
if($page->isTrash() && !$parentPrevious->isTrash()) {
|
||||
if($this->pages->trash($page, false)) $callback = 'trashed';
|
||||
} else if($parentPrevious->isTrash() && !$page->parent->isTrash()) {
|
||||
if($this->pages->restore($page, false)) $callback = 'restored';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($options['adjustName']) $this->pages->names()->checkNameConflicts($page);
|
||||
if(!$this->savePageQuery($page, $options)) return false;
|
||||
$result = $this->savePageFinish($page, $isNew, $options);
|
||||
|
||||
if($page->namePrevious && !$isNew && $page->namePrevious != $page->name) {
|
||||
if($useHooks) $this->pages->renameReady($page);
|
||||
}
|
||||
|
||||
$result = $this->savePageQuery($page, $options);
|
||||
if($result) $result = $this->savePageFinish($page, $isNew, $options);
|
||||
if($language) $user->setLanguage($language); // restore language
|
||||
|
||||
if($result && !empty($callback) && $useHooks) {
|
||||
if(is_string($callback) && ctype_alnum($callback)) {
|
||||
$this->pages->$callback($page); // hook method name in $pages
|
||||
} else if(is_callable($callback)) {
|
||||
$callback($page); // user defined callback
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Implements page trash/restore/empty methods of the $pages API variable
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -18,6 +18,14 @@ class PagesTrash extends Wire {
|
||||
*/
|
||||
protected $pages;
|
||||
|
||||
/**
|
||||
* Last action, i.e. "restore:1234"
|
||||
*
|
||||
* @var int
|
||||
*
|
||||
*/
|
||||
protected $lastAction = '';
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
@@ -41,17 +49,18 @@ class PagesTrash extends Wire {
|
||||
*
|
||||
*/
|
||||
public function trash(Page $page, $save = true) {
|
||||
|
||||
|
||||
if(!$this->pages->isDeleteable($page) || $page->template->noTrash) {
|
||||
throw new WireException("This page (id=$page->id) may not be placed in the trash");
|
||||
}
|
||||
|
||||
$trash = $this->pages->get($this->config->trashPageID);
|
||||
$trash = $this->pages->get($this->wire()->config->trashPageID);
|
||||
|
||||
if(!$trash->id) {
|
||||
throw new WireException("Unable to load trash page defined by config::trashPageID");
|
||||
}
|
||||
|
||||
$this->pages->trashReady($page);
|
||||
if($this->lastAction != "trash:$page") $this->pages->trashReady($page);
|
||||
|
||||
$page->addStatus(Page::statusTrash);
|
||||
|
||||
@@ -70,10 +79,10 @@ class PagesTrash extends Wire {
|
||||
// make the name unique when in trash, to avoid namespace collision and maintain parent restore info
|
||||
$name = $page->id;
|
||||
if($parentPrevious && $parentPrevious->id) {
|
||||
$name .= "." . $parentPrevious->id;
|
||||
$name .= "." . $page->sort;
|
||||
$sort = $page->get('sortPrevious|sort');
|
||||
$name .= ".$parentPrevious->id.$sort";
|
||||
}
|
||||
$page->name = ($name . "_" . $page->name);
|
||||
$page->name = ($name . '_' . $page->name);
|
||||
|
||||
// do the same for other languages, if present
|
||||
$languages = $this->wire()->languages;
|
||||
@@ -87,9 +96,13 @@ class PagesTrash extends Wire {
|
||||
}
|
||||
}
|
||||
|
||||
if($save) $this->pages->save($page);
|
||||
$this->lastAction = "trash:$page";
|
||||
|
||||
if($save) {
|
||||
$this->pages->save($page, array('caller' => 'pages.trash', 'callback' => 'trashed'));
|
||||
}
|
||||
|
||||
$this->pages->editor()->savePageStatus($page->id, Page::statusTrash, true, false);
|
||||
if($save) $this->pages->trashed($page);
|
||||
$this->pages->debugLog('trash', $page, true);
|
||||
|
||||
return true;
|
||||
@@ -107,24 +120,30 @@ class PagesTrash extends Wire {
|
||||
*
|
||||
*/
|
||||
public function restore(Page $page, $save = true) {
|
||||
|
||||
$info = $this->getRestoreInfo($page, true);
|
||||
|
||||
if($info['restorable']) {
|
||||
// we detected original parent
|
||||
if($save) $page->save();
|
||||
if($this->lastAction !== "restore:$page") $this->pages->restoreReady($page);
|
||||
|
||||
} else if(!$page->parent->isTrash()) {
|
||||
// page has had new parent already set
|
||||
if($this->lastAction !== "restore:$page") $this->pages->restoreReady($page);
|
||||
$page->removeStatus(Page::statusTrash);
|
||||
if($save) $page->save();
|
||||
$this->pages->editor()->savePageStatus($page->id, Page::statusTrash, true, true);
|
||||
if($save) $this->pages->restored($page);
|
||||
$this->pages->debugLog('restore', $page, true);
|
||||
} else {
|
||||
// page is in trash and we cannot detect new parent
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->lastAction = "restore:$page";
|
||||
|
||||
if($save) {
|
||||
$this->pages->save($page, array('caller' => 'pages.restore', 'callback' => 'restored'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -221,6 +240,7 @@ class PagesTrash extends Wire {
|
||||
|
||||
if($populateToPage) {
|
||||
$page->name = $name;
|
||||
$page->removeStatus(Page::statusTrash);
|
||||
if($newParent) {
|
||||
$page->sort = $sort;
|
||||
$page->parent = $newParent;
|
||||
|
@@ -2157,20 +2157,17 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
|
||||
}
|
||||
}
|
||||
|
||||
$restored = false;
|
||||
if($input->post('restore_page') && $page->isTrash() && $page->restorable()) {
|
||||
if($formErrors) {
|
||||
$this->warning($this->_('Page cannot be restored while errors are present'));
|
||||
} else if($pages->restore($page, false)) {
|
||||
$message = sprintf($this->_('Restored Page: %s'), '{path}') . $numChanges;
|
||||
$restored = true;
|
||||
} else {
|
||||
$this->warning($this->_('Error restoring page'));
|
||||
}
|
||||
}
|
||||
|
||||
$pages->save($page, $options);
|
||||
if($restored) $pages->restored($page);
|
||||
$message = str_replace('{path}', $page->path, $message);
|
||||
$this->message($message);
|
||||
|
||||
|
Reference in New Issue
Block a user