From 8b5d96f1b6eb8182328b3d36f5a1eefd21fd5cb5 Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Wed, 5 Feb 2025 14:45:05 -0500 Subject: [PATCH] Fix issue processwire/processwire-issues#2035 plus some related additions to help identify and fix pages that might incorrectly have trash status --- wire/core/PagesEditor.php | 43 +++++++++++++------ wire/core/PagesTrash.php | 1 + .../ProcessPageEdit/ProcessPageEdit.module | 17 ++++++-- .../ProcessPageListRenderJSON.php | 4 ++ 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/wire/core/PagesEditor.php b/wire/core/PagesEditor.php index c370c09c..b4997514 100644 --- a/wire/core/PagesEditor.php +++ b/wire/core/PagesEditor.php @@ -815,6 +815,11 @@ class PagesEditor extends Wire { if($page->templatePrevious) $this->pages->templateChanged($page); if(in_array('status', $changes)) $this->pages->statusChanged($page); } + + if($triggerAddedPage && $page->rootParent()->id === $this->wire()->config->trashPageID) { + // new page created directly in trash, not a great way to start but that's how it is + $this->savePageStatus($page, Page::statusTrash); + } $this->pages->debugLog('save', $page, true); @@ -1094,29 +1099,34 @@ class PagesEditor extends Wire { $database = $this->wire()->database; $rowCount = 0; $multi = is_array($pageID) || $pageID instanceof PageArray; + $page = $pageID instanceof Page ? $pageID : null; $status = (int) $status; if($status < 0 || $status > Page::statusMax) { throw new WireException("status must be between 0 and " . Page::statusMax); } - $sql = "UPDATE pages SET status="; + $sqlUpdate = "UPDATE pages SET status="; if($remove === 2) { // overwrite status (internal/undocumented) - $sql .= "status=$status"; + $sqlUpdate .= "status=$status"; + if($page instanceof Page) $page->status = $status; } else if($remove) { // remove status - $sql .= "status & ~$status"; + $sqlUpdate .= "status & ~$status"; + if($page instanceof Page) $page->removeStatus($status); } else { // add status - $sql .= "status|$status"; + $sqlUpdate .= "status|$status"; + if($page instanceof Page) $page->addStatus($status); } if($multi && $recursive) { // multiple page IDs combined with recursive option, must be handled individually foreach($pageID as $id) { - $rowCount += $this->savePageStatus((int) "$id", $status, $recursive, $remove); + $id = $id instanceof Page ? $id : (int) "$id"; + $rowCount += $this->savePageStatus($id, $status, $recursive, $remove); } // exit early in this case return $rowCount; @@ -1128,15 +1138,17 @@ class PagesEditor extends Wire { $id = (int) "$id"; if($id > 0) $ids[$id] = $id; } - if(!count($ids)) $ids[] = 0; - $query = $database->prepare("$sql WHERE id IN(" . implode(',', $ids) . ")"); - $database->execute($query); - return $query->rowCount(); + if(count($ids)) { + $query = $database->prepare("$sqlUpdate WHERE id IN(" . implode(',', $ids) . ")"); + $database->execute($query); + $rowCount = $query->rowCount(); + } + return $rowCount; } else { // single page ID or Page object $pageID = (int) "$pageID"; - $query = $database->prepare("$sql WHERE id=:page_id"); + $query = $database->prepare("$sqlUpdate WHERE id=:page_id"); $query->bindValue(":page_id", $pageID, \PDO::PARAM_INT); $database->execute($query); $rowCount = $query->rowCount(); @@ -1146,12 +1158,13 @@ class PagesEditor extends Wire { // recursive mode assumed from this point forward $parentIDs = array($pageID); + $ids = []; do { $parentID = array_shift($parentIDs); // update all children to have the same status - $query = $database->prepare("$sql WHERE parent_id=:parent_id"); + $query = $database->prepare("$sqlUpdate WHERE parent_id=:parent_id"); $query->bindValue(":parent_id", $parentID, \PDO::PARAM_INT); $database->execute($query); $rowCount += $query->rowCount(); @@ -1171,13 +1184,19 @@ class PagesEditor extends Wire { /** @noinspection PhpAssignmentInConditionInspection */ while($row = $query->fetch(\PDO::FETCH_ASSOC)) { - $parentIDs[] = (int) $row['id']; + $id = (int) $row['id']; + $parentIDs[$id] = $id; + $ids[$id] = $id; } $query->closeCursor(); } while(count($parentIDs)); + if(count($ids)) { + $rowCount += $this->savePageStatus($ids, $status, false, $remove); + } + return $rowCount; } diff --git a/wire/core/PagesTrash.php b/wire/core/PagesTrash.php index 5df38be1..f8ac92c3 100644 --- a/wire/core/PagesTrash.php +++ b/wire/core/PagesTrash.php @@ -126,6 +126,7 @@ class PagesTrash extends Wire { if($info['restorable']) { // we detected original parent if($this->lastAction !== "restore:$page") $this->pages->restoreReady($page); + $this->pages->editor()->savePageStatus($page->id, Page::statusTrash, true, true); } else if(!$page->parent->isTrash()) { // page has had new parent already set diff --git a/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.module b/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.module index f79c37c3..be88b9d6 100644 --- a/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.module +++ b/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.module @@ -1046,11 +1046,17 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod if($this->page->addable() || $this->page->numChildren) $form->append($this->buildFormChildren()); if(!$this->page->template->noSettings && $this->useSettings) $form->append($this->buildFormSettings()); + if($this->isTrash && !$this->isPost) { - $this->message($this->_("This page is in the Trash")); - $tabRestore = $this->buildFormRestore(); - if($tabRestore) $form->append($tabRestore); + if($this->page->rootParent()->id != $this->config->trashPageID) { + $this->warning($this->_('This page incorrectly has trash status, please “save” to fix it')); + } else { + $this->message($this->_('This page is in the Trash')); + $tabRestore = $this->buildFormRestore(); + if($tabRestore) $form->append($tabRestore); + } } + $tabDelete = $this->buildFormDelete(); if($tabDelete->children()->count()) $form->append($tabDelete); if($this->page->viewable() && !$this->requestModal) $this->buildFormView($this->getViewUrl()); @@ -2565,6 +2571,11 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod } } + if(($value & Page::statusTrash) && $this->page->rootParent()->id != $this->config->trashPageID) { + $value = $value & ~Page::statusTrash; + $this->message($this->_('Removed trash status')); + } + $this->page->status = $value; return true; diff --git a/wire/modules/Process/ProcessPageList/ProcessPageListRenderJSON.php b/wire/modules/Process/ProcessPageList/ProcessPageListRenderJSON.php index fb8b6327..0db9f77c 100644 --- a/wire/modules/Process/ProcessPageList/ProcessPageListRenderJSON.php +++ b/wire/modules/Process/ProcessPageList/ProcessPageListRenderJSON.php @@ -132,6 +132,10 @@ class ProcessPageListRenderJSON extends ProcessPageListRender { if($page->hasStatus(Page::statusLocked)) $icons[] = 'lock'; if($page->hasStatus(Page::statusDraft)) $icons[] = 'paperclip'; if($page->hasStatus(Page::statusFlagged)) $icons[] = 'exclamation-triangle'; + if($page->hasStatus(Page::statusTrash) && !$page->rootParent()->isTrash()) { + $icons[] = 'trash'; + $icons[] = 'exclamation-triangle'; + } $numChildren = $this->numChildren($page, 1); $numTotal = strpos($this->qtyType, 'total') !== false ? $page->numDescendants : $numChildren;