praiadeseselle/wire/modules/Process/ProcessRecentPages/ProcessRecentPages.module
2022-03-08 15:55:41 +01:00

420 lines
12 KiB
Text

<?php namespace ProcessWire;
/**
* Recent pages list for admin
*
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
*
* @todo: make everything configurable
*
* https://processwire.com
*
* Translatable labels:
*
* __('Edited');
* __('Created');
* __('Edited by me');
* __('Created by me');
* __('Add another');
*
*/
class ProcessRecentPages extends Process {
public static function getModuleInfo() {
return array(
'title' => 'Recent Pages',
'summary' => 'Shows a list of recently edited pages in your admin.',
'version' => 2,
'author' => 'Ryan Cramer',
'href' => 'http://modules.processwire.com/',
'icon' => 'clock-o',
'permission' => 'page-edit-recent',
'permissions' => array(
'page-edit-recent' => 'Can see recently edited pages'
),
'page' => array(
'name' => 'recent-pages',
'parent' => 'page',
'title' => 'Recent',
),
'useNavJSON' => true,
'nav' => array(
array(
'url' => '?edited=1',
'label' => 'Edited',
'icon' => 'users',
'navJSON' => 'navJSON/?edited=1',
),
array(
'url' => '?added=1',
'label' => 'Created',
'icon' => 'users',
'navJSON' => 'navJSON/?added=1',
),
array(
'url' => '?edited=1&me=1',
'label' => 'Edited by me',
'icon' => 'user',
'navJSON' => 'navJSON/?edited=1&me=1',
),
array(
'url' => '?added=1&me=1',
'label' => 'Created by me',
'icon' => 'user',
'navJSON' => 'navJSON/?added=1&me=1',
),
array(
'url' => 'another/',
'label' => 'Add another',
'icon' => 'plus-circle',
'navJSON' => 'anotherNavJSON/',
)
)
);
}
/**
* Shared translation labels
*
* @var array
*
*/
protected $labels = array();
/**
* Oldest date to match or pages (hopefully equal to site installation date)
*
* @var int
*
*/
protected $oldestDate = 0;
public function __construct() {
$this->set('itemLimit', 15);
}
public function init() {
$this->addHookProperty('Page::recentTimeStr', $this, 'hookPageRecentTimeStr');
parent::init();
$this->labels['nothing'] = $this->_('No pages match (yet)');
$this->oldestDate = (int) $this->wire('config')->installed;
if(!$this->oldestDate) $this->oldestDate = @filemtime($this->wire('config')->paths->assets . 'installed.php');
}
/**
* Add a 'recentTimeStr' property to all Page objects while this Process is active
*
* @param HookEvent $event
*
*/
public function hookPageRecentTimeStr(HookEvent $event) {
$page = $event->object;
$time = $this->getSort() == '-created' ? $page->created : $page->modified;
$event->return = wireRelativeTimeStr($time, true, false);
}
/**
* Provides output for recent edited/added nav options ajax calls
*
* @param array $options
* @return string
*
*/
public function ___executeNavJSON(array $options = array()) {
$options['add'] = '';
$options['iconKey'] = 'template.icon';
$options['itemLabel'] = 'title|name';
$options['itemLabel2'] = 'recentTimeStr';
$options['sort'] = false;
$selector = str_replace(',,', ',', $this->getSelectorString());
$items = $this->wire('pages')->find("$selector, limit=$this->itemLimit");
if(!$this->wire('user')->isSuperuser()) foreach($items as $item) {
if(!$item->editable()) $items->remove($item);
}
$options['items'] = $items;
return parent::___executeNavJSON($options);
}
/**
* Update selector string to exclude things we won't want showing in any of our results
*
* @param string $selector
*
*/
protected function updateSelectorString(&$selector) {
$adminID = $this->wire('config')->adminRootPageID;
$selector .= ", has_parent!=$adminID";
if($this->wire('modules')->isInstalled('FieldtypePageTable')) {
$this->wire('modules')->get('FieldtypePageTable');
$skipTemplates = array();
$skipParents = array();
foreach($this->wire('fields') as $field) {
if(!$field->type instanceof FieldtypePageTable) continue;
if(!empty($field->parent_id)) $skipParents[] = $field->parent_id;
if(!empty($field->template_id)) {
$value = $field->template_id;
if(is_array($value)) $skipTemplates = array_merge($skipTemplates, $value);
else $skipTemplates[] = $value;
}
}
if(count($skipTemplates)) $selector .= ", template!=" . implode('|', $skipTemplates);
if(count($skipParents)) $selector .= ", parent_id!=" . implode('|', $skipParents);
}
}
/**
* Get selector string to find pages for navJSON (not used by 'add another')
*
* @return string
*
*/
protected function getSelectorString() {
$sort = $this->getSort();
$selector = "include=unpublished, sort=$sort";
$this->updateSelectorString($selector);
if($this->input->get('me')) {
if($sort == '-modified') {
$selector .= ",,modified_users_id=$this->user, modified>=$this->oldestDate";
} else if($sort == '-created') {
$selector .= ",,created_users_id=$this->user, created>=$this->oldestDate";
}
}
return $selector;
}
/**
* Get the current sort for navJSON (not used by 'add another')
*
* @return string
*
*/
protected function getSort() {
if($this->input->get('added')) {
return "-created";
} else {
return "-modified";
}
}
/**
* Provide the interactive view for when user clicks on Added/Edited menu items rather than pages
*
* This basically redirects to a Lister that shows the pages.
*
*/
public function ___execute() {
$selector = $this->getSelectorString();
$useLister = false;
$out = '';
if($useLister) {
if(strpos($selector, ',,') !== false) {
list($initSelector, $defaultSelector) = explode(',,', $selector);
} else {
$initSelector = $selector;
$defaultSelector = '';
}
$a = array(
'initSelector' => $initSelector,
'defaultSelector' => $defaultSelector,
'defaultSort' => $this->getSort(),
);
$url = ProcessPageLister::addSessionBookmark('recent-pages', $a);
if($url) {
$this->session->redirect($url);
} else {
$this->error($this->_('This feature requires page-lister permission'));
}
} else {
$table = $this->wire('modules')->get('MarkupAdminDataTable');
$table->setEncodeEntities(false);
$table->headerRow(array(
$this->_x('Page', 'th'),
$this->_x('Parent', 'th'),
$this->_x('Template', 'th'),
$this->_x('Created', 'th'),
$this->_x('Modified', 'th')
));
$items = $this->wire('pages')->find("$selector, limit=$this->itemLimit");
$sanitizer = $this->wire('sanitizer');
$title = $this->_('Recent pages');
foreach($items as $item) {
if(!$item->editable()) continue;
$created = $item->created;
$modified = $item->modified;
if($created < $this->oldestDate) $created = $this->oldestDate;
if($modified < $this->oldestDate) $modified = $this->oldestDate;
$table->row(array(
"<!--$item->id-->" . $sanitizer->entities1($item->get('title|name')) => $item->editURL,
$sanitizer->entities1($item->parent->get('title|name')),
$sanitizer->entities1($item->template->getLabel()),
"<span class='sort-date'>$created</span>" . wireRelativeTimeStr($created),
"<span class='sort-date'>$modified</span>" . wireRelativeTimeStr($modified)
));
$me = $this->input->get('me');
if($this->getSort() == '-created') {
if($me) $title = sprintf($this->_('Pages recently created by %s'), $this->wire('user')->name);
else $title = $this->_('Recently created pages');
} else {
if($me) $title = sprintf($this->_('Pages recently edited by %s'), $this->wire('user')->name);
else $title = $this->_('Recently edited pages');
}
}
$out .= "<h2>$title</h2>";
if(count($items)) {
$out .= $table->render();
} else {
$out .= "<p>" . $this->labels['nothing'] . "</p>";
}
}
return $out;
}
/**
* The /edit/ option redirects to the page editor for the given page ID
*
* @throws WireException On invalid page ID
*
*/
public function ___executeEdit() {
$id = (int) $this->input->get('id');
if(!$id) throw new WireException("No page ID");
$this->session->redirect("../edit/?id=$id");
}
/**
* Returns array of 'add another' pages
*
* There is only one of each parent/template combination here.
* Each returned page has two additional properties populated:
* - _addAnotherURL: URL to add another of the same type
* - _addAnotherLabel: Recommended label for links
*
* @param int $limit Max items to include
* @param string|int $oldest Timestamp or strtotime() compatible oldest date to retrieve from
* @param int $userID When omitted, current user assumed
* @return array of Page objects
*
*/
public function getAddAnotherNavItems($limit = 10, $oldest = 0, $userID = 0) {
$items = array();
if(empty($oldest)) $oldest = $this->oldestDate;
else if(!ctype_digit($oldest)) $oldest = strtotime($oldest);
if(!$userID) $userID = $this->wire('user')->id;
$n = 0;
$_selector = "include=unpublished, created_users_id=$userID, created>=$oldest, sort=-created, limit=50";
$this->updateSelectorString($_selector);
do {
$selector = $_selector;
if(count($items)) {
$selector .= ", id!=";
foreach($items as $item) $selector .= $item->id . '|';
$selector = rtrim($selector, '|');
}
$matches = $this->wire('pages')->find($selector);
foreach($matches as $item) {
if(!$item->editable() || !$item->parent->addable()) continue;
if($item->template->noParents) continue;
if($item->parent->template->noChildren) continue;
$childTemplates = $item->parent->template->childTemplates;
if(count($childTemplates) && !in_array($item->template->id, $childTemplates)) continue;
$parentTemplates = $item->template->parentTemplates;
if(count($parentTemplates) && !in_array($item->parent->template->id, $parentTemplates)) continue;
$key = $item->parent->id . "-" . $item->template->id; // limit to 1 parent-template match
if(isset($items[$key])) continue;
$url = $this->wire('config')->urls->admin . "page/add/?parent_id=$item->parent_id&template_id={$item->template->id}";
$label = $this->sanitizer->entities($item->template->getLabel());
$label .= ' <small>' . sprintf($this->_('in %s'), $item->parent->get('title|name')) . '</small>';
$item->set('_addAnotherURL', $url);
$item->set('_addAnotherLabel', $label);
$items[$key] = $item;
}
} while(count($items) < $limit && (++$n < 10));
return $items;
}
/**
* Provides the navJSON data for the 'add another' menu item
*
* @return string
*
*/
public function ___executeAnotherNavJSON() {
$data = array(
'url' => '',
'label' => $this->_((string) $this->page->get('title|name')),
'icon' => '',
'list' => array(),
);
$items = $this->getAddAnotherNavItems();
foreach($items as $item) {
$data['list'][] = array(
'url' => $item->_addAnotherURL,
'label' => $item->_addAnotherLabel,
'icon' => $item->template->getIcon(),
);
}
if(!count($items)) {
$data['list'][] = array(
'url' => $this->wire('config')->urls->admin,
'label' => $this->labels['nothing'],
);
}
if($this->wire('config')->ajax) header("Content-Type: application/json");
return json_encode($data);
}
/**
* Outputs a table of 'add another' pages, for when user clicks on the 'Add another' text rather than a page item
*
* @return string
*
*/
public function ___executeAnother() {
$items = $this->getAddAnotherNavItems();
if(!count($items)) return "<h2>" . $this->labels['nothing'] . "</h2>";
$this->headline($this->_('Add another'));
$table = $this->wire('modules')->get('MarkupAdminDataTable');
$table->headerRow(array(
$this->_x('Template', 'th'),
$this->_x('Parent', 'th'),
$this->_x('Last Created', 'th')
));
foreach($items as $item) {
$table->row(array(
$item->template->getLabel() => $item->_addAnotherURL,
$item->parent->get('title|name'),
wireRelativeTimeStr($item->created)
));
}
return "<h2>" . $this->_('Click any item to add another of the same type') . "</h2>" . $table->render();
}
}