diff --git a/wire/core/Pages.php b/wire/core/Pages.php index 7f54789b..5aae8114 100644 --- a/wire/core/Pages.php +++ b/wire/core/Pages.php @@ -8,7 +8,7 @@ * * This is the most used object in the ProcessWire API. * - * ProcessWire 3.x, Copyright 2019 by Ryan Cramer + * ProcessWire 3.x, Copyright 2020 by Ryan Cramer * https://processwire.com * * @link http://processwire.com/api/variables/pages/ Offical $pages Documentation @@ -49,10 +49,13 @@ * @method added(Page $page) Hook called when a new page has been added. * @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 restored(Page $page) Hook called when a page has been moved OUT of the trash. - * @method deleteReady(Page $page) Hook called just before a page is deleted. - * @method deleted(Page $page) Hook called after a page has been deleted. + * @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. + * @method deleteBranchReady(Page $page, array $options) Hook called before a branch of pages deleted, on initiating page only. + * @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 renamed(Page $page) Hook called after a page has been successfully renamed. @@ -1677,6 +1680,18 @@ class Pages extends Wire { } } + + /** + * Hook called when a Page is about to be trashed + * + * @param Page $page + * @since 3.0.163 + * + */ + public function ___trashReady(Page $page) { + if($page) {} // ignore + } + /** * Hook called when a page has been moved to the trash * @@ -1733,9 +1748,11 @@ class Pages extends Wire { * #pw-hooker * * @param Page $page Page that is about to be deleted. + * @param array $options Options passed to delete method (since 3.0.163) * */ - public function ___deleteReady(Page $page) { + public function ___deleteReady(Page $page, array $options = array()) { + if($options) {} // ignore foreach($this->types as $manager) { if($manager->hasValidTemplate($page)) $manager->deleteReady($page); } @@ -1747,10 +1764,12 @@ class Pages extends Wire { * #pw-hooker * * @param Page $page Page that was deleted + * @param array $options Options passed to delete method (since 3.0.163) * */ - public function ___deleted(Page $page) { - $this->log("Deleted page", $page); + public function ___deleted(Page $page, array $options = array()) { + if($options) {} + if(empty($options['_deleteBranch'])) $this->log("Deleted page", $page); /** @var WireCache $cache */ $cache = $this->wire('cache'); $cache->maintenance($page); @@ -1758,6 +1777,40 @@ class Pages extends Wire { if($manager->hasValidTemplate($page)) $manager->deleted($page); } } + + /** + * Hook called before a branch of pages is about to be deleted, called on root page of branch only + * + * Note: this is called only on deletions that had 'recursive' option true and 1+ children. + * + * #pw-hooker + * + * @param Page $page Page that was deleted + * @param array $options Options passed to delete method + * @since 3.0.163 + * + */ + public function ___deleteBranchReady(Page $page, array $options) { + if($page && $options) {} + } + + /** + * Hook called after a a branch of pages has been deleted, called on root page of branch only + * + * Note: this is called only on deletions that had 'recursive' option true and 1+ children. + * + * #pw-hooker + * + * @param Page $page Page that was the root of the branch + * @param array $options Options passed to delete method + * @param int $numDeleted Number of pages deleted + * @since 3.0.163 + * + */ + public function ___deletedBranch(Page $page, array $options, $numDeleted) { + if($page && $options) {} + $this->log("Deleted branch with $numDeleted page(s)", $page); + } /** * Hook called when a page is about to be cloned, but before data has been touched diff --git a/wire/core/PagesEditor.php b/wire/core/PagesEditor.php index 5594b212..e7bc6637 100644 --- a/wire/core/PagesEditor.php +++ b/wire/core/PagesEditor.php @@ -5,7 +5,7 @@ * * Implements page manipulation methods of the $pages API variable * - * ProcessWire 3.x, Copyright 2016 by Ryan Cramer + * ProcessWire 3.x, Copyright 2020 by Ryan Cramer * https://processwire.com * */ @@ -1044,8 +1044,8 @@ class PagesEditor extends Wire { * @param bool|array $recursive If set to true, then this will attempt to delete all children too. * If you don't need this argument, optionally provide $options array instead. * @param array $options Optional settings to change behavior: - * - uncacheAll (bool): Whether to clear memory cache after delete (default=false) - * - recursive (bool): Same as $recursive argument, may be specified in $options array if preferred. + * - `uncacheAll` (bool): Whether to clear memory cache after delete (default=false) + * - `recursive` (bool): Same as $recursive argument, may be specified in $options array if preferred. * @return bool|int Returns true (success), or integer of quantity deleted if recursive mode requested. * @throws WireException on fatal error * @@ -1055,29 +1055,40 @@ class PagesEditor extends Wire { $defaults = array( 'uncacheAll' => false, 'recursive' => is_bool($recursive) ? $recursive : false, + // internal use properties: + '_level' => 0, + '_deleteBranch' => false, ); - + if(is_array($recursive)) $options = $recursive; $options = array_merge($defaults, $options); $this->isDeleteable($page, true); // throws WireException $numDeleted = 0; + $numChildren = $page->numChildren; + $deleteBranch = false; - if($page->numChildren) { + if($numChildren) { if(!$options['recursive']) { throw new WireException("Can't delete Page $page because it has one or more children."); - } else foreach($page->children("include=all") as $child) { + } + if($options['_level'] === 0) { + $deleteBranch = true; + $options['_deleteBranch'] = $page; + $this->pages->deleteBranchReady($page, $options); + } + foreach($page->children('include=all') as $child) { /** @var Page $child */ - if($this->pages->delete($child, true, $options)) { - $numDeleted++; - } else { - throw new WireException("Error doing recursive page delete, stopped by page $child"); - } + $options['_level']++; + $result = $this->pages->delete($child, true, $options); + $options['_level']--; + if(!$result) throw new WireException("Error doing recursive page delete, stopped by page $child"); + $numDeleted += $result; } } // trigger a hook to indicate delete is ready and WILL occur - $this->pages->deleteReady($page); + $this->pages->deleteReady($page, $options); foreach($page->fieldgroup as $field) { if(!$field->type->deletePageField($page, $field)) { @@ -1099,7 +1110,7 @@ class PagesEditor extends Wire { // delete entirely from pages_parents table $this->pages->parents()->delete($page); - $database = $this->wire('database'); + $database = $this->wire()->database; $query = $database->prepare("DELETE FROM pages WHERE id=:page_id LIMIT 1"); // QA $query->bindValue(":page_id", $page->id, \PDO::PARAM_INT); $query->execute(); @@ -1107,8 +1118,9 @@ class PagesEditor extends Wire { $this->pages->sortfields()->delete($page); $page->setTrackChanges(false); $page->status = Page::statusDeleted; // no need for bitwise addition here, as this page is no longer relevant - $this->pages->deleted($page); + $this->pages->deleted($page, $options); $numDeleted++; + if($deleteBranch) $this->pages->deletedBranch($page, $options, $numDeleted); if($options['uncacheAll']) $this->pages->uncacheAll($page); $this->pages->debugLog('delete', $page, true); diff --git a/wire/core/PagesTrash.php b/wire/core/PagesTrash.php index 8b284951..d64fa713 100644 --- a/wire/core/PagesTrash.php +++ b/wire/core/PagesTrash.php @@ -5,7 +5,7 @@ * * Implements page trash/restore/empty methods of the $pages API variable * - * ProcessWire 3.x, Copyright 2018 by Ryan Cramer + * ProcessWire 3.x, Copyright 2020 by Ryan Cramer * https://processwire.com * */ @@ -45,10 +45,13 @@ class PagesTrash extends Wire { throw new WireException("This page (id=$page->id) may not be placed in the trash"); } - if(!$trash = $this->pages->get($this->config->trashPageID)) { + $trash = $this->pages->get($this->config->trashPageID); + if(!$trash->id) { throw new WireException("Unable to load trash page defined by config::trashPageID"); } + $this->pages->trashReady($page); + $page->addStatus(Page::statusTrash); if(!$page->parent->isTrash()) {