__('Page Sort and Move', __FILE__), // getModuleInfo title 'summary' => __('Handles page sorting and moving for PageList', __FILE__), // getModuleInfo summary 'version' => 100, 'permanent' => true, 'permission' => 'page-edit', ); } /** * Install a new permission in addition to the regular ProcessPageSort permission * * The "ProcessPageSortMove" permission refers to changing the page's parent, * whereas the "ProcessPageSort" permission refers to changing the sort within the same parent. * */ public function ___install() { parent::___install(); } /** * Save a move/sort request * */ public function ___execute() { $input = $this->wire()->input; $pages = $this->wire()->pages; $sort = $input->post('sort'); if($this->config->demo) { throw new WireException($this->_("Your change was not saved because this site is in demo mode")); } if($sort === null) { throw new WireException($this->_("This Process is only accessible via POST")); } $this->session->CSRF->validate(); // throws exception if invalid $this->user = $this->wire()->user; $this->ids = array(); $ids = explode(',', $sort); foreach($ids as $sort => $id) $this->ids[(int) $sort] = (int) $id; if(!count($this->ids)) return; unset($ids); $this->parent_id = (int) $input->post('parent_id'); $this->move_id = (int) $input->post('id'); $parentPage = $pages->get($this->parent_id); $movePage = $pages->get($this->move_id); if($movePage->id < 2 || !$parentPage->id) return; $this->movePage($movePage, $parentPage); $this->sortPages($movePage, $parentPage); } /** * Saves a page that has had it's parent_id changed * * @param Page $page * @param Page $parent * @throws WirePermissionException * */ protected function movePage(Page $page, Page $parent) { if($page->parent_id == $parent->id) return; if(!$page->moveable($parent)) { throw new WirePermissionException( $this->_("You do not have permission to move pages using this parent") . " - " . $parent->path() ); } $page->setOutputFormatting(false); $page->resetTrackChanges(true); $page->parent = $parent; $page->save(); $this->message("Moved page $page to parent $parent"); $this->isMoved = true; } /** * Updates the sortfield for all pages having the same parent * * @param Page $page * @param Page $parent * @throws WirePermissionException|WireException * */ protected function sortPages(Page $page, Page $parent) { if(!$page->sortable()) { if(!$this->isMoved) { throw new WirePermissionException( $this->_("You do not have permission to sort pages using this parent") . " - " . $parent->path() ); } return; } $sortfield = $parent->sortfield(); if($sortfield && $sortfield != 'sort') { $msg = sprintf($this->_("Your sort was not saved because these pages are automatically sorted by %s."), $sortfield); if(!$this->isMoved) { throw new WireException($msg); } else { $this->message($msg); } return; } $changes = 0; $database = $this->wire()->database; // locate the 'sort' value of the current first sorted item, to use as our starting point // (in case sorting in a pagination other than 1) $sql = "SELECT sort FROM pages WHERE parent_id=:parent_id AND id IN("; foreach($this->ids as $id) $sql .= ((int) $id) . ","; $sql = rtrim($sql, ",") . ") "; if($this->isMoved) $sql .= "AND id!=:move_id "; $sql .= "ORDER BY sort LIMIT 1"; $query = $database->prepare($sql); $query->bindValue(":parent_id", $parent->id, \PDO::PARAM_INT); if($this->isMoved) $query->bindValue(":move_id", $this->move_id, \PDO::PARAM_INT); $query->execute(); $sortStart = (int) $query->fetchColumn(); $query = $database->prepare("UPDATE pages SET sort=:sort1 WHERE id=:id AND parent_id=:parent_id AND sort!=:sort2"); $query->bindValue(":parent_id", $parent->id, \PDO::PARAM_INT); $pageSort = 0; foreach($this->ids as $sort => $id) { $sort += $sortStart; $query->bindValue(":sort1", $sort, \PDO::PARAM_INT); $query->bindValue(":sort2", $sort, \PDO::PARAM_INT); $query->bindValue(":id", $id, \PDO::PARAM_INT); $query->execute(); if($query->rowCount() > 0) $changes++; if($page->id == $id) $pageSort = $sort; } // trigger hooks $page->set('sort', $pageSort); $page->trackChange('sort'); $page->save(); $parent->trackChange('children'); $parent->save(); $this->wire()->pages->sorted($page, false, $changes); if($changes) $this->message("Updated sort for $changes pages", Notice::log); } }