From 6d8afc418afe6c859b6bb1c84287aa16ecc4ae03 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sat, 26 Dec 2015 09:22:51 +0100 Subject: [PATCH] Add media search on media list page in ACP --- .../install/files/acp/templates/mediaList.tpl | 128 +++++++------ .../js/WoltLab/WCF/Media/Manager/Search.js | 157 ++++++++++++++++ .../files/js/WoltLab/WCF/Media/Search.js | 172 +++++------------- .../lib/acp/page/MediaListPage.class.php | 73 +++++++- .../lib/data/media/MediaAction.class.php | 60 ++---- .../files/lib/data/media/MediaList.class.php | 47 +++++ .../files/lib/page/AbstractPage.class.php | 12 +- 7 files changed, 414 insertions(+), 235 deletions(-) create mode 100644 wcfsetup/install/files/js/WoltLab/WCF/Media/Manager/Search.js diff --git a/wcfsetup/install/files/acp/templates/mediaList.tpl b/wcfsetup/install/files/acp/templates/mediaList.tpl index 75d296d323..31d90004d0 100644 --- a/wcfsetup/install/files/acp/templates/mediaList.tpl +++ b/wcfsetup/install/files/acp/templates/mediaList.tpl @@ -1,39 +1,45 @@ {include file='header' pageTitle='wcf.acp.media.list'} @@ -44,53 +50,55 @@ {include file='formError'} -{* -TODO: add file search
-
-
- {lang}wcf.global.filter{/lang} - -
-
-
- -
-
- -
-
-
+
+

{lang}wcf.global.filter{/lang}

+ +
+
+
+
-
- -
-
-
- -
-
-
-
+ + + + +
+
+
+ +
+
+ + {event name='filterFields'} + + + {event name='sections'}
{@SECURITY_TOKEN_INPUT_TAG}
-*}
{assign var='linkParameters' value=''} - {* + {if $username}{capture append=linkParameters}&username={@$username|rawurlencode}{/capture}{/if} {if $filename}{capture append=linkParameters}&filename={@$filename|rawurlencode}{/capture}{/if} {if $fileType}{capture append=linkParameters}&fileType={@$fileType|rawurlencode}{/capture}{/if} - *} {pages print=true assign=pagesLinks controller="MediaList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$linkParameters"} diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Media/Manager/Search.js b/wcfsetup/install/files/js/WoltLab/WCF/Media/Manager/Search.js new file mode 100644 index 0000000000..b64d292041 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLab/WCF/Media/Manager/Search.js @@ -0,0 +1,157 @@ +/** + * Provides the media search for the media manager. + * + * @author Matthias Schmidt + * @copyright 2001-2015 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLab/WCF/Media/Manager/Search + */ +define(['Ajax', 'Core', 'Dom/Traverse', 'Dom/Util', 'Language', 'WoltLab/WCF/Media/Search', 'Ui/SimpleDropdown'], function(Ajax, Core, DomTraverse, DomUtil, Language, MediaSearch, UiSimpleDropdown) { + "use strict"; + + /** + * @constructor + */ + function MediaManagerSearch(mediaManager) { + MediaSearch.call(); + + this._mediaManager = mediaManager; + this._searchMode = false; + + this._input = elById(this._getIdPrefix() + 'SearchField'); + this._input.addEventListener('keypress', this._keyPress.bind(this)); + + this._cancelButton = elById(this._getIdPrefix() + 'SearchCancelButton'); + this._cancelButton.addEventListener('click', this._cancelSearch.bind(this)); + }; + Core.inherit(MediaManagerSearch, MediaSearch, { + /** + * Returns the data for Ajax to setup the Ajax/Request object. + * + * @return {object} setup data for Ajax/Request object + */ + _ajaxSetup: function() { + return { + data: { + actionName: 'getSearchResultList', + className: 'wcf\\data\\media\\MediaAction', + interfaceName: 'wcf\\data\\ISearchAction' + } + }; + }, + + /** + * Handles successful AJAX requests. + * + * @param {object} data response data + */ + _ajaxSuccess: function(data) { + this._mediaManager.setMedia(data.returnValues.media || { }, data.returnValues.template || ''); + }, + + /** + * Cancels the search after clicking on the cancel search button. + */ + _cancelSearch: function() { + if (this._searchMode) { + this._searchMode = false; + + this._mediaManager.resetMedia(); + this.resetSearch(); + } + }, + + /** + * @see WoltLab/WCF/Media/Search#_getIdPrefix + */ + _getIdPrefix: function() { + return 'mediaManager'; + }, + + /** + * Handles the `[ENTER]` key to submit the form. + * + * @param {Event} event event object + */ + _keyPress: function(event) { + // 13 = [ENTER] + if (event.charCode === 13) { + event.preventDefault(); + + var innerInfo = DomTraverse.childByClass(this._input.parentNode.parentNode, 'innerInfo'); + + // TODO: treshold option? + if (this._input.value.length >= 3) { + if (innerInfo) { + elHide(innerInfo); + } + + this._search(); + } + else { + if (innerInfo) { + elShow(innerInfo); + } + else { + innerInfo = elCreate('p'); + innerInfo.className = 'innerInfo'; + innerInfo.textContent = Language.get('wcf.media.search.info.searchStringTreshold'); + + DomUtil.insertAfter(innerInfo, this._input.parentNode); + } + } + } + }, + + /** + * Sends an AJAX request to fetch seach results. + */ + _search: function() { + this._searchMode = true; + + Ajax.api(this, { + parameters: { + fileType: this._fileType, + fileTypeFilters: this._mediaManager.getOption('fileTypeFilters'), + mode: this._mediaManager.getMode(), + searchString: this._input.value + } + }); + }, + + /** + * @see WoltLab/WCF/Media/Search#_selectFileType + */ + _selectFileType: function(event) { + MediaManagerSearch._super.prototype._selectFileType.call(this, event); + + this._search(); + }, + + /** + * Hides the media search. + */ + hideSearch: function() { + elHide(elById(this._getIdPrefix() + 'Search')); + }, + + /** + * Resets the media search. + */ + resetSearch: function() { + this._input.value = ''; + this._fileType = 'all'; + + this._updateDropdownButtonLabel(); + }, + + /** + * Shows the media search. + */ + showSearch: function() { + elShow(elById(this._getIdPrefix() + 'Search')); + } + }); + + return MediaManagerSearch; +}); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Media/Search.js b/wcfsetup/install/files/js/WoltLab/WCF/Media/Search.js index e0e33a3f4d..6dc909a9b8 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Media/Search.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Media/Search.js @@ -12,26 +12,41 @@ define(['Ajax', 'Dom/Traverse', 'Dom/Util', 'Language', 'Ui/SimpleDropdown'], fu /** * @constructor */ - function MediaSearch(mediaManager) { - this._mediaManager = mediaManager; - this._searchMode = false; + function MediaSearch(initialFileType) { this._fileType = 'all'; - this._input = elById('mediaManagerSearchField'); - this._input.addEventListener('keypress', this._keyPress.bind(this)); - - this._cancelButton = elById('mediaManagerSearchCancelButton'); - this._cancelButton.addEventListener('click', this._cancelSearch.bind(this)); - - var dropdown = UiSimpleDropdown.getDropdownMenu('mediaManagerSearch'); + var dropdown = UiSimpleDropdown.getDropdownMenu(this._getIdPrefix() + 'Search'); if (dropdown) { this._fileTypes = DomTraverse.childrenBySel(dropdown, 'li:not(.dropdownDivider)'); + var selectFileType = this._selectFileType.bind(this); for (var i = 0, length = this._fileTypes.length; i < length; i++) { + var listItem = this._fileTypes[i]; + + if (initialFileType && elData(listItem, 'file-type') == initialFileType) { + this._fileType = initialFileType; + } + this._fileTypes[i].addEventListener('click', selectFileType); } - UiSimpleDropdown.registerCallback('mediaManagerSearch', this._updateFileTypeDropdown.bind(this)); + if (initialFileType && initialFileType.length) { + this._updateDropdownButtonLabel(); + } + + UiSimpleDropdown.registerCallback(this._getIdPrefix() + 'Search', this._updateFileTypeDropdown.bind(this)); + + var form = DomTraverse.parentByTag(elById(this._getIdPrefix() + 'Search'), 'FORM'); + if (form) { + form.addEventListener('submit', function() { + var fileTypeInput = elCreate('input'); + elAttr(fileTypeInput, 'type', 'hidden'); + elAttr(fileTypeInput, 'name', 'fileType'); + elAttr(fileTypeInput, 'value', this._fileType); + + form.appendChild(fileTypeInput); + }.bind(this)); + } } else { this._fileType = null; @@ -39,90 +54,12 @@ define(['Ajax', 'Dom/Traverse', 'Dom/Util', 'Language', 'Ui/SimpleDropdown'], fu }; MediaSearch.prototype = { /** - * Returns the data for Ajax to setup the Ajax/Request object. + * Returns the prefix to identify search-related elements. * - * @return {object} setup data for Ajax/Request object - */ - _ajaxSetup: function() { - return { - data: { - actionName: 'getSearchResultList', - className: 'wcf\\data\\media\\MediaAction', - interfaceName: 'wcf\\data\\ISearchAction' - } - }; - }, - - /** - * Handles successful AJAX requests. - * - * @param {object} data response data - */ - _ajaxSuccess: function(data) { - this._mediaManager.setMedia(data.returnValues.media || { }, data.returnValues.template || ''); - }, - - /** - * Cancels the search after clicking on the cancel search button. - */ - _cancelSearch: function() { - if (this._searchMode) { - this._searchMode = false; - - this._mediaManager.resetMedia(); - this.resetSearch(); - } - }, - - /** - * Handles the `[ENTER]` key to submit the form. - * - * @param {Event} event event object - */ - _keyPress: function(event) { - // 13 = [ENTER] - if (event.charCode === 13) { - event.preventDefault(); - - var innerInfo = DomTraverse.childByClass(this._input.parentNode.parentNode, 'innerInfo'); - - // TODO: treshold option? - if (this._input.value.length >= 3) { - if (innerInfo) { - elHide(innerInfo); - } - - this._search(); - } - else { - if (innerInfo) { - elShow(innerInfo); - } - else { - innerInfo = elCreate('p'); - innerInfo.className = 'innerInfo'; - innerInfo.textContent = Language.get('wcf.media.search.info.searchStringTreshold'); - - DomUtil.insertAfter(innerInfo, this._input.parentNode); - } - } - } - }, - - /** - * Sends an AJAX request to fetch seach results. + * @return {string} */ - _search: function() { - this._searchMode = true; - - Ajax.api(this, { - parameters: { - fileType: this._fileType, - fileTypeFilters: this._mediaManager.getOption('fileTypeFilters'), - mode: this._mediaManager.getMode(), - searchString: this._input.value - } - }); + _getIdPrefix: function() { + return 'media'; }, /** @@ -133,20 +70,33 @@ define(['Ajax', 'Dom/Traverse', 'Dom/Util', 'Language', 'Ui/SimpleDropdown'], fu _selectFileType: function(event) { this._fileType = elData(event.currentTarget, 'file-type'); - this._updateDropdownButtonLabel(); - - this._search(); + this._updateDropdownButtonLabel(event); }, /** * Updates the label of the dropdown button based on the currently selected file type. */ - _updateDropdownButtonLabel: function() { - var dropdown = UiSimpleDropdown.getDropdown('mediaManagerSearch'); + _updateDropdownButtonLabel: function(event) { + var dropdown = UiSimpleDropdown.getDropdown(this._getIdPrefix() + 'Search'); var buttonLabel = DomTraverse.childBySel(DomTraverse.childByClass(dropdown, 'dropdownToggle'), 'SPAN'); if (this._fileType !== 'all') { - buttonLabel.textContent = DomTraverse.childBySel(event.currentTarget, 'SPAN').textContent; + var listItem; + if (event) { + listItem = event.currentTarget; + } + else { + for (var i = 0, length = this._fileTypes.length; i < length; i++) { + var _listItem = this._fileTypes[i]; + + if (elData(_listItem, 'file-type') == this._fileType) { + listItem = _listItem; + break; + } + } + } + + buttonLabel.textContent = DomTraverse.childBySel(listItem, 'SPAN').textContent; } else { buttonLabel.textContent = Language.get('wcf.media.search.filetype'); @@ -162,30 +112,6 @@ define(['Ajax', 'Dom/Traverse', 'Dom/Util', 'Language', 'Ui/SimpleDropdown'], fu listItem.classList[elData(listItem, 'file-type') === this._fileType ? 'add' : 'remove']('active'); } - }, - - /** - * Hides the media search. - */ - hideSearch: function() { - elHide(elById('mediaManagerSearch')); - }, - - /** - * Resets the media search. - */ - resetSearch: function() { - this._input.value = ''; - this._fileType = 'all'; - - this._updateDropdownButtonLabel(); - }, - - /** - * Shows the media search. - */ - showSearch: function() { - elShow(elById('mediaManagerSearch')); } }; diff --git a/wcfsetup/install/files/lib/acp/page/MediaListPage.class.php b/wcfsetup/install/files/lib/acp/page/MediaListPage.class.php index 6bd7668433..7080532b3e 100644 --- a/wcfsetup/install/files/lib/acp/page/MediaListPage.class.php +++ b/wcfsetup/install/files/lib/acp/page/MediaListPage.class.php @@ -3,7 +3,9 @@ namespace wcf\acp\page; use wcf\data\media\ViewableMediaList; use wcf\page\SortablePage; use wcf\system\clipboard\ClipboardHandler; +use wcf\system\request\LinkHandler; use wcf\system\WCF; +use wcf\util\StringUtil; /** * Shows the list of media entries. @@ -20,7 +22,7 @@ class MediaListPage extends SortablePage { /** * @inheritDoc */ - public $activeMenuItem = 'wcf.acp.menu.link.media.list'; + public $activeMenuItem = 'wcf.acp.menu.link.cms.media.list'; /** * @inheritDoc @@ -32,6 +34,23 @@ class MediaListPage extends SortablePage { */ public $defaultSortOrder = 'DESC'; + /** + * searched media filename + * @var string + */ + public $filename = ''; + + /** + * searched media file type + * @var string + */ + public $fileType = 'all'; + + /** + * @inheritDoc + */ + public $forceCanonicalURL = true; + /** * @inheritDoc */ @@ -42,6 +61,12 @@ class MediaListPage extends SortablePage { */ public $objectListClassName = ViewableMediaList::class; + /** + * name of the user who uploaded the searched media files + * @var string + */ + public $username = ''; + /** * @inheritDoc */ @@ -59,7 +84,51 @@ class MediaListPage extends SortablePage { public function assignVariables() { parent::assignVariables(); - WCF::getTPL()->assign('hasMarkedItems', ClipboardHandler::getInstance()->hasMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.media'))); + WCF::getTPL()->assign([ + 'filename' => $this->filename, + 'fileType' => $this->fileType, + 'hasMarkedItems' => ClipboardHandler::getInstance()->hasMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.media')), + 'username' => $this->username + ]); + } + + /** + * @inheritDoc + */ + protected function initObjectList() { + parent::initObjectList(); + + if ($this->filename) { + $this->objectList->addSearchConditions($this->filename); + } + if ($this->fileType) { + $this->objectList->addDefaultFileTypeFilter($this->fileType); + } + if ($this->username) { + $this->objectList->getConditionBuilder()->add('media.username LIKE ?', ['%'.addcslashes($this->username, '_%').'%']); + } + } + + /** + * @inheritDoc + */ + public function readParameters() { + parent::readParameters(); + + if (isset($_REQUEST['filename'])) $this->filename = StringUtil::trim($_REQUEST['filename']); + if (isset($_REQUEST['fileType'])) $this->fileType = StringUtil::trim($_REQUEST['fileType']); + if (isset($_REQUEST['username'])) $this->username = StringUtil::trim($_REQUEST['username']); + + if ($this->fileType == 'all') $this->fileType = ''; + + $parameters = []; + if ($this->sortField) $parameters['sortField'] = $this->sortField; + if ($this->sortOrder) $parameters['sortOrder'] = $this->sortOrder; + if ($this->filename) $parameters['filename'] = $this->filename; + if ($this->fileType) $parameters['fileType'] = $this->fileType; + if ($this->username) $parameters['username'] = $this->username; + + $this->canonicalURL = LinkHandler::getInstance()->getLink('MediaList', $parameters); } /** diff --git a/wcfsetup/install/files/lib/data/media/MediaAction.class.php b/wcfsetup/install/files/lib/data/media/MediaAction.class.php index 7fefe1c2bb..e5662a5736 100644 --- a/wcfsetup/install/files/lib/data/media/MediaAction.class.php +++ b/wcfsetup/install/files/lib/data/media/MediaAction.class.php @@ -28,13 +28,7 @@ use wcf\util\FileUtil; */ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, IUploadAction { /** - * condition builder for searched media file type - * @var PreparedStatementConditionBuilder - */ - public $fileTypeConditionBuilder = null; - - /** - * @inheritdoc + * @inheritDoc */ public function validateUpload() { WCF::getSession()->checkPermissions(['admin.content.cms.canManageMedia']); @@ -47,7 +41,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function upload() { // save files @@ -258,7 +252,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function validateUpdate() { WCF::getSession()->checkPermissions(['admin.content.cms.canManageMedia']); @@ -275,7 +269,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function update() { if (empty($this->objects)) { @@ -345,7 +339,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function validateGetSearchResultList() { if (!WCF::getSession()->getPermission('admin.content.cms.canManageMedia') && !WCF::getSession()->getPermission('admin.content.cms.canUseMedia')) { @@ -359,27 +353,6 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, throw new UserInputException('searchString'); } - $this->fileTypeConditionBuilder = new PreparedStatementConditionBuilder(false); - switch ($this->parameters['fileType']) { - case 'other': - $this->fileTypeConditionBuilder->add('media.fileType NOT LIKE ?', ['image/%']); - $this->fileTypeConditionBuilder->add('media.fileType <> ?', ['application/pdf']); - $this->fileTypeConditionBuilder->add('media.fileType NOT LIKE ?', ['text/%']); - break; - - case 'image': - $this->fileTypeConditionBuilder->add('media.fileType LIKE ?', ['image/%']); - break; - - case 'pdf': - $this->fileTypeConditionBuilder->add('media.fileType = ?', ['application/pdf']); - break; - - case 'text': - $this->fileTypeConditionBuilder->add('media.fileType LIKE ?', ['text/%']); - break; - } - if (isset($this->parameters['fileTypeFilters']) && !is_array($this->parameters['fileTypeFilters'])) { throw new UserInputException('fileTypeFilters'); } @@ -391,24 +364,15 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function getSearchResultList() { - $searchString = '%'.addcslashes($this->parameters['searchString'], '_%').'%'; - $mediaList = new MediaList(); - $mediaList->sqlConditionJoins = 'LEFT JOIN wcf'.WCF_N.'_media_content media_content ON (media_content.mediaID = media.mediaID)'; - - $searchConditionBuilder = new PreparedStatementConditionBuilder(false, 'OR'); - $searchConditionBuilder->add('media_content.title LIKE ?', [$searchString]); - $searchConditionBuilder->add('media_content.caption LIKE ?', [$searchString]); - $searchConditionBuilder->add('media_content.altText LIKE ?', [$searchString]); - $searchConditionBuilder->add('media.filename LIKE ?', [$searchString]); - $mediaList->getConditionBuilder()->add($searchConditionBuilder->__toString(), $searchConditionBuilder->getParameters()); - - if (!empty($this->fileTypeConditionBuilder->__toString())) { - $mediaList->getConditionBuilder()->add($this->fileTypeConditionBuilder->__toString(), $this->fileTypeConditionBuilder->getParameters()); + $mediaList->addSearchConditions($this->parameters['searchString']); + if (!empty($this->parameters['fileType'])) { + $mediaList->addDefaultFileTypeFilter($this->parameters['fileType']); } + $mediaList->getConditionBuilder()->add($searchConditionBuilder->__toString(), $searchConditionBuilder->getParameters()); if (!empty($this->parameters['fileTypeFilters'])) { $mediaList->addFileTypeFilters($this->parameters['fileTypeFilters']); } @@ -435,7 +399,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function validateDelete() { WCF::getSession()->checkPermissions(['admin.content.cms.canManageMedia']); @@ -450,7 +414,7 @@ class MediaAction extends AbstractDatabaseObjectAction implements ISearchAction, } /** - * @inheritdoc + * @inheritDoc */ public function delete() { if (empty($this->objects)) { diff --git a/wcfsetup/install/files/lib/data/media/MediaList.class.php b/wcfsetup/install/files/lib/data/media/MediaList.class.php index 4355635a9b..001a061d4a 100644 --- a/wcfsetup/install/files/lib/data/media/MediaList.class.php +++ b/wcfsetup/install/files/lib/data/media/MediaList.class.php @@ -44,4 +44,51 @@ class MediaList extends DatabaseObjectList { $this->getConditionBuilder()->add($conditionBuilder->__toString(), $conditionBuilder->getParameters()); } } + + /** + * Adds one of the default file filters. + * + * Default filters are: 'image', 'pdf', 'text', 'other'. + * + * @param string $filter + */ + public function addDefaultFileTypeFilter($filter) { + switch ($filter) { + case 'other': + $this->getConditionBuilder()->add('media.fileType NOT LIKE ?', ['image/%']); + $this->getConditionBuilder()->add('media.fileType <> ?', ['application/pdf']); + $this->getConditionBuilder()->add('media.fileType NOT LIKE ?', ['text/%']); + break; + + case 'image': + $this->getConditionBuilder()->add('media.fileType LIKE ?', ['image/%']); + break; + + case 'pdf': + $this->getConditionBuilder()->add('media.fileType = ?', ['application/pdf']); + break; + + case 'text': + $this->getConditionBuilder()->add('media.fileType LIKE ?', ['text/%']); + break; + } + } + + /** + * Adds conditions to search the media files by a certain search string. + * + * @param string $searchString + */ + public function addSearchConditions($searchString) { + $searchString = '%'.addcslashes($searchString, '_%').'%'; + + $this->sqlConditionJoins .= ' LEFT JOIN wcf'.WCF_N.'_media_content media_content ON (media_content.mediaID = media.mediaID)'; + + $conditionBuilder = new PreparedStatementConditionBuilder(false, 'OR'); + $conditionBuilder->add('media_content.title LIKE ?', [$searchString]); + $conditionBuilder->add('media_content.caption LIKE ?', [$searchString]); + $conditionBuilder->add('media_content.altText LIKE ?', [$searchString]); + $conditionBuilder->add('media.filename LIKE ?', [$searchString]); + $this->getConditionBuilder()->add($conditionBuilder->__toString(), $conditionBuilder->getParameters()); + } } diff --git a/wcfsetup/install/files/lib/page/AbstractPage.class.php b/wcfsetup/install/files/lib/page/AbstractPage.class.php index c9f0334091..d6bf0f6ec7 100644 --- a/wcfsetup/install/files/lib/page/AbstractPage.class.php +++ b/wcfsetup/install/files/lib/page/AbstractPage.class.php @@ -50,6 +50,12 @@ abstract class AbstractPage implements IPage, ITrackablePage { */ public $enableTracking = false; + /** + * is true if canonical URL will be enforced even if POST data is represent + * @var boolean + */ + public $forceCanonicalURL = false; + /** * indicates if you need to be logged in to access this page * @var boolean @@ -181,7 +187,7 @@ abstract class AbstractPage implements IPage, ITrackablePage { } // check if current request URL matches the canonical URL - if ($this->canonicalURL && empty($_POST)) { + if ($this->canonicalURL && (empty($_POST) || $this->forceCanonicalURL)) { $canoncialURL = parse_url(preg_replace('~[?&]s=[a-f0-9]{40}~', '', $this->canonicalURL)); // use $_SERVER['REQUEST_URI'] because it represents the URL used to access the site and not the internally rewritten one @@ -222,8 +228,9 @@ abstract class AbstractPage implements IPage, ITrackablePage { } if ($redirect) { - die("should redirect"); $redirectURL = $this->canonicalURL; + // TODO + /* if (!empty($requestURL['query'])) { $queryString = $requestURL['query']; parse_str($requestURL['query'], $rQueryString); @@ -252,6 +259,7 @@ abstract class AbstractPage implements IPage, ITrackablePage { $redirectURL .= (mb_strpos($redirectURL, '?') === false ? '?' : '&') . http_build_query($rQueryString, '', '&'); } } + */ // force a permanent redirect as recommended by Google // https://support.google.com/webmasters/answer/6033086?hl=en#a_note_about_redirects -- 2.20.1