";
} else {
$parentLabel = $this->_x('Parent', 'prev-path-parent');
$parent = $pages->get((int) $item['virtual']);
if($parent->id) $parentLabel = "$parentLabel";
$row[] = $parentLabel;
}
$table->row($row);
}
/** @var InputfieldTextarea $add */
$add = $modules->get('InputfieldTextarea');
$add->attr('name', '_prevpath_add');
$add->label = $this->_('Add new redirect URLs');
$add->description =
$this->_('Enter additional paths/URLs (one per line) that should redirect to this page.') . ' ' .
$this->_('Enter the URL path only (i.e. “/hello/world/”), do NOT include scheme, domain, port, query string or fragments.') . ' ';
if($rootUrl != '/') {
$add->description .= sprintf(
$this->_('Paths are relative to site root so do NOT include the %s subdirectory at the beginning.'),
$rootUrl
);
}
$add->collapsed = Inputfield::collapsedYes;
$add->icon = 'plus';
$add->addClass('InputfieldIsSecondary', 'wrapClass');
if($multilang) {
$add->notes = $this->_('To specify a language for the redirect, enter path/URL on line prefixed with language name:');
foreach($languages->findNonDefault() as $language) {
$add->notes .= "\n`$language->name:" .
sprintf($this->_('/your/%s/url/'), $language->name) . "` " . // /your/[language-name]/url/
sprintf($this->_('(for %s)'), $language->get('title|name')); // (for [language-title])
}
}
if($this->isPost && $this->form->isSubmitted('_prevpath_add')) {
$add->processInput($input->post);
if($add->val()) {
foreach(explode("\n", $add->val()) as $path) {
if(strpos($path, ':')) {
list($langName, $path) = explode(':', $path, 2);
$language = $languages->get($sanitizer->pageName($langName));
if(!$language || !$language->id) $language = null;
} else {
$language = null;
}
$path = $sanitizer->pagePathName($path);
if(!strlen($path)) continue;
if($history->addPathHistory($this->page, $path, $language)) {
$this->message(sprintf(
$this->_('Added redirect: %s'),
$path
));
} else {
$this->warning(sprintf(
$this->_('Unable to add redirect %s because it appears to conflict with another path'),
$path
));
}
}
}
} else {
$field->val($table->render());
$field->add($add);
}
return $field;
}
/**
* Build the Settings > Info fieldset on the Page Edit form
*
* @return InputfieldMarkup
*
*/
protected function buildFormInfo() {
$page = $this->page;
$dateFormat = $this->config->dateFormat;
$unknown = '[?]';
/** @var InputfieldMarkup $field */
$field = $this->modules->get("InputfieldMarkup");
$createdName = $page->createdUser ? $page->createdUser->name : '';
$modifiedName = $page->modifiedUser ? $page->modifiedUser->name : '';
if(empty($createdName)) $createdName = $unknown;
if(empty($modifiedName)) $modifiedName = $unknown;
if($this->user->isSuperuser()) {
$url = $this->config->urls->admin . 'access/users/edit/?id=';
if($createdName != $unknown && $page->createdUser instanceof User) $createdName = "$createdName";
if($modifiedName != $unknown && $page->modifiedUser instanceof User) $modifiedName = "$modifiedName";
}
$lowestDate = strtotime('1974-10-10');
$createdDate = $page->created > $lowestDate ? date($dateFormat, $page->created) . " " .
"(" . wireRelativeTimeStr($page->created) . ")" : $unknown;
$modifiedDate = $page->modified > $lowestDate ? date($dateFormat, $page->modified) . " " .
"(" . wireRelativeTimeStr($page->modified) . ")" : $unknown;
$publishedDate = $page->published > $lowestDate ? date($dateFormat, $page->published) . " " .
"(" . wireRelativeTimeStr($page->published) . ")" : $unknown;
$info = "\n
" .
sprintf($this->_('Created by %1$s on %2$s'), $createdName, $createdDate) . " " . // Settings: created user/date information line
sprintf($this->_('Last modified by %1$s on %2$s'), $modifiedName, $modifiedDate) . " " . // Settings: modified user/date information line
sprintf($this->_('Published on %s'), $publishedDate) . // Settings: published information line
"
";
$field->attr('id+name', 'ProcessPageEditInfo');
$field->label = $this->_('Info'); // Settings: Info field label
$field->icon = 'info-circle';
if($this->config->advanced) $field->notes = "Object type: " . $page->className();
$field->value = $info;
return $field;
}
/**
* Build the Settings > Status fieldset on the Page Edit form
*
* @return InputfieldCheckboxes
*
*/
protected function buildFormStatus() {
$status = (int) $this->page->status;
$debug = $this->config->debug;
$statuses = $this->getAllowedStatuses();
/** @var InputfieldCheckboxes $field */
$field = $this->modules->get('InputfieldCheckboxes');
$field->attr('name', 'status');
$field->icon = 'sliders';
$value = array();
foreach($statuses as $s => $label) {
if($s & $status) $value[] = $s;
if(strpos($label, ': ')) $label = str_replace(': ', ': [span.detail]', $label) . '[/span]';
$field->addOption($s, $label);
}
$field->attr('value', $value);
$field->label = $this->_('Status'); // Settings: Status field label
if($debug) $field->notes = $this->page->statusStr;
return $field;
}
/**
* Build the 'delete' tab on the Page Edit form
*
* @return InputfieldWrapper
*
*/
protected function ___buildFormDelete() {
/** @var InputfieldWrapper $wrapper */
$wrapper = $this->wire(new InputfieldWrapper());
$deleteable = $this->page->deleteable();
$trashable = $deleteable || $this->page->trashable();
if(!$trashable) return $wrapper;
$id = $this->className() . 'Delete';
$deleteLabel = $this->_('Delete'); // Tab Label: Delete
$wrapper->attr('id', $id);
$wrapper->attr('title', $deleteLabel);
$this->addTab($id, $deleteLabel, $wrapper);
/** @var InputfieldCheckbox $field */
$field = $this->modules->get('InputfieldCheckbox');
$field->attr('id+name', 'delete_page');
$field->attr('value', $this->page->id);
if($deleteable && ($this->isTrash || $this->page->template->noTrash)) {
$deleteLabel = $this->_('Delete Permanently'); // Delete permanently checkbox label
} else {
$deleteLabel = $this->_('Move to Trash'); // Move to trash checkbox label
}
$field->icon = 'trash-o';
$field->label = $deleteLabel;
$field->description = $this->_('Check the box to confirm that you want to do this.'); // Delete page confirmation instruction
$field->label2 = $this->_('Confirm');
$wrapper->append($field);
if(count($wrapper->children())) {
/** @var InputfieldButton $field */
$field = $this->modules->get('InputfieldButton');
$field->attr('id+name', 'submit_delete');
$field->value = $deleteLabel;
$wrapper->append($field);
} else {
$wrapper->description = $this->_('This page may not be deleted at this time'); // Page can't be deleted message
}
return $wrapper;
}
/**
* Build the 'restore' tab shown for pages in the trash
*
* Returns boolean false if restore not possible.
*
* @return InputfieldWrapper|bool
*
*/
protected function buildFormRestore() {
if(!$this->page->isTrash()) return false;
if(!$this->page->restorable()) return false;
$info = $this->wire()->pages->trasher()->getRestoreInfo($this->page);
if(!$info['restorable']) return false;
/** @var InputfieldWrapper $wrapper */
$wrapper = $this->wire(new InputfieldWrapper());
$id = $this->className() . 'Restore';
$restoreLabel = $this->_('Restore'); // Tab Label: Restore
$restoreLabel2 = $this->_('Move out of trash and restore to original location');
$wrapper->attr('id', $id);
$wrapper->attr('title', $restoreLabel);
$this->addTab($id, $restoreLabel, $wrapper);
/** @var Page $parent */
$parent = $info['parent'];
$newPath = $parent->path() . $info['name'] . '/';
/** @var InputfieldCheckbox $field */
$field = $this->modules->get('InputfieldCheckbox');
$field->attr('id+name', 'restore_page');
$field->attr('value', $this->page->id);
$field->icon = 'trash-o';
$field->label = $restoreLabel2;
$field->description = $this->_('Check the box to confirm that you want to restore this page.'); // Restore page confirmation instruction
$field->notes = sprintf($this->_('The page will be restored to: **%s**.'), $newPath);
if($info['namePrevious']) $field->notes .= ' ' .
sprintf($this->_('Original name will be adjusted from **%1$s** to **%2$s** to be unique.'), $info['namePrevious'], $info['name']);
$field->label2 = $restoreLabel;
$wrapper->append($field);
return $wrapper;
}
/**
* Build the 'view' tab on the Page Edit form
*
* @param string $url
*
*/
protected function ___buildFormView($url) {
$label = $this->_('View'); // Tab Label: View
$id = $this->className() . 'View';
if((!empty($this->configSettings['viewNew'])) || $this->viewAction == 'new') {
$target = '_blank';
} else {
$target = '_top';
}
$a =
"$label" .
"" .
"";
$this->addTab($id, $a);
}
/**
* Build the Settings > Roles fieldset on the Page Edit form
*
* @return InputfieldMarkup
*
*/
protected function ___buildFormRoles() {
/** @var InputfieldMarkup $field */
$field = $this->modules->get("InputfieldMarkup");
$field->label = $this->_('Who can access this page?'); // Roles information field label
$field->icon = 'users';
$field->attr('id+name', 'ProcessPageEditRoles');
$field->collapsed = Inputfield::collapsedYesAjax;
/** @var MarkupAdminDataTable $table */
$table = $this->modules->get("MarkupAdminDataTable");
$pageHasTemplateFile = $this->page->template->filenameExists();
if($this->input->get('renderInputfieldAjax') == 'ProcessPageEditRoles') {
$roles = $this->page->getAccessRoles();
$accessTemplate = $this->page->getAccessTemplate('edit');
if($accessTemplate) {
$editRoles = $accessTemplate->editRoles;
$addRoles = $accessTemplate->addRoles;
$createRoles = $accessTemplate->createRoles;
} else {
$editRoles = array();
$addRoles = array();
$createRoles = array();
}
$table->headerRow(array(
$this->_('Role'), // Roles table column header: Role
$this->_('What they can do') // Roles table colum header: what they can do
));
$table->setEncodeEntities(false);
$addLabel = 'add';
if(count($roles)) {
$hasPublishPermission = $this->wire()->permissions->has('page-publish');
foreach($roles as $role) {
/** @var Role $role */
$permissions = array();
$roleName = $role->name;
if($roleName == 'guest') $roleName .= " " . $this->_('(everyone)'); // Identifies who guest is (everyone)
$permissions["page-view"] = 'view' . ($pageHasTemplateFile ? '' : '¹');
$checkEditable = true;
if($hasPublishPermission && !$this->page->hasStatus(Page::statusUnpublished)
&& !$role->hasPermission('page-publish', $this->page)) {
$checkEditable = false;
}
$key = array_search($role->id, $addRoles);
if($key !== false && $role->hasPermission('page-add', $this->page)) {
$permissions["page-add"] = 'add';
unset($addRoles[$key]);
}
$editable = $role->hasPermission('page-edit', $this->page) && in_array($role->id, $editRoles);
if($checkEditable && $editable) {
foreach($role->permissions as $permission) {
if(strpos($permission->name, 'page-') !== 0) continue;
if(in_array($permission->name, array('page-view', 'page-publish', 'page-create', 'page-add'))) continue;
if(!$role->hasPermission($permission, $this->page)) continue;
$permissions[$permission->name] = str_replace('page-', '', $permission->name); // only page-context permissions
}
if($hasPublishPermission && $role->hasPermission('page-publish', $this->page)) {
$permissions["page-publish"] = 'publish';
}
}
if(in_array($role->id, $createRoles) && $editable) {
$permissions["page-create"] = 'create';
}
$table->row(array($roleName, implode(', ', $permissions)));
}
}
if(count($addRoles)) {
foreach($addRoles as $roleID) {
$role = $this->wire('roles')->get($roleID);
if(!$role->id) continue;
if(!$role->hasPermission("page-add", $this->page)) continue;
$table->row(array($role->name, $addLabel));
}
}
$table->row(array('superuser', $this->_x('all', 'all permissions')));
$field->value = $table->render();
}
$accessParent = $this->page->getAccessParent();
if($accessParent === $this->page) {
$field->notes = sprintf($this->_('Access is defined with this page’s template: %s'), $accessParent->template); // Where access is defined: with this page's template
} else {
$field->notes = sprintf($this->_('Access is inherited from page "%1$s" and defined with template: %2$s'), $accessParent->path, $accessParent->template); // Where access is defined: inherited from a parent
}
if(!$pageHasTemplateFile) {
$field->notes = trim("¹ " . $this->_('Viewable by its URL if page had a template file (it does not currently).') . "\n$field->notes");
}
return $field;
}
/***********************************************************************************************************************
* FORM PROCESSING
*
*/
/**
* Save a submitted Page Edit form
*
*/
protected function processSave() {
$input = $this->wire()->input;
$pages = $this->wire()->pages;
$page = $this->page;
$user = $this->user;
$form = $this->form;
if($page->hasStatus(Page::statusLocked)) {
$inputStatus = $input->post('status');
if(!$user->hasPermission('page-lock', $page) || (is_array($inputStatus) && in_array(Page::statusLocked, $inputStatus))) {
$this->error($this->noticeLocked);
$this->processSaveRedirect($this->redirectUrl);
return;
}
}
$formErrors = 0;
// remove temporary status that may have been assigned by ProcessPageAdd quick add mode
if($page->hasStatus(Page::statusTemp)) $page->removeStatus(Page::statusTemp);
if($form->isSubmitted('submit_delete')) {
if(((int) $input->post('delete_page')) === $this->page->id) $this->deletePage();
} else {
$this->processInput($form);
$changes = array_unique($page->getChanges());
$numChanges = count($changes);
if($numChanges) {
$this->changes = $changes;
$this->message(sprintf($this->_('Change: %s'), implode(', ', $changes)), Notice::debug); // Message shown for each changed field
}
foreach($this->notices as $notice) {
if($notice instanceof NoticeError) $formErrors++;
}
// if any Inputfields threw errors during processing, give the page a 'flagged' status
// so that it can later be identified the page may be missing something
if($formErrors && count($form->getErrors())) {
// add flagged status when form had errors
$page->addStatus(Page::statusFlagged);
} else if($page->hasStatus(Page::statusFlagged)) {
// if no errors, remove incomplete status
$page->removeStatus(Page::statusFlagged);
$this->message($this->_('Removed flagged status because no errors reported during save'));
}
$isUnpublished = $page->hasStatus(Page::statusUnpublished);
if($input->post('submit_publish') || $input->post('submit_save')) {
try {
$options = array();
$name = '';
if($page->isChanged('name')) {
if(!strlen($page->name) && $page->namePrevious) {
// blank page name when there was a previous name, set back the previous
// example instance: when template.childNameFormat in use and template.noSettings active
$page->name = $page->namePrevious;
} else {
$name = $page->name;
}
$options['adjustName'] = true;
}
$numChanges = $numChanges > 0 ? ' (' . sprintf($this->_n('%d change', '%d changes', $numChanges) . ')', $numChanges) : '';
if($input->post('submit_publish') && $isUnpublished && $this->page->publishable() && !$formErrors) {
$page->removeStatus(Page::statusUnpublished);
$message = sprintf($this->_('Published Page: %s'), '{path}') . $numChanges; // Message shown when page is published
} else {
$message = sprintf($this->_('Saved Page: %s'), '{path}') . $numChanges; // Message shown when page is saved
if($isUnpublished && $formErrors && $input->post('submit_publish')) {
$message .= ' - ' . $this->_('Cannot be published until errors are corrected');
}
}
$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);
if($name && $name != $page->name) {
$this->warning(sprintf($this->_('Changed page URL name to "%s" because requested name was already taken.'), $this->page->name));
}
} catch(\Exception $e) {
$show = true;
$message = $e->getMessage();
foreach($this->errors('all') as $error) {
if(strpos($error, $message) === false) continue;
$show = false;
break;
}
if($show) $this->error($message);
}
}
}
if($this->redirectUrl) {
// non-default redirectUrl overrides after_submit_action
} else if($formErrors) {
// if there were errors to attend to, stay where we are
} else {
// after submit action
$submitAction = $input->post('_after_submit_action');
if($submitAction) $this->processSubmitAction($submitAction);
}
$this->processSaveRedirect($this->getRedirectUrl());
}
/**
* Process the given submit action value
*
* #pw-hooker
*
* @param string $value Value of selected action, i.e. 'exit', 'view', 'add', next', etc.
* @return bool Returns true if value was acted upon or false if not
* @since 3.0.142
* @see ___getSubmitActions(), setRedirectUrl()
*
*/
protected function ___processSubmitAction($value) {
if($value == 'exit') {
$this->setRedirectUrl('../');
} else if($value == 'view') {
$this->setRedirectUrl($this->getViewUrl());
} else if($value == 'add') {
$this->setRedirectUrl("../add/?parent_id={$this->page->parent_id}");
} else if($value == 'next') {
$nextPage = $this->page->next("include=unpublished");
if($nextPage->id) {
if(!$nextPage->editable()) {
$nextPage = $this->page->next("include=hidden");
if($nextPage->id && !$nextPage->editable()) {
$nextPage = $this->page->next();
if($nextPage->id && !$nextPage->editable()) $nextPage = new NullPage();
}
}
}
if($nextPage->id) {
$this->setRedirectUrl($this->getEditUrl(array('id' => $nextPage->id)));
} else {
$this->warning($this->_('There is no editable next page to edit.'));
}
} else {
return false;
}
return true;
}
/**
* Perform an after save redirect
*
* @param string $redirectUrl
*
*/
protected function ___processSaveRedirect($redirectUrl = '') {
if($redirectUrl) {
$c = substr($redirectUrl, 0, 1);
$admin = $c === '.' || $c === '?' || strpos($redirectUrl, $this->config->urls->admin) === 0;
if($admin) {
$redirectUrl .= (strpos($redirectUrl, '?') === false ? '?' : '&') . 's=1';
}
} else {
$admin = true;
$redirectUrl = $this->getEditUrl(array('s' => 1));
}
if($admin) {
$redirectUrl .= "&c=" . count($this->changes);
if(count($this->fields) && count($this->changes)) {
$redirectUrl .= "&changes=" . implode(',', $this->changes);
}
}
$this->setRedirectUrl($redirectUrl);
$this->session->location($this->getRedirectUrl());
}
/**
* Process the input from a submitted Page Edit form, delegating to other methods where appropriate
*
* @param InputfieldWrapper $form
* @param int $level
* @param Inputfield $formRoot
*
*/
protected function ___processInput(InputfieldWrapper $form, $level = 0, $formRoot = null) {
$input = $this->wire()->input;
$languages = $this->wire()->languages;
$page = $this->page;
static $skipFields = array(
'sortfield_reverse',
'submit_publish',
'submit_save',
'delete_page',
);
if(!$level) {
$form->processInput($input->post);
$formRoot = $form;
$page->setQuietly('_forceAddStatus', 0);
}
$errorAction = (int) $page->template->errorAction;
foreach($form as $inputfield) {
/** @var Inputfield|InputfieldWrapper $inputfield */
$name = $inputfield->attr('name');
if($name == '_pw_page_name') $name = 'name';
if(in_array($name, $skipFields)) continue;
if(!$page->editable($name, false)) {
$page->untrackChange($name); // just in case
continue;
}
if($name == 'sortfield' && $this->useChildren && $form->isProcessable($inputfield->parent->parent)) {
$this->processInputSortfield($inputfield) ;
continue;
}
if($this->useSettings) {
if($name == 'template') {
$this->processInputTemplate($inputfield);
continue;
} else if($name == 'created_users_id') {
$this->processInputUser($inputfield);
continue;
} else if($name == 'parent_id' && count($this->predefinedParents)) {
if(!$this->predefinedParents->has("id=$inputfield->value")) {
$this->error("Parent $inputfield->value is not allowed for $page");
continue;
}
}
if($name == 'status' && $this->processInputStatus($inputfield)) continue;
}
if($this->processInputErrorAction($page, $inputfield, $name, $errorAction)) continue;
if($name && $inputfield->isChanged()) {
if($languages && $inputfield->getSetting('useLanguages')) {
$v = $page->get($name);
if(is_object($v)) {
$v = clone $v;
$v->setFromInputfield($inputfield);
$page->set($name, $v);
} else {
$page->set($name, $inputfield->val());
}
} else {
$page->set($name, $inputfield->val());
}
}
if($inputfield instanceof InputfieldWrapper && count($inputfield->getChildren())) {
$this->processInput($inputfield, $level + 1, $formRoot);
}
}
if(!$level) {
$forceAddStatus = $page->get('_forceAddStatus');
if($forceAddStatus && !$page->hasStatus($forceAddStatus)) {
$page->addStatus($forceAddStatus);
}
}
}
/**
* Process required error actions as configured with page’s template
*
* @param Page $page
* @param Inputfield|InputfieldRepeater $inputfield Inputfield that has already had its processInput() method called.
* @param string $name Name of field that we are checking.
* @param null|int $errorAction Error action from $page->template->errorAction, or omit to auto-detect.
* @return bool Returns true if field $name should be skipped over during processing, or false if not
*
*/
public function processInputErrorAction(Page $page, Inputfield $inputfield, $name, $errorAction = null) {
if(empty($name)) return false;
if($errorAction === null) $errorAction = (int) $page->template->get('errorAction');
if(!$errorAction) return false;
if($page->isUnpublished()) return false;
$isRequired = $inputfield->getSetting('required');
$isRepeater = strpos($inputfield->className(), 'Repeater') > 0 && wireInstanceOf($inputfield, 'InputfieldRepeater', false);
if(!$isRepeater && !$isRequired) return false;
if($inputfield->getSetting('requiredSkipped')) return false;
if($isRepeater) {
if($inputfield->numRequiredEmpty() > 0) {
// repeater has required fields that are empty
} else if($isRequired && $inputfield->numPublished() < 1) {
// repeater is required and has no published items
} else {
// repeater is okay for now
return false;
}
} else if(!$inputfield->isEmpty()) {
return false;
}
if($errorAction === 1) {
// restore existing value by skipping processing of empty when required
$value = $inputfield->attr('value');
if($value instanceof Wire) $value->resetTrackChanges();
if($page->getField($name)) $page->remove($name); // force fresh copy to reload
$previousValue = $page->get($name);
$page->untrackChange($name);
if($previousValue) {
// we should have a previous value to restore
if(WireArray::iterable($previousValue) && !count($previousValue)) {
// previous value still empty
} else {
// previous value restored by simply not setting new value to $page
$inputfield->error($this->_('Restored previous value'));
return true;
}
}
} else if($errorAction === 2 && $page->publishable() && $page->id > 1) {
// unpublish page missing required value
$page->setQuietly('_forceAddStatus', Page::statusUnpublished);
$label = $inputfield->getSetting('label');
if(empty($label)) $label = $inputfield->attr('name');
$inputfield->error(sprintf($this->_('Page unpublished because field "%s" is required'), $label));
return false;
}
return false;
}
/**
* Check to see if the page's created user has changed and make sure it's valid
*
* @param Inputfield $inputfield
*
*/
protected function processInputUser(Inputfield $inputfield) {
$page = $this->page;
if(!$this->user->isSuperuser() || !$page->id || !$page->template->allowChangeUser) return;
$userID = $inputfield->val();
if(is_array($userID)) $userID = reset($userID);
if($userID instanceof PageArray) $userID = $userID->first();
if($userID instanceof Page) $userID = $userID->id;
$userID = (int) $userID;
if(!$userID) return;
if($userID == $this->page->created_users_id) return; // no change
$user = $this->pages->get($userID);
if(!$user->id) return;
if(!in_array($user->template->id, $this->config->userTemplateIDs)) return; // invalid user template
if(!in_array($user->parent_id, $this->config->usersPageIDs)) return; // invalid user parent
$page->created_users_id = $user->id;
$page->trackChange('created_users_id');
}
/**
* Check to see if the page's template has changed and setup a redirect to a confirmation form if it has
*
* @param Inputfield $inputfield
* @return bool
* @throws WireException
*
*/
protected function processInputTemplate(Inputfield $inputfield) {
if($this->page->template->noChangeTemplate) return true;
$templateID = (int) $inputfield->attr('value');
if(!$templateID) return true;
$template = $this->wire()->templates->get((int) $inputfield->val());
if(!$template) return true; // invalid template
if($template->id == $this->page->template->id) return true; // no change
if(!$this->isAllowedTemplate($template)) {
throw new WireException(sprintf($this->_("Template '%s' is not allowed"), $template)); // Selected template is not allowed
}
// template has changed, set a redirect URL which will confirm the change
$this->setRedirectUrl("template?id={$this->page->id}&template=$template->id");
return true;
}
/**
* Process the submitted 'status' field and account for the bitwise logic present
*
* @param Inputfield $inputfield
* @return bool
*
*/
protected function processInputStatus(Inputfield $inputfield) {
$inputStatusFlags = $inputfield->val();
if(!is_array($inputStatusFlags)) $inputStatusFlags = array();
foreach($inputStatusFlags as $k => $v) $inputStatusFlags[$k] = (int) $v;
$allowedStatusFlags = array_keys($this->getAllowedStatuses());
$statusLabels = array_flip(Page::getStatuses());
$value = $this->page->status;
foreach($allowedStatusFlags as $flag) {
if(in_array($flag, $inputStatusFlags, true)) {
if($value & $flag) {
// already has flag
} else {
$value = $value | $flag; // add status
$this->message(sprintf($this->_('Added status: %s'), $statusLabels[$flag]), Notice::debug);
}
} else if($value & $flag) {
$value = $value & ~$flag; // remove flag
$this->message(sprintf($this->_('Removed status: %s'), $statusLabels[$flag]), Notice::debug);
}
}
$this->page->status = $value;
return true;
}
/**
* Process the Children > Sortfield input
*
* @param Inputfield $inputfield
* @return bool
*
*
*/
protected function processInputSortfield(Inputfield $inputfield) {
if(!$this->user->hasPermission('page-sort', $this->page)) return true;
$sortfield = $this->sanitizer->name($inputfield->val());
if($sortfield != 'sort' && !empty($_POST['sortfield_reverse'])) $sortfield = '-' . $sortfield;
if(empty($sortfield)) $sortfield = 'sort';
$this->page->sortfield = $sortfield;
return true;
}
/**
* Process a delete page request, moving the page to the trash if applicable
*
* @return bool
*
*/
protected function deletePage() {
$page = $this->page;
if(!$page->trashable(true)) {
$this->error($this->_('This page is not deleteable'));
return false;
}
$redirectUrl = $this->wire()->config->urls->admin . "page/?open={$this->parent->id}";
if($this->wire()->page->process != $this->className()) $redirectUrl = "../";
$pagePath = $page->path();
if(($this->isTrash || $page->template->noTrash) && $page->deleteable()) {
$this->wire()->session->message(sprintf($this->_('Deleted page: %s'), $pagePath)); // Page deleted message
$this->pages->delete($page, true);
$this->deletedPage($page, $redirectUrl, false);
} else if($this->pages->trash($page)) {
$this->wire()->session->message(sprintf($this->_('Moved page to trash: %s'), $pagePath)); // Page moved to trash message
$this->deletedPage($page, $redirectUrl, true);
} else {
$this->error($this->_('Unable to move page to trash')); // Page can't be moved to the trash error
return false;
}
return true;
}
/**
* Called after a page has been deleted or trashed, performs redirect
*
* @param Page $page Page that was deleted or trashed
* @param string $redirectUrl URL that should be redirected to
* @param bool $trashed True if page was trashed rather than deleted
* @since 3.0.173
*
*/
protected function ___deletedPage($page, $redirectUrl, $trashed = false) {
if($page || $trashed) {} // ignore
$this->wire()->session->location($redirectUrl);
}
/**
* Save only the fields posted via ajax
*
* - Field name must be included in server header HTTP_X_FIELDNAME or directly in the POST vars.
* - Note that fields that would be not present in POST vars (like a checkbox) are only supported
* by the HTTP_X_FIELDNAME version.
* - Works for custom fields only at present.
*
* @param Page $page
* @throws WireException
*
*/
protected function ___ajaxSave(Page $page) {
if($this->config->demo) throw new WireException("Ajax save is disabled in demo mode");
if($page->hasStatus(Page::statusLocked)) throw new WireException($this->noticeLocked);
if(!$this->ajaxEditable($page)) throw new WirePermissionException($this->noticeNoAccess);
$this->wire()->session->CSRF->validate(); // throws exception when invalid
/** @var InputfieldWrapper $form */
$form = $this->wire(new InputfieldWrapper());
$form->useDependencies = false;
$keys = array();
$error = '';
$message = '';
if(isset($_SERVER['HTTP_X_FIELDNAME'])) {
$keys[] = $this->sanitizer->fieldName($_SERVER['HTTP_X_FIELDNAME']);
} else if(count($this->fields)) {
$keys = array_keys($this->fields);
} else {
foreach($this->input->post as $key => $unused) {
if($key === 'id') continue;
$keys[] = $this->sanitizer->fieldName($key);
}
}
foreach($keys as $key) {
if(!$field = $page->template->fieldgroup->getFieldContext($key)) continue;
if(!$this->ajaxEditable($page, $key)) continue;
if(!$inputfield = $field->getInputfield($page)) continue;
$inputfield->showIf = ''; // cancel showIf dependencies since other fields may not be present
$inputfield->name = $key;
$inputfield->value = $page->get($key);
$form->add($inputfield);
}
$form->processInput($this->input->post);
$page->setTrackChanges(true);
$pageClass = $page->className();
$numFields = 0;
$lastFieldName = null;
$savedNames = array();
$saved = false; // was page saved?
$languages = $this->wire()->languages;
$changes = array();
foreach($form->children() as $inputfield) {
/** @var Inputfield $inputfield */
$name = $inputfield->attr('name');
if($languages && $inputfield->getSetting('useLanguages')) {
$v = $page->get($name);
if(is_object($v)) {
$v = clone $v;
$v->setFromInputfield($inputfield);
$page->set($name, $v);
} else {
$page->set($name, $inputfield->val());
}
} else {
$page->set($name, $inputfield->val());
}
$numFields++;
$lastFieldName = $inputfield->name;
$savedNames[] = $lastFieldName;
if($inputfield instanceof InputfieldFile) $page->trackChange($name);
}
if($page->isChanged()) {
$changes = $page->getChanges();
if($numFields === 1) {
if($page->save((string) $lastFieldName)) {
$saved = true;
$message = "Ajax saved $pageClass $page->id field: $lastFieldName";
} else {
$error = "Ajax error saving $pageClass $page->id field: $lastFieldName";
}
} else {
if($page->save()) {
$saved = true;
$message = "Ajax saved $pageClass $page->id fields: " . implode(', ', $savedNames);
} else {
$error = "Ajax error saving $pageClass $page->id fields: " . implode(', ', $savedNames);
}
}
} else {
$message = "Ajax $pageClass $page->id not saved (no changes)";
$savedNames = array();
}
$data = array(
'fields' => $savedNames,
'changes' => $changes,
'error' => strlen($error) > 0,
'message' => ($error ? $error : $message),
'saved' => $saved,
);
if(!$this->ajaxSaveDone($page, $data)) {
if($message) $this->message($message);
if($error) $this->error($error);
}
}
/**
* Ajax save done - send output
*
* When a hook overrides this, it should hook after and set `$event->return = true;`
* to indicate that it has handled the output.
* ~~~~~
* $wire->addHookAfter('ProcessPageEdit::ajaxSaveDone', function($event) {
* if($event->return === true) return; // another hook already handled output
* $page = $event->arguments(0); // Page
* $data = $event->arguments(1); // array
* $data['page'] = $page->id;
* header('Content-Type', 'application/json');
* echo json_encode($data);
* $event->return = true; // tell ProcessPageEdit we handled output
* });
* ~~~~~
*
* #pw-hooker
*
* @param Page $page
* @param array $data
* @return bool Return true if hook has handled output, false if not (default)
* @since 3.0.188
*
*/
protected function ___ajaxSaveDone(Page $page, array $data) {
return false;
}
/***************************************************************************************************************
* OTHER ACTIONS
*
*/
/**
* Build template form
*
* @param Template $template Proposed template to change to
* @return InputfieldForm
* @throws WireException
* @since 3.0.205
*
*/
protected function buildTemplateForm(Template $template) {
if($this->page->template->noChangeTemplate) {
throw new WireException("Template changes not allowed by pages using template: $template");
}
if(!$this->useSettings || !$this->user->hasPermission('page-template', $this->page)) {
throw new WireException("You don't have permission to change the template on this page.");
}
if(!$this->isAllowedTemplate($template->id)) {
throw new WireException("That template is not allowed");
}
$labelConfirm = $this->_('Confirm template change'); // Change template confirmation subhead
$labelAction = sprintf($this->_('Change template from "%1$s" to "%2$s"'), $this->page->template, $template->name); // Change template A to B headline
$this->headline($labelConfirm);
if($this->requestModal) $this->error("$labelConfirm – $labelAction"); // force modal open
/** @var InputfieldForm $form */
$form = $this->modules->get("InputfieldForm");
$form->attr('action', 'saveTemplate');
$form->attr('method', 'post');
$form->description = $labelAction;
/** @var InputfieldMarkup $f */
$f = $this->modules->get("InputfieldMarkup");
$f->icon = 'cubes';
$f->label = $labelConfirm;
$list = array();
foreach($this->page->template->fieldgroup as $field) {
/** @var Field $field */
if(!$template->fieldgroup->has($field)) {
$list[] = $this->sanitizer->entities($field->getLabel()) . " ($field->name)";
}
}
if(count($list)) {
$f->description = $this->_('Warning, changing the template will delete the following fields:'); // Headline that precedes list of fields that will be deleted as a result of template change
$icon = wireIconMarkup('times-circle');
$f->attr('value', "
$icon " . implode(" $icon ", $list) . '
');
$form->append($f);
}
/** @var InputfieldCheckbox $f */
$f = $this->modules->get("InputfieldCheckbox");
$f->attr('name', 'template');
$f->attr('value', $template->id);
$f->label = $this->_('Are you sure?'); // Checkbox label to confirm they want to change template
$f->label2 = $labelAction;
$f->icon = 'warning';
if(count($list)) $f->description = $this->_('Please confirm that you understand the above by clicking the checkbox below.'); // Checkbox description to confirm they want to change template
$form->append($f);
/** @var InputfieldHidden $f */
$f = $this->modules->get("InputfieldHidden");
$f->attr('name', 'id');
$f->attr('value', $this->page->id);
$form->append($f);
/** @var InputfieldSubmit $f */
$f = $this->modules->get("InputfieldSubmit");
$f->attr('name', 'submit_change_template');
$form->append($f);
return $form;
}
/**
* Execute a template change for a page, building an info + confirmation form (handler for /template/ action)
*
* @return string
* @throws WireException
*
*/
public function ___executeTemplate() {
$page = $this->page;
$editUrl = "./?id=$page->id";
$templateId = (int) $this->input->get('template');
try {
if($templateId < 1) throw new WireException("Missing a 'template' GET variable");
$template = $this->templates->get($templateId);
if(!$template) throw new WireException("Unknown template");
$form = $this->buildTemplateForm($template);
} catch(\Exception $e) {
$this->error($e->getMessage());
$this->session->location($editUrl);
return '';
}
$this->breadcrumb($editUrl, $page->get("title|name"));
return $form->render();
}
/**
* Save a template change for a page (handler for /saveTemplate/ action)
*
* @throws WireException
*
*/
public function ___executeSaveTemplate() {
$page = $this->page;
$editUrl = "./?id=$page->id";
$templateId = (int) $this->input->post('template');
$template = $templateId > 0 ? $this->templates->get($templateId) : null;
if(!$template) {
// checkbox not checked, template change aborted
$this->session->location($editUrl);
return;
}
try {
$form = $this->buildTemplateForm($template);
} catch(\Exception $e) {
$this->error($e->getMessage());
$form = null;
}
if(!$form || !$form->isSubmitted('submit_change_template')) {
$this->session->location($editUrl);
return;
}
try {
$page->template = $template;
$page->save();
$this->message(sprintf($this->_("Changed template to '%s'"), $template->name)); // Message: template was changed
} catch(\Exception $e) {
$this->error($e->getMessage());
}
$this->session->location($editUrl);
}
/**
* Returns an array of templates that are allowed to be used here
*
* @return array|Template[] Array of Template objects
*
*/
protected function getAllowedTemplates() {
if(is_array($this->allowedTemplates)) return $this->allowedTemplates;
$templates = array();
$user = $this->user;
$isSuperuser = $user->isSuperuser();
$page = $this->masterPage ? $this->masterPage : $this->page;
$parent = $page->parent;
$parentEditable = ($parent->id && $parent->editable());
$config = $this->config;
$superAdvanced = $isSuperuser && $config->advanced;
// current page template is assumed, otherwise we wouldn't be here
$templates[$page->template->id] = $page->template;
// check if they even have permission to change it
if(!$user->hasPermission('page-template', $page) || $page->template->noChangeTemplate) {
$this->allowedTemplates = $templates;
return $templates;
}
$allTemplates = count($this->predefinedTemplates) ? $this->predefinedTemplates : $this->wire()->templates;
// note: this triggers load of all templates, fieldgroups and fields
foreach($allTemplates as $template) {
/** @var Template $template */
if(isset($templates[$template->id])) continue;
if($template->flags & Template::flagSystem) {
// if($template->name == 'user' && $parent->id != $this->config->usersPageID) continue;
if(in_array($template->id, $config->userTemplateIDs) && !in_array($parent->id, $config->usersPageIDs)) continue;
if($template->name == 'role' && $parent->id != $config->rolesPageID) continue;
if($template->name == 'permission' && $parent->id != $config->permissionsPageID) continue;
if(strpos($template->name, 'repeater_') === 0 || strpos($template->name, 'fieldset_') === 0) continue;
}
if(count($template->parentTemplates) && $parent->id && !in_array($parent->template->id, $template->parentTemplates)) {
// this template specifies it can only be used with certain parents, and our parent's template isn't one of them
continue;
}
if($parent->id && count($parent->template->childTemplates)) {
// the page's parent only allows certain templates for it's children
// if this isn't one of them, then continue;
if(!in_array($template->id, $parent->template->childTemplates)) continue;
}
if(!$superAdvanced && ((int) $template->noParents) < 0 && $template->getNumPages() > 0) {
// only one of these is allowed to exist (noParents=-1)
continue;
} else if($template->noParents > 0) {
// user can't change to a template that has been specified as no more instances allowed
continue;
} else if($isSuperuser) {
$templates[$template->id] = $template;
} else if((!$template->useRoles && $parentEditable) || $user->hasPermission('page-edit', $template)) {
// determine if the template's assigned roles match up with the users's roles
// and that at least one of those roles has page-edit permission
if($user->hasPermission('page-create', $page)) {
// user is allowed to create more pages of this type, so template may be used
$templates[$template->id] = $template;
}
}
}
$this->allowedTemplates = $templates;
return $templates;
}
/**
* Is the given template or template ID allowed here?
*
* @param int|Template $id
* @return bool
*
*/
public function isAllowedTemplate($id) {
// if $id is a template, then convert it to it's numeric ID
if($id instanceof Template) $id = $id->id;
$id = (int) $id;
// if the template is the same one already in place, of course it's allowed
if($id == $this->page->template->id) return true;
// if we've made it this far, then get a list of templates that are allowed...
$templates = $this->getAllowedTemplates();
// ...and determine if the supplied template is in that list
return isset($templates[$id]);
}
/**
* Returns true if this page may be ajax saved (user has access), or false if not
*
* @param Page $page
* @param string $fieldName Optional field name
* @return bool
*
*/
protected function ___ajaxEditable(Page $page, $fieldName = '') {
return $page->editable($fieldName);
}
/**
* Return instance of the Page being edited (required by WirePageEditor interface)
*
* For Inputfields/Fieldtypes to use if they want to retrieve the editing page rather than the viewing page
*
* @return Page
*
*/
public function getPage() {
return $this->page;
}
/**
* Set the page being edited
*
* @param Page $page
*
*/
public function setPage(Page $page) {
$this->page = $page;
}
/**
* Set the 'master' page
*
* @param Page $page
* @deprecated
*
*/
public function setMasterPage(Page $page) {
$this->masterPage = $page;
}
/**
* Get the 'master' page (if set)
*
* @return null|Page
* @deprecated
*
*/
public function getMasterPage() {
return $this->masterPage;
}
/**
* Set whether or not 'settings' tab should show
*
* @param bool $useSettings
*
*/
public function setUseSettings($useSettings) {
$this->useSettings = (bool) $useSettings;
}
/**
* Set predefined allowed templates
*
* @param array|Template[] $templates
*
*/
public function setPredefinedTemplates($templates) {
if(WireArray::iterable($templates)) $this->predefinedTemplates = $templates;
}
/**
* Set predefined allowed parents
*
* @param PageArray $parents
*
*/
public function setPredefinedParents(PageArray $parents) {
$this->predefinedParents = $parents;
}
/**
* Set the primary editor, if not ProcessPageEdit
*
* @param WirePageEditor $editor
*
*/
public function setEditor(WirePageEditor $editor) {
$this->editor = $editor;
}
/**
* Called on save requests, sets the next redirect URL for the next request
*
* @param string $url URL to redirect to
* @since 3.0.142 Was protected in previous versions
*
*/
public function setRedirectUrl($url) {
$this->redirectUrl = $url;
}
/**
* Get the current redirectUrl
*
* @param array $extras Any extra parts you want to add as array of strings like "key=value"
* @return string
* @since 3.0.142 Was protected in previous versions
*
*/
public function getRedirectUrl(array $extras = array()) {
$url = (string) $this->redirectUrl;
if(!strlen($url)) $url = "./?id=$this->id";
if($this->requestModal && strpos($url, 'modal=') === false) {
$extras[] = "modal=$this->requestModal";
}
if(strpos($url, '&field=') === false && strpos($url, '&fields=') === false) {
if(count($this->fields)) {
$names = array();
foreach($this->fields as $field) {
$names[] = "$field";
}
$extras[] = "fields=" . implode(',', $names);
} else if($this->field) {
$extras[] = "field=$this->field";
}
}
if(strpos($url, './') === 0 || (strpos($url, '/') !== 0 && strpos($url, '../') !== 0)) {
if($this->requestLanguage && strpos($url, 'language=') === false) {
$extras[] = "language=$this->requestLanguage";
}
if($this->requestContext && preg_match('/\bid=' . $this->id . '\b/', $url)) {
$extras[] = "context=$this->requestContext";
}
}
if(count($extras)) {
$url .= strpos($url, '?') === false ? "?" : "&";
$url .= implode('&', $extras);
}
return $url;
}
/**
* Add a tab with HTML id attribute and label
*
* Label may contain markup, and thus you should entity encode text labels as appropriate.
*
* @param string $id
* @param string $label
* @param InputfieldWrapper|null $wrapper
*
*/
public function addTab($id, $label, $wrapper = null) {
$this->tabs[$id] = $label;
if($wrapper) $wrapper->addClass('WireTab');
}
/**
* Remove the tab with the given id
*
* @param string $id
*
*/
public function removeTab($id) {
unset($this->tabs[$id]);
}
/**
* Returns associative array of tab ID => tab Label
*
* @return array
*
*/
public function ___getTabs() {
return $this->tabs;
}
/**
* Get allowed page statuses
*
* @return array Array of [ statusFlagInteger => 'Status flag label' ]
* @since 3.0.181
*
*/
public function getAllowedStatuses() {
$page = $this->page;
$config = $this->wire()->config;
$statuses = array();
$superuser = $this->user->isSuperuser();
if(!$this->page->template->noUnpublish && $this->page->publishable()) {
$statuses[Page::statusUnpublished] = $this->_('Unpublished: Not visible on site'); // Settings: Unpublished status checkbox label
}
if($this->user->hasPermission('page-hide', $this->page)) {
$statuses[Page::statusHidden] = $this->_('Hidden: Excluded from lists and searches'); // Settings: Hidden status checkbox label
}
if($this->user->hasPermission('page-lock', $this->page)) {
$statuses[Page::statusLocked] = $this->_('Locked: Not editable'); // Settings: Locked status checkbox label
}
if($superuser) {
$uniqueNote = ($this->wire('languages') ? ' ' . $this->_('(in default language only)') : '');
$statuses[Page::statusUnique] = sprintf($this->_('Unique: Require page name “%s” to be globally unique'), $this->page->name) . $uniqueNote;
}
if($superuser && $config->advanced) {
// additional statuses available to superuser in advanced mode
$hasSystem = $page->hasStatus(Page::statusSystem) || $page->hasStatus(Page::statusSystemID) || $page->hasStatus(Page::statusSystemOverride);
$statuses[Page::statusSystem] = "System: Non-deleteable and locked ID, name, template, parent (status not removeable without override)";
$statuses[Page::statusSystemID] = "System ID: Non-deleteable and locked ID (status not removeable without override)";
if($hasSystem) $statuses[Page::statusSystemOverride] = "System Override: Override (must be added temporarily in its own save before system status can be removed)";
$statuses[Page::statusDraft] = "Draft: Page has a separate draft version";
$statuses[Page::statusOn] = "On: Internal toggle when combined with other statuses (only for specific cases, otherwise ignored)";
/*
* Additional statuses that are possible but shouldn't be editable (uncomment temporarily if needed)
*
* $statuses[Page::statusTemp] = "Temp: Unpublished page more than 1 day old may be automatically deleted";
* $statuses[Page::statusFlagged] = "Flagged: Page is flagged as incomplete, needing review, or having some issue";
* $statuses[Page::statusTrash] = "Internal trash: Indicates that page is in the trash";
* $statuses[Page::statusReserved] = "Internal-reserved: Status reserved for future use";
* $statuses[Page::statusInternal] = "Internal-internal: Status for internal or future use";
*
*/
}
return $statuses;
}
/**
* Get PageBookmarks array
*
* @return PageBookmarks
*
*/
protected function getPageBookmarks() {
static $bookmarks = null;
if(is_null($bookmarks)) {
require_once(dirname(__FILE__) . '/PageBookmarks.php');
$bookmarks = $this->wire(new PageBookmarks($this));
}
return $bookmarks;
}
/**
* navJSON action
*
* @param array $options
* @return string
* @throws Wire404Exception
* @throws WireException
*
*/
public function ___executeNavJSON(array $options = array()) {
$bookmarks = $this->getPageBookmarks();
$options['edit'] = $this->config->urls->admin . 'page/edit/?id={id}';
$options['defaultIcon'] = 'pencil';
$options = $bookmarks->initNavJSON($options);
return parent::___executeNavJSON($options);
}
/**
* Bookmarks action
*
* @return string
*
*/
public function ___executeBookmarks() {
$bookmarks = $this->getPageBookmarks();
return $bookmarks->editBookmarks();
}
/**
* Set the headline used in the UI
*
*/
public function setupHeadline() {
$titlePage = null;
$page = $this->page;
if($page && $page->id) {
$title = $page->get('title');
if(is_object($title) && !strlen("$title") && wireInstanceOf($title, 'LanguagesPageFieldValue')) {
/** @var LanguagesPageFieldValue $title */
$title = $title->getNonEmptyValue($page->name);
} else {
$title = (string) $title;
}
if(empty($title)) {
if($this->pages->names()->isUntitledPageName($page->name)) {
$title = $page->template->getLabel();
} else {
$title = $page->get('name');
}
}
if(empty($title)) $title = $page->name;
} else if($this->parent && $this->parent->id) {
$titlePage = $this->parent;
$title = rtrim($this->parent->path, '/') . '/[...]';
} else {
$titlePage = new NullPage();
$title = '[...]';
}
$browserTitle = sprintf($this->_('Edit Page: %s'), $title);
$headline = '';
if($this->field) {
if(count($this->fields) == 1) {
$headline = $this->field->getLabel();
} else {
$labels = array();
foreach($this->fields as $field) {
$labels[] = $field->getLabel();
}
$headline = implode(', ', $labels);
}
$browserTitle .= " ($headline)";
} else if($titlePage) {
$headline = $titlePage->get('title|name');
}
if(empty($headline)) $headline = $title;
$this->headline($headline);
$this->browserTitle($browserTitle);
}
/**
* Setup the breadcrumbs used in the UI
*
*/
public function setupBreadcrumbs() {
if($this->input->urlSegment1) return;
if($this->wire()->page->process != $this->className()) return;
$this->wire()->breadcrumbs->shift(); // shift off the 'Admin' breadcrumb
if($this->page && $this->page->id != 1) $this->wire()->breadcrumbs->shift(); // shift off the 'Pages' breadcrumb
$page = $this->page ? $this->page : $this->parent;
if($this->masterPage) $page = $this->masterPage;
$lastID = (int) $this->session->get('ProcessPageList', 'lastID');
$editCrumbs = !empty($this->configSettings['editCrumbs']);
$numParents = $page->parents->count();
foreach($page->parents() as $cnt => $p) {
$url = $editCrumbs && $p->editable() ? "./?id=$p->id" : "../?open=$p->id";
if(!$editCrumbs && $cnt == $numParents-1 && $p->id == $lastID) $url = "../";
$this->breadcrumb($url, $p->get("title|name"));
}
if($this->page && $this->field) {
$this->breadcrumb("./?id={$this->page->id}", $page->get("title|name"));
}
}
/**
* Are we processing a submitted page edit form in this request?
*
* @return bool
* @since 3.0.170
*
*/
public function isSubmit() {
return $this->isPost;
}
/**
* URL to redirect to after non-authenticated user is logged-in, or false if module does not support
*
* @param Page $page
* @return string
* @sine 3.0.167
*
*/
public static function getAfterLoginUrl(Page $page) {
$sanitizer = $page->wire()->sanitizer;
$input = $page->wire()->input;
if($input->urlSegmentStr === 'bookmarks') return $page->url . 'bookmarks/';
$qs = array(
'id' => (int) $input->get('id'),
'language' => (int) $input->get('language'),
'template' => (int) $input->get('template'), // used by executeTemplate() only
'uploadOnlyMode' => (int) $input->get('uploadOnlyMode'),
'fnsx' => $input->get->fieldName('fnsx'),
'context' => $input->get->name('context'),
'field' => $input->get->fieldName('field'),
'fields' => array(),
);
if($input->urlSegmentStr === 'template') {
return "$page->url?id=$qs[id]&template=$qs[template]";
}
if($input->get('fields')) {
foreach(explode(',', $input->get('fields')) as $value) {
$qs['fields'] .= ($qs['fields'] ? ',' : '') . $sanitizer->fieldName($value);
}
}
$a = array();
foreach($qs as $name => $value) {
if(!empty($value)) $a[] = "$name=$value";
}
return "$page->url?" . implode('&', $a);
}
/**
* Module config
*
* @param array $data
* @return InputfieldWrapper
* @throws WireException
*
*/
public function getModuleConfigInputfields(array $data) {
$config = $this->wire()->config;
$pages = $this->wire()->pages;
$modules = $this->wire()->modules;
$inputfields = new InputfieldWrapper();
$this->wire($inputfields);
/** @var InputfieldRadios $f */
$f = $modules->get('InputfieldRadios');
$f->name = 'viewAction';
$f->label = $this->_('Default "view" location/action');
$f->description = $this->_('The default type of action used when the "view" tab is clicked on in the page editor.');
$f->icon = 'eye';
foreach($this->getViewActions(array(), true) as $name => $label) {
$f->addOption($name, $label);
}
$configData = $config->pageEdit;
if(isset($data['viewAction'])) {
$f->attr('value', $data['viewAction']);
} else if(is_array($configData) && !empty($configData['viewNew'])) {
$f->attr('value', 'new');
} else {
$f->attr('value', 'this');
}
$inputfields->add($f);
$bookmarks = $this->getPageBookmarks();
$bookmarks->addConfigInputfields($inputfields);
$admin = $pages->get($config->adminRootPageID);
$page = $pages->get($admin->path . 'page/edit/');
$bookmarks->checkProcessPage($page);
return $inputfields;
}
}