get('MarkupPagerNav'); * #pw-summary-options-methods Specific to setting certain options that are typically set automatically. Not necessary to use these unless for a specific purpose. * * #pw-body = * This module can create pagination for a `PageArray` or any other kind of `PaginatedArray` type. * Below is an example of creating pagination for a PageArray returned from `$pages->find()`. * ~~~~~ * // $items can be PageArray or any other kind of PaginatedArray type * $items = $pages->find("id>0, limit=10"); // replace id>0 with your selector * if($items->count()) { * $pager = $modules->get("MarkupPagerNav"); * echo "
Sorry there were no items found
"; * } * ~~~~~ * Here’s a shortcut alternative that you can use for PageArray types (thanks to the `MarkupPageArray` module). * Note that in this case, it’s not necessary to load the MarkupPagerNav module yourself: * ~~~~~ * $items = $pages->find("id>0, limit=10"); // replace id>0 with your selector * if($items->count()) { * echo "Sorry there were no items found
"; * } * ~~~~~ * It’s common to specify different markup and/or classes specific to the need when rendering * pagination. This is done by providing an `$options` array to the `MarkupPagerNav::render()` call. * In the example below, we'll specify Uikit markup rather then the default markup: * ~~~~~ * // Change options for Uikit "uk-pagination" navigation * $options = array( * 'numPageLinks' => 5, * 'listClass' => 'uk-pagination', * 'linkMarkup' => "{out}", * 'currentItemClass' => 'uk-active', * 'separatorItemLabel' => '…', * 'separatorItemClass' => 'uk-disabled', * 'currentLinkMarkup' => "{out}" * 'nextItemLabel' => '', * 'previousItemLabel' => '', * 'nextItemClass' => '', // blank out classes irrelevant to Uikit * 'previousItemClass' => '', * 'lastItemClass' => '', * ); * * $items = $pages->find("id>0, limit=10"); // replace id>0 with your selector * * if($items->count()) { * $pager = $modules->get('MarkupPagerNav'); * echo "Sorry there were no items found
"; * } * ~~~~~ * The full list of options can be seen below. Please note that most options are set automatically since this module can * determine most of the needed information directly from the WireArray that it’s given. As a result, it’s often * not necessary to change any of the default options unless you want to change the markup and/or classes used in output. * #pw-body * * @property int $numPageLinks The number of links that the pagination navigation should have, minimum 5 (default=10). #pw-group-general-options * @property array $getVars GET vars that should appear in the pagination, or leave empty and populate $input->whitelist (recommended). #pw-group-general-options * @property string $baseUrl The base URL from which the navigation item links will start (default=''). #pw-group-general-options * @property null|Page $page The current Page, or leave NULL to autodetect. #pw-group-general-options * @property string $listMarkup List container markup. Place {out} where you want the individual items rendered and {class} where you want the list class (default="Sorry there were no items found
"; * } * ~~~~~ * * @param WirePaginatable|PageArray|PaginatedArray $items Items used in the pagination that have had a "limit=n" selector applied when they were loaded. * @param array $options Any options to override the defaults. See the `MarkupPagerNav` reference for all options. * @return string * @see MarkupPageArray::renderPager() * */ public function ___render(WirePaginatable $items, $options = array()) { $config = $this->wire()->config; $this->isLastPage = true; $this->totalItems = $items->getTotal(); if(!$this->totalItems) return ''; $this->options = array_merge($this->options, $options); $limit = $items->getLimit(); if($limit) $this->itemsPerPage = $limit; $this->pageNum = $items->getStart() < $this->itemsPerPage ? 1 : ceil($items->getStart() / $this->itemsPerPage)+1; if(is_null($this->options['page'])) { $this->options['page'] = $this->wire('page'); } if(!strlen($this->queryString)) { $whitelist = $this->wire()->input->whitelist->getArray(); if(!count($this->options['getVars']) && count($whitelist)) { $this->setGetVars($whitelist); } else if(count($this->options['getVars'])) { $this->setGetVars($this->getVars); } } if($config->pageNumUrlPrefix) { $this->pageNumUrlPrefix = $config->pageNumUrlPrefix; } $pagerNav = new PagerNav($this->totalItems, $this->itemsPerPage, $this->pageNum); $pagerNav->setLabels($this->options['previousItemLabel'], $this->options['nextItemLabel']); $pagerNav->setNumPageLinks($this->numPageLinks); $pager = $pagerNav->getPager(); $out = ''; $pagerCount = count($pager); if($pagerCount > 1) $this->isLastPage = false; $firstNumberKey = null; $lastNumberKey = null; // determine first and last numbered items foreach($pager as $key => $item) { if(!ctype_digit("$item->label")) continue; if(is_null($firstNumberKey)) $firstNumberKey = $key; $lastNumberKey = $key; } $_url = ''; // URL from previous loop interation $nextURL = ''; $prevURL = ''; $lastWasCurrent = false; // was the last iteration for the current page item? foreach($pager as $key => $item) { if($item->type == 'separator') { $out .= $this->renderItemSeparator(); continue; } $url = $this->getURL($item->pageNum); $classes = array(); if($item->type != 'first' && $item->type != 'last' && isset($this->options[$item->type . 'ItemClass'])) { $classes[] = $this->options[$item->type . 'ItemClass']; } if(!$key) { $classes[] = $this->options['firstItemClass']; } else if($key == ($pagerCount-1)) { $classes[] = $this->options['lastItemClass']; } if($key === $firstNumberKey) { $classes[] = $this->options['firstNumberItemClass']; } else if($key === $lastNumberKey) { $classes[] = $this->options['lastNumberItemClass']; if($item->type == 'current') $this->isLastPage = true; } $itemExtraAttr = ''; if($item->type == 'current') { $itemAriaLabel = $this->options['currentItemAriaLabel']; $itemExtraAttr = ' ' . $this->options['currentItemExtraAttr']; } else if($item->type == 'previous') { $itemAriaLabel = $this->options['previousItemAriaLabel']; } else if($item->type == 'next') { $itemAriaLabel = $this->options['nextItemAriaLabel']; } else if($item->type == 'last') { $itemAriaLabel = $this->options['lastItemAriaLabel']; } else { $itemAriaLabel = $this->options['itemAriaLabel']; } $itemAriaLabel = str_replace('{n}', $item->pageNum, $itemAriaLabel); if(isset($this->options[$item->type . 'LinkMarkup'])) { $linkMarkup = $this->options[$item->type . 'LinkMarkup']; } else { $linkMarkup = $this->options['linkMarkup']; } $link = str_replace(array('{url}', '{out}'), array($url, $item->label), $linkMarkup); $out .= str_replace( array( '{class}', '{out}', '{aria-label}', ' {attr}', '{attr}' ), array( implode(' ', $classes), $link, $itemAriaLabel, $itemExtraAttr, $itemExtraAttr ), $this->options['itemMarkup'] ); if($item->type == 'current') { $prevURL = $_url; $lastWasCurrent = true; } else { if($lastWasCurrent) $nextURL = $url; $lastWasCurrent = false; } $_url = $url; // remember previous url } if($out) { $out = str_replace(array( '{class}', '{aria-label}', '{out}', " class=''", ' class=""' ), array( $this->options['listClass'], $this->options['listAriaLabel'], $out, '', '' ), $this->options['listMarkup']); if($nextURL || $prevURL) $this->updateConfigVars($nextURL, $prevURL); } return $out; } /** * Render the "..." item separator * * @return string * */ protected function renderItemSeparator() { if($this->options['separatorItemMarkup'] !== null) { $markup = $this->options['separatorItemMarkup']; } else { $markup = $this->options['itemMarkup']; } return str_replace( array( '{class}', '{out}', '{aria-label}', ' {attr}', // optionally with leading space '{attr}' ), array( $this->options['separatorItemClass'], $this->options['separatorItemLabel'], '', '', '' ), $markup ); } /** * Retrieve a MarkupPagerNav option as an object property * * @param string $name * @return mixed * */ public function __get($name) { if(isset($this->options[$name])) return $this->options[$name]; if($name === 'isLastPage') return $this->isLastPage; return null; } /** * Set a MarkupPagerNav option as an object property * * @param string $property * @param mixed $value * */ public function __set($property, $value) { if(isset($this->options[$property])) $this->options[$property] = $value; } /** * Returns true when the current pagination is the last one * * Only set after a render() call. Prior to that it is null. * * #pw-internal * * @return bool|null * */ public function isLastPage() { return $this->isLastPage; } /** * Get all options or set options * * - See the main `MarkupPagerNav` documentation for a list of all available options. * - When used to set options this method should be called before the `MarkupPagerNav::render()` method. * - Options can also be set as a 2nd argument to the `MarkupPagerNav::render()` method. * * ~~~~~ * // Getting options * echo "" . print_r($pager->options(), true) . ""; * * // Setting options * $pager->options([ 'numPageLinks' => 5 ]); * echo $pager->render($items); * * // Alternative that does the same as above * echo $pager->render($items, [ 'numPageLinks' => 5 ]); * ~~~~~ * * @param array $options Associative array of options you want to set, or omit to just return all available/current options. * @return array Returns associative array if options with all current values. * @since 3.0.44 * */ public function options(array $options = array()) { if(!empty($options)) { $this->options = array_merge($this->options, $options); } return $this->options; } /************************************************************************************************* * All the methods below are optional and typically set automatically, or via the $options param. * */ /** * Set the getVars for this MarkupPagerNav * * Generates $this->options['queryString'] automatically. * * #pw-group-method-options * * @param array $vars Array of GET vars indexed as ($key => $value) * */ public function setGetVars(array $vars) { $this->options['getVars'] = $vars; $queryString = "?"; foreach($this->options['getVars'] as $key => $value) { if(is_array($value)) { if($this->options['arrayToCSV']) { $queryString .= "$key=" . urlencode(implode(",", $value)) . "&"; } else { foreach($value as $v) $queryString .= "$key%5B%5D=" . urlencode($v) . "&"; } } else { $queryString .= "$key=" . urlencode($value) . "&"; } } $this->queryString = htmlspecialchars(rtrim($queryString, "?&")); } /** * Set the current page number * * #pw-group-method-options * * @param int $n * */ public function setPageNum($n) { $this->pageNum = $n; } /** * Set the number of items shown per page * * #pw-group-method-options * * @param int $n * */ public function setItemsPerPage($n) { $this->itemsPerPage = $n; } /** * Set the total number of items * * #pw-group-method-options * * @param int $n * */ public function setTotalItems($n) { $this->totalItems = $n; } /** * Set the number of pagination links to use * * #pw-group-method-options * * @param int $n * */ public function setNumPageLinks($n) { $this->numPageLinks = $n; } /** * Set the query string * * #pw-group-method-options * * @param string $s Already-sanitized/validated query string * */ public function setQueryString($s) { $this->queryString = $s; } /** * Set the base URL for pagination * * #pw-group-method-options * * @param string $url * */ public function setBaseUrl($url) { $this->baseUrl = $url; } /** * Set the "next" and "prev" labels * * #pw-group-method-options * * @param string $next * @param string $prev * */ public function setLabels($next, $prev) { $this->options['nextItemLabel'] = $next; $this->options['previousItemLabel'] = $prev; } /** * Get URL for given pagination number * * Requires that render() method has already started or been previously called. * * @param int $pageNum * @param bool $http Include scheme and hostname? * @return string * */ public function getURL($pageNum, $http = false) { /** @var Page $page */ $page = $this->options['page']; $template = $page->template; if($this->baseUrl) { $url = $this->baseUrl; } else if($http) { $url = $page->httpUrl(); } else { $url = $page->url(); } if($pageNum > 1) { if($template->allowPageNum) { // if allowPageNum is true, then we can use urlSegment style page numbers rather than GET var page numbers if($template->slashUrls === 0) $url .= '/'; // enforce a trailing slash, regardless of slashUrls template setting $url .= $this->pageNumUrlPrefix . $pageNum; if($template->slashPageNum > 0) $url .= '/'; $url .= $this->queryString; } else { // query string style pagination $url .= $this->queryString . (strlen($this->queryString) ? "&" : "?") . "$this->pageNumUrlPrefix=$pageNum"; } } else { $url .= $this->queryString; } return $url; } /** * Populate $config->urls->next, $config->urls->prev, and $config->pagerHeadTags * * @param string $nextURL * @param string $prevURL * */ protected function updateConfigVars($nextURL, $prevURL) { $config = $this->wire()->config; $httpRoot = $this->wire()->input->httpHostUrl(); $pagerHeadTags = ''; if($nextURL) { $config->urls->next = $nextURL; $pagerHeadTags .= ""; } if($prevURL) { $config->urls->prev = $prevURL; $pagerHeadTags .= ""; } $config->set('pagerHeadTags', $pagerHeadTags); } /* * The following methods are specific to the Module interface * */ public function init() { } public function ___install() { } public function ___uninstall() { } }