1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-08 07:47:00 +02:00

Expand upon the Page::url() method to include an $options argument that adds many new capabilities.

This commit is contained in:
Ryan Cramer
2016-12-02 10:38:49 -05:00
parent 7eddb51bc9
commit 707cd9e735
4 changed files with 210 additions and 13 deletions

View File

@@ -104,7 +104,8 @@ class Installer {
case 4: $this->dbSaveConfig(); break;
case 5: require("./index.php");
case 5: require("./index.php");
/** @var ProcessWire $wire */
$this->adminAccountSave($wire);
break;

View File

@@ -44,10 +44,11 @@ class NullPage extends Page {
/**
* #pw-internal
*
* @param array $options
* @return string
*
*/
public function url() { return ''; }
public function url($options = array()) { return ''; }
/**
* #pw-internal

View File

@@ -16,6 +16,12 @@
* #pw-summary-system Most system properties directly correspond to columns in the `pages` database table.
* #pw-order-groups common,traversal,manipulation,date-time,access,output-rendering,status,constants,languages,system,advanced,hooks
* #pw-use-constants
* #pw-var $page
* #pw-body =
* The `$page` API variable represents the current page being viewed. However, the documentation
* here also applies to all Page objects that you may work with in the API. We use `$page` as the most common example
* throughout the documentation, but you can substitute that with any variable name representing a Page.
* #pw-body
*
* @link http://processwire.com/api/ref/page/ Offical $page Documentation
* @link http://processwire.com/api/selectors/ Official Selectors Documentation
@@ -2583,7 +2589,7 @@ class Page extends WireData implements \Countable, WireMatchable {
}
/**
* Returns the URL to the page
* Returns the URL to the page (optionally with additional $options)
*
* - This method can also be accessed by property `$page->url` (without parenthesis).
*
@@ -2595,7 +2601,34 @@ class Page extends WireData implements \Countable, WireMatchable {
* - **Need to hook this method?** While it's not directly hookable, it does use the `$page->path()`
* method, which *is* hookable. As a result, you can affect the output of the url() method by
* hooking the path() method instead.
*
*
* ## $options argument
*
* You can specify an `$options` argument to this method with any of the following:
*
* - `pageNum` (int|string): Specify pagination number, or "+" for next pagination, or "-" for previous pagination.
* - `urlSegmentStr` (string): Specify a URL segment string to append.
* - `urlSegments` (array): Specify array of URL segments to append (may be used instead of urlSegmentStr).
* - `data` (array): Array of key=value variables to form a query string.
* - `http` (bool): Specify true to make URL include scheme and hostname (default=false).
* - `language` (Language): Specify Language object to return URL in that Language.
*
* You can also specify any of the following for `$options` as shortcuts:
*
* - If you specify an `int` for options it is assumed to be the `pageNum` option.
* - If you specify `+` or `-` for options it is assumed to be the `pageNum` “next/previous pagination” option.
* - If you specify any other `string` for options it is assumed to be the `urlSegmentStr` option.
* - If you specify a `boolean` (true) for options it is assumed to be the `http` option.
*
* Please also note regarding `$options`:
*
* - This method honors template slash settings for page, URL segments and page numbers.
* - Any passed in URL segments are automatically sanitized with `Sanitizer::pageNameUTF8()`.
* - If using the `pageNum` or URL segment options please also make sure these are enabled on the pages template.
* - The query string generated by any `data` variables is entity encoded when output formatting is on.
* - The `language` option requires that the `LanguageSupportPageNames` module is installed.
* - The prefix for page numbers honors `$config->pageNumUrlPrefix` and multi-language prefixes as well.
*
* ~~~~~
* // Using $page->url to output navigation
* foreach($page->children as $child) {
@@ -2607,14 +2640,54 @@ class Page extends WireData implements \Countable, WireMatchable {
* echo $page->url(); // outputs: /my-site/about/contact/
* echo $page->path(); // outputs: /about/contact/
* ~~~~~
* ~~~~~
* // Specify that you want a specific pagination (output: /example/page2)
* echo $page->url(2);
*
* // Get URL for next and previous pagination
* echo $page->url('+'); // next
* echo $page->url('-'); // prev
*
* // Get a URL with scheme and hostname (output: http://domain.com/example/)
* echo $page->url(true);
*
* // Specify a URL segment string (output: /example/photos/1)
* echo $page->url('photos/1');
*
* // Use a URL segment array (output: /example/photos/1)
* echo $page->url([
* 'urlSegments' => [ 'photos', '1' ]
* ]);
*
* // Get URL in a specific language
* $fr = $languages->get('fr');
* echo $page->url($fr);
*
* // Include data/query vars (output: /example/?action=view&type=photos)
* echo $page->url([
* 'data' => [
* 'action' => 'view',
* 'type' => 'photos'
* ]
* ]);
*
* // Specify multiple options (output: http://domain.com/example/foo/page3?bar=baz)
* echo $page->url([
* 'http' => true,
* 'pageNum' => 3,
* 'urlSegmentStr' => 'foo',
* 'data' => [ 'bar' => 'baz' ]
* ]);
* ~~~~~
*
* @param array|int|string|bool|Language|null $options Optionally specify options to modify default behavior (see method description).
* @return string Returns page URL, for example: `/my-site/about/contact/`
* @see Page::path(), Page::httpUrl(), Page::editUrl(), Page::localUrl()
* @todo add $options support
*
*/
public function url() {
$url = rtrim($this->wire('config')->urls->root, "/") . $this->path();
public function url($options = null) {
if($options !== null) return $this->traversal()->urlOptions($this, $options);
$url = rtrim($this->wire('config')->urls->root, "/") . $this->path();
if($this->template->slashUrls === 0 && $this->settings['id'] > 1) $url = rtrim($url, '/');
return $url;
}
@@ -2634,21 +2707,22 @@ class Page extends WireData implements \Countable, WireMatchable {
* // Generating a link to this page using httpUrl
* echo "<a href='$page->httpUrl'>$page->title</a>";
* ~~~~~
*
*
* @param array $options For details on usage see `Page::url()` options argument.
* @return string Returns full URL to page, for example: `https://processwire.com/about/`
* @see Page::url(), Page::localHttpUrl()
*
*/
public function httpUrl() {
public function httpUrl($options = array()) {
if(!$this->template) return '';
switch($this->template->https) {
case -1: $protocol = 'http'; break;
case 1: $protocol = 'https'; break;
default: $protocol = $this->wire('config')->https ? 'https' : 'http';
default: $protocol = $this->wire('config')->https ? 'https' : 'http';
}
return "$protocol://" . $this->wire('config')->httpHost . $this->url();
if(is_array($options)) unset($options['http']);
else if(is_bool($options)) $options = array();
return "$protocol://" . $this->wire('config')->httpHost . $this->url($options);
}
/**

View File

@@ -709,6 +709,127 @@ class PageTraversal {
return $all;
}
/**
* Returns the URL to the page with $options
*
* You can specify an `$options` argument to this method with any of the following:
*
* - `pageNum` (int|string): Specify pagination number, or "+" for next pagination, or "-" for previous pagination.
* - `urlSegmentStr` (string): Specify a URL segment string to append.
* - `urlSegments` (array): Specify array of URL segments to append (may be used instead of urlSegmentStr).
* - `data` (array): Array of key=value variables to form a query string.
* - `http` (bool): Specify true to make URL include scheme and hostname (default=false).
* - `language` (Language): Specify Language object to return URL in that Language.
*
* You can also specify any of the following for `$options` as shortcuts:
*
* - If you specify an `int` for options it is assumed to be the `pageNum` option.
* - If you specify `+` or `-` for options it is assumed to be the `pageNum` “next/previous pagination” option.
* - If you specify any other `string` for options it is assumed to be the `urlSegmentStr` option.
* - If you specify a `boolean` (true) for options it is assumed to be the `http` option.
*
* Please also note regarding `$options`:
*
* - This method honors template slash settings for page, URL segments and page numbers.
* - Any passed in URL segments are automatically sanitized with `Sanitizer::pageNameUTF8()`.
* - If using the `pageNum` or URL segment options please also make sure these are enabled on the pages template.
* - The query string generated by any `data` variables is entity encoded when output formatting is on.
* - The `language` option requires that the `LanguageSupportPageNames` module is installed.
* - The prefix for page numbers honors `$config->pageNumUrlPrefix` and multi-language prefixes as well.
*
* @param Page $page
* @param array|int|string|bool|Language $options Optionally specify options to modify default behavior (see method description).
* @return string Returns page URL, for example: `/my-site/about/contact/`
* @see Page::path(), Page::httpUrl(), Page::editUrl(), Page::localUrl()
*
*/
public function urlOptions(Page $page, $options = array()) {
$config = $page->wire('config');
$defaults = array(
'http' => is_bool($options) ? $options : false,
'pageNum' => is_int($options) || (is_string($options) && in_array($options, array('+', '-'))) ? $options : 1,
'data' => array(),
'urlSegmentStr' => is_string($options) ? $options : '',
'urlSegments' => array(),
'language' => is_object($options) && $options instanceof Page && $options->className() === 'Language' ? $options : null,
);
if(empty($options)) return rtrim($config->urls->root, '/') . $page->path();
$options = is_array($options) ? array_merge($defaults, $options) : $defaults;
$template = $page->template;
$sanitizer = $page->wire('sanitizer');
$language = null;
$url = null;
if(count($options['urlSegments'])) {
$options['urlSegmentStr'] = implode('/', $options['urlSegments']);
}
if($options['language'] && $page->wire('modules')->isInstalled('LanguageSupportPageNames')) {
if(!is_object($options['language'])) {
$options['language'] = null;
} else if(!$options['language'] instanceof Page) {
$options['language'] = null;
} else if(strpos($options['language']->className(), 'Language') === false) {
$options['language'] = null;
}
if($options['language']) {
/** @var Language $language */
$language = $options['language'];
// localUrl method provided as hook by LanguageSupportPageNames
$url = $page->localUrl($language);
}
}
if(is_null($url)) {
$url = rtrim($config->urls->root, '/') . $page->path();
if($template->slashUrls === 0 && $page->id > 1) $url = rtrim($url, '/');
}
if(is_string($options['urlSegmentStr']) && strlen($options['urlSegmentStr'])) {
$url = rtrim($url, '/') . '/' . $sanitizer->pagePathNameUTF8(trim($options['urlSegmentStr'], '/'));
if($template->slashUrlSegments === '' || $template->slashUrlSegments) $url .= '/';
}
if($options['pageNum']) {
if($options['pageNum'] === '+') {
$options['pageNum'] = $page->wire('input')->pageNum + 1;
} else if($options['pageNum'] === '-' || $options['pageNum'] === -1) {
$options['pageNum'] = $page->wire('input')->pageNum - 1;
}
if((int) $options['pageNum'] > 1) {
$prefix = '';
if($language) {
$lsp = $page->wire('modules')->get('LanguageSupportPageNames');
$prefix = $lsp ? $lsp->get("pageNumUrlPrefix$language") : '';
}
if(!strlen($prefix)) $prefix = $config->pageNumUrlPrefix;
$url = rtrim($url, '/') . '/' . $prefix . ((int) $options['pageNum']);
if($template->slashPageNum) $url .= '/';
}
}
if(count($options['data'])) {
$query = http_build_query($options['data']);
if($page->of()) $query = $sanitizer->entities($query);
$url .= '?' . $query;
}
if($options['http']) {
switch($template->https) {
case -1: $scheme = 'http'; break;
case 1: $scheme = 'https'; break;
default: $scheme = $config->https ? 'https' : 'http';
}
$url = "$scheme://" . $page->wire('config')->httpHost . $url;
}
return $url;
}
/**
* Return the next or previous sibling page (new fast version)
*