I am trying to use the Zebra Pagination library to paginate a section of my website. I have managed to do it, but I have a problem with the URL.
I use a .htaccess file to beautify my URL:
<IfModule mod_rewrite.c>
RewriteEngine on
ErrorDocument 404 http://localhost/recopilatorios/php/web/mvc/error/index
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)/(.*) index.php?controlador=$1&accion=$2
</IfModule>
So my URL looks like url_base/controlador/accion
.
The section that I am paging is url_base/listas/clasificacion
, so that when paging it should be url_base/listas/clasificacion&page=x
, where x is the page in question that is being displayed at that moment.
However, the pagination controller that adds the library to my website does not work as expected:
If I go into url_base/listas/clasificacion
and click on the controller to go to the second page, instead of taking me to url_base/listas/clasificacion&page=2
it takes me to url_base/listas/clasificacion?controlador=listas&accion=clasificacion&page=2
, and I still see page 1.
That is, instead of adding just &page=2
add also again the controller and the "unbeautified" action, ?controlador=listas&accion=clasificacion
.
Do you know what could be the problem?
EDITION:
I have found the library function that seems to handle the matter:
/**
* The base URL to be used when generating the navigation links.
*
* This is helpful for the case when the URL where the records are paginated may have parameters that are not needed
* for subsequent requests generated by pagination.
*
* For example, suppose some records are paginated at `https://yourwebsite/mypage/`. When a record from the list is
* updated, the URL could become something like `https://youwebsite/mypage/?action=updated`. Based on the value of
* `action` a message would be shown to the user.
*
* Because of the way this script works, the pagination links would become
*
* `https://youwebsite/mypage/?action=updated&page=[page number]`
*
* when {@link method} is `get` and {@link variable_name} is `page`
*
* `https://youwebsite/mypage/page[page number]/?action=updated`
*
* when {@link method} is `url` and {@link variable_name} is `page`
*
* As a result, whenever the user would paginate, the message would be shown to him again and again because
* `action` will be preserved in the URL!
*
* The solution is to set the `base_url` to `https://youwebsite/mypage/` and in this way, regardless of how the URL
* changes, the pagination links will always be in the form of
*
* `https://youwebsite/mypage/?page=[page number]`
*
* when {@link method} is `get` and {@link variable_name} is `page`
*
* `https://youwebsite/mypage/page[page number]/`
*
* when {@link method} is `url` and {@link variable_name} is `page`
*
* Of course, you may still have query strings in the value of the `base_url` if you wish so, and these will be
* preserved when paginating.
*
* > If you need to preserve the hash in the URL, make sure to include the zebra_pagination.js file in your page!
*
* @param string $base_url (Optional) The base URL to be used when generating the navigation
* links
*
* Defaults is whatever returned by
* {@link https://www.php.net/manual/en/reserved.variables.server.php $_SERVER['REQUEST_URI']}
*
* @param boolean $preserve_query_string (Optional) Indicates whether values in query strings, other than
* those set in `base_url`, should be preserved
*
* Default is `TRUE`
*
* @return void
*/
public function base_url($base_url = '', $preserve_query_string = false) {
// we'll need this in case "variable_name" is an empty string
// (when "base_url" must be explicitly declared)
$this->_properties['base_url_explicit'] = $base_url !== '';
// set the base URL
$base_url = ($base_url == '' ? $_SERVER['REQUEST_URI'] : $base_url);
// parse the URL
$parsed_url = parse_url($base_url);
// cache the "path" part of the URL (that is, everything *before* the "?")
$this->_properties['base_url'] = rtrim($parsed_url['path'], '/');
// cache the "query" part of the URL (that is, everything *after* the "?")
$this->_properties['base_url_query'] = isset($parsed_url['query']) ? $parsed_url['query'] : '';
// store query string as an associative array
parse_str($this->_properties['base_url_query'], $this->_properties['base_url_query']);
// should query strings (other than those set in $base_url) be preserved?
$this->_properties['preserve_query_string'] = $preserve_query_string;
}
Changing the input parameter from $preserve_query_string
to true
stops false
adding the controller and action, which is a step forward, but adds the page with ?
instead of with &
, like this: url_base/listas/clasificacion?page=x
instead of like this: url_base/listas/clasificacion&page=x
, which also doesn't work.
EDIT 2:
I have sent an email to the creator of the library and he tells me that it is mandatory for the string to start with ?
, that it must be a problem with my .htaccess.
EDIT 3:
Attached the HTML of the pagination. I have taken it directly from the browser console, because in my code I only tell the library to apply the method render()
on my object $paginacion
:
if($elementos_totales > $elementos_por_pagina) //Controlador de la páginación
{
$paginacion->labels('<<', '>>');
$paginacion->render();
}
The HTML:
<div class="Zebra_Pagination">
<ol class="pagination">
<li class="page-item disabled">
<a href="javascript:void(0)" class="page-link"><<</a>
</li>
<li class="page-item active">
<a href="/recopilatorios/php/web/mvc/listas/clasificacion" class="page-link">1</a>
</li>
<li class="page-item">
<a href="/recopilatorios/php/web/mvc/listas/clasificacion?pagina=2" class="page-link">2</a>
</li>
<li class="page-item">
<a href="/recopilatorios/php/web/mvc/listas/clasificacion?pagina=2" class="page-link">>></a>
</li>
</ol>
</div>
It now looks like this because of some modifications I've made to the CSS, in addition to changing the labels
:
I guess the key is here, but from my code I think I have no possibility to access this link, it is automatically generated by the method:
<a href="/recopilatorios/php/web/mvc/listas/clasificacion?pagina=2" class="page-link">2</a>
EDIT 4:
I think I found the function that generates the link:
/**
* Generate the link for the page given as argument.
*
* @return void
*/
private function _build_uri($page) {
// if page propagation method is through SEO friendly URLs
if ($this->_properties['method'] == 'url') {
// see if the current page is already set in the URL
// when "variable_name" is an empty string we'll also factor in "base_url" (which is mandatory in this case)
if (preg_match(
'/\b' . str_replace('/', '\/', preg_quote(($this->_properties['variable_name'] === '' ? $this->_properties['base_url'] . '/' : '') . $this->_properties['variable_name'])) . '([0-9]+)\b/i',
$this->_properties['variable_name'] === '' ? $_SERVER['REQUEST_URI'] : $this->_properties['base_url']
) > 0) {
// build string
$url = str_replace('//', '/', preg_replace(
// replace the currently existing value
// (also handle the case when "variable_name" is an empty string)
'/\b' . str_replace('/', '\/', preg_quote(($this->_properties['variable_name'] === '' ? $this->_properties['base_url'] . '/' : '') . $this->_properties['variable_name'])) . '([0-9]+)\b/i',
// if on the first page and we are avoiding duplicate content, remove page number
// (also handle the case when "variable_name" is an empty string)
($this->_properties['variable_name'] === '' ? $this->_properties['base_url'] . '/' : '') . ($page == 1 && $this->_properties['avoid_duplicate_content'] ? '' : $this->_properties['variable_name'] . $page),
// handle the case when "variable_name" is an empty string
$this->_properties['variable_name'] === '' ? $_SERVER['REQUEST_URI'] : $this->_properties['base_url']
));
// if the current page is not yet in the URL, set it, unless we're on the first page
// case in which we don't set it in order to avoid duplicate content
} else $url = ($this->_properties['variable_name'] !== '' ? $this->_properties['base_url'] . '/' : '') . $this->_properties['variable_name'] . $page;
// handle trailing slash according to preferences
$url = rtrim($url, '/') . ($this->_properties['trailing_slash'] ? '/' : '');
// if values in the query string - other than those set through base_url() - are not to be preserved
// preserve only those set initially
if (!$this->_properties['preserve_query_string']) $query = implode('&', $this->_properties['base_url_query']);
// otherwise, get the current query string
else $query = $_SERVER['QUERY_STRING'];
// return the built string also appending the query string, if any
$uri = $url . ($query != '' ? '?' . $query : '');
// if page propagation is to be done through GET
} else {
// if values in the query string - other than those set through base_url() - are not to be preserved
// preserve only those set initially
if (!$this->_properties['preserve_query_string']) $query = $this->_properties['base_url_query'];
// otherwise, get the current query string, if any, and transform it to an array
else parse_str($_SERVER['QUERY_STRING'], $query);
// if we are avoiding duplicate content and if not the first/last page (depending on whether the pagination links are shown in natural or reversed order)
if (!$this->_properties['avoid_duplicate_content'] || ($page != ($this->_properties['reverse'] ? $this->_properties['total_pages'] : 1)))
// add/update the page number
$query[$this->_properties['variable_name']] = $page;
// if we are avoiding duplicate content, don't use the "page" variable on the first/last page
elseif ($this->_properties['avoid_duplicate_content'] && $page == ($this->_properties['reverse'] ? $this->_properties['total_pages'] : 1))
unset($query[$this->_properties['variable_name']]);
// make sure the returned HTML is W3C compliant
$uri = htmlspecialchars(html_entity_decode($this->_properties['base_url']) . (!empty($query) ? '?' . http_build_query(array_map('urldecode', $query)) : ''));
}
// if for whatever reason the URI is an empty string it means it should be pointing to the root ("/")
// we can't leave this as an empty string or it will point to whatever URL is currently open in the browser
return $uri !== '' ? $uri : '/';
}
EDIT 5:
I've tried substituting '?'
for '&'
on both lines where it appears and, well, it works fine the first time you click a button, but then it keeps adding &pagina=x
like crazy, ending up with an unsightly URL:
url_base/listas/clasificacion&pagina=2&pagina=3&pagina=4&pagina=3&pagina=2
More than two pages come out because I have tried to reduce the number of elements per page:
Also, it is impossible to go back to the first page, since it would have to be simply:
url_base/listas/clasificacion
The solution was as simple as adding
[QSA]
to theRewriteRule
:150 reputation points evaporated afterwards, not too bad.