Paginations are good to become master of many data. A simple AFX based pagination can be found here. Be sure you have at least Neos 4.3 installed for this type of pagination.
For every file you have to change the Vendor.Packagename informations (don't change Arsors.Prototypes)
You need Paginated.fusion
You need PaginationArrayImplementation.php
You need Routes.yaml
Configure Settings.yaml
<Arsors.Neos:Paginated
collection = (FlowQuery-Object) | Required | Holds the Nodes wich should get a pagination
itemsPerPage = (string) | Default: 24 | How many items per page do you want?
paginationMaxAmount = (string) | Default: 15 | What is the maximum amount of numbers you want to see in the pagination?
paginationClass = (string) | Optional | Additional Class for the pagination
paginationId = (string) | Optional | Additional ID for the pagination
paginationTop = (boolean) | Default: false | Show/Hide the top pagination
paginationBottom = (boolean) | Default: true | Show/Hide the bottom pagination
enableFirst = (boolean) | Default: false | Show/Hide go to first page
enableLast = (boolean) | Default: false | Show/Hide go to last page
enableArrows = (boolean) | Default: true | Show/Hide next and prev arrows
>
Just copy this file and adjust this line to your vendor and package name: Arsors\\Neos\\Fusion\\PaginationArrayImplementation
/*
AFX-PAGINATION
Written by Marvin Schieler https://neos.arsors.de (c) 2019
Inpsired by https://github.com/Flowpack/Flowpack.Listable
*/
prototype(Arsors.Prototypes:Paginated) < prototype(Neos.Fusion:Component) {
# Pagination variables
collection = 'must-be-set'
currentPage = ${request.arguments.currentPage || 1}
itemsTotalAmount = ${this.collection.count()}
itemsPerPage = 24
paginationMaxAmount = 15
needPagination = ${ itemsTotalAmount > itemsPerPage ? true : false }
# Optional pagination variables
paginationClass = null
paginationId = null
paginationTop = false
paginationBottom = true
enableFirst = false
enableLast = false
enableArrows = true
# Set paginatedItems as Array
paginatedItems = ${ this.collection.slice( (this.currentPage - 1) * this.itemsPerPage, this.currentPage * this.itemsPerPage ) }
@context.paginatedItems = ${this.paginatedItems}
# Set pagination as AFX-Template
@context {
itemsTotalAmount = ${this.itemsTotalAmount}
itemsPerPage = ${this.itemsPerPage}
paginationMaxAmount = ${this.paginationMaxAmount}
paginationClass = ${this.paginationClass}
paginationId = ${this.paginationId}
enableFirst = ${this.enableFirst}
enableLast = ${this.enableLast}
enableArrows = ${this.enableArrows}
}
pagination = Arsors.Prototypes:Pagination {
currentPage = ${request.arguments.currentPage || 1}
itemsTotalAmount = ${itemsTotalAmount}
itemsPerPage = ${itemsPerPage}
paginationMaxAmount = ${paginationMaxAmount}
enableFirst = ${enableFirst}
enableLast = ${enableLast}
enableArrows = ${enableArrows}
}
# Output
renderer = afx`
<ul @if.show={props.paginationTop && props.needPagination} class={['pagination', 'paginationTop', props.paginationClass]} id={props.paginationId}>{props.pagination}</ul>
{props.content}
<ul @if.show={props.paginationBottom && props.needPagination} class={['pagination', 'paginationBottom', props.paginationClass]} id={props.paginationId}>{props.pagination}</ul>
`
@cache {
mode = 'cached'
entryIdentifier {
node = ${node}
}
entryDiscriminator = ${request.arguments.currentPage}
context {
1 = 'node'
2 = 'documentNode'
3 = 'site'
}
}
}
prototype(Arsors.Prototypes:PaginationArray) {
@class = 'Arsors\\Neos\\Fusion\\PaginationArrayImplementation'
itemsTotalAmount = ''
currentPage = ''
itemsPerPage = ''
paginationMaxAmount = ''
enableFirst = false
enableLast = false
enableArrows = true
}
prototype(Arsors.Prototypes:Pagination) < prototype(Neos.Fusion:Component) {
@context {
currentPage = ${this.currentPage}
itemsTotalAmount = ${this.itemsTotalAmount}
itemsPerPage = ${this.itemsPerPage}
paginationMaxAmount = ${this.paginationMaxAmount}
enableFirst = ${this.enableFirst}
enableLast = ${this.enableLast}
enableArrows = ${this.enableArrows}
}
# pagination numbers
paginationArray = Arsors.Prototypes:PaginationArray {
itemsTotalAmount = ${itemsTotalAmount}
currentPage = ${currentPage}
itemsPerPage = ${itemsPerPage}
paginationMaxAmount = ${paginationMaxAmount}
enableFirst = ${enableFirst}
enableLast = ${enableLast}
enableArrows = ${enableArrows}
}
renderer = afx`
<li @if.showFirst={props.paginationArray.first}>
<Neos.Neos:NodeLink node={documentNode} additionalParams={{'currentPage':props.paginationArray.first}} content="first" />
</li>
<li @if.showPrevious={props.paginationArray.previous}>
<Neos.Neos:NodeLink node={documentNode} additionalParams={{'currentPage':props.paginationArray.previous}} content="prev" />
</li>
<Neos.Fusion:Loop items={props.paginationArray.pagination} item="item">
<li class={item == props.paginationArray.raw.currentPage ? 'current' : 'normal'}>
<Neos.Neos:NodeLink @if.link={item!='...'} node={documentNode} additionalParams={{'currentPage':item}} content={item} />
<span @if.separator={item=='...'}>{item}</span>
</li>
</Neos.Fusion:Loop>
<li @if.showFirst={props.paginationArray.next}>
<Neos.Neos:NodeLink node={documentNode} additionalParams={{'currentPage':props.paginationArray.next}} content="next" />
</li>
<li @if.showLast={props.paginationArray.last}>
<Neos.Neos:NodeLink node={documentNode} additionalParams={{'currentPage':props.paginationArray.last}} content="last" />
</li>
`
}
prototype(Neos.Fusion:GlobalCacheIdentifiers) {
pagination = ${request.arguments.currentPage}
}
root.@cache.entryIdentifier.pagination = ${request.arguments.currentPage}
prototype(Neos.Neos:Page) {
@cache.entryIdentifier.pagination = ${request.arguments.currentPage}
}
prototype(Neos.Neos:PrimaryContent).default {
renderer.@cache.entryIdentifier.pagination = ${request.arguments.currentPage}
}
Just adjust the namespace to your vendor and package name.
<?php
namespace Arsors\Neos\Fusion;
use Neos\Flow\Annotations as Flow;
use Neos\Fusion\FusionObjects\AbstractFusionObject;
class PaginationArrayImplementation extends AbstractFusionObject {
/**
* @return array
*/
public function evaluate() {
/*
* This snippet comes from https://github.com/Flowpack/Flowpack.Listable
* Extended by Marvin Schieler https://neos.arsors.de
* */
$maximumNumberOfLinks = intval($this->fusionValue('paginationMaxAmount')) - 2;
$paginationMaxAmount = intval($this->fusionValue('paginationMaxAmount'));
$itemsPerPage = intval($this->fusionValue('itemsPerPage'));
$totalCount = intval($this->fusionValue('itemsTotalAmount'));
$currentPage = intval($this->fusionValue('currentPage'));
if ($totalCount > 0 !== true) {
return [];
}
$numberOfPages = ceil($totalCount / $itemsPerPage);
if ($maximumNumberOfLinks > $numberOfPages) {
$maximumNumberOfLinks = $numberOfPages;
}
$delta = floor($maximumNumberOfLinks / 2);
$displayRangeStart = $currentPage - $delta;
$displayRangeEnd = $currentPage + $delta + ($maximumNumberOfLinks % 2 === 0 ? 1 : 0);
if ($displayRangeStart < 1) {
$displayRangeEnd -= $displayRangeStart - 1;
}
if ($displayRangeEnd > $numberOfPages) {
$displayRangeStart -= ($displayRangeEnd - $numberOfPages);
}
$displayRangeStart = (integer)max($displayRangeStart, 1);
$displayRangeEnd = (integer)min($displayRangeEnd, $numberOfPages);
$links = \range($displayRangeStart, $displayRangeEnd);
if ($displayRangeStart >= 2) {
if ($displayRangeStart > 2) array_unshift($links, "...");
if ($displayRangeStart == 2) {
array_pop($links);
}
array_unshift($links, 1);
}
if ($displayRangeEnd + 1 <= $numberOfPages) {
if($displayRangeEnd + 1 < $numberOfPages) $links[] = "...";
if($displayRangeEnd + 1 == $numberOfPages) unset($links[2]);
$links[] = $numberOfPages;
}
$enableFirst = $this->fusionValue('enableFirst');
$enableLast = $this->fusionValue('enableLast');
$enableArrows = $this->fusionValue('enableArrows');
$showFirst = false;
$showLast = false;
$showArrows = [false,false];
if ($enableFirst && $currentPage != 1) $showFirst = 1;
if ($enableLast && $currentPage != $numberOfPages) $showLast = $numberOfPages;
if ($enableArrows) {
if ($currentPage != 1) $showArrows[0] = $currentPage-1;
if ($currentPage != $numberOfPages) $showArrows[1] = $currentPage+1;
}
return [
'raw'=> [
'itemsTotalAmount' => $totalCount,
'currentPage' => $currentPage,
'itemsPerPage' => $itemsPerPage,
'paginationMaxAmount' => $paginationMaxAmount,
],
'first' => $showFirst,
'previous'=>$showArrows[0],
'pagination'=>$links,
'next'=>$showArrows[1],
'last'=>$showLast
];
}
}
Make sure you got the right routing rules for your Settings.yaml
Neos:
Flow:
mvc:
routes:
'Arsors.Neos':
position: 'before Neos.Neos'
Set this route rule, so neos can serve you a link like: xyz.com/en/page/2
-
name: 'pagination page'
uriPattern: '{node}/page/{currentPage}'
defaults:
'@package': 'Neos.Neos'
'@controller': 'Frontend\Node'
'@format': 'html'
'@action': 'show'
routeParts:
node:
handler: Neos\Neos\Routing\FrontendNodeRoutePartHandlerInterface
appendExceedingArguments: TRUE
If you insert all the scripts above to your project you got all what you need.
So last but not least you can call the pagination where ever you want like below.
Note: In paginatedItems you get all the nodes for the current page. You can't change this variable name unless you change the source file.
prototype(Arsors.Neos:Pagination) < prototype(Neos.Neos:ContentComponent) {
collection = ${q(site).find('[instanceof Arsors.Neos:Page]')}
renderer = afx`
<Arsors.Prototypes:Paginated collection={props.collection} itemsPerPage="4">
<ul>
<Neos.Fusion:Loop items={paginatedItems} item="item">
<li><Neos.Neos:NodeLink node={item} /></li>
</Neos.Fusion:Loop>
</ul>
</Arsors.Prototypes:Paginated>
`
}