Concrete CMS provides the Concrete\Core\Page\PageList
object to make it easy for developers to query Concrete for a list of pages based on different criteria.
Any time you want to sort, search or filter a list of pages you should use this object (rather than querying the database directly), as it handles the compexities of permissions, page versions, and aliasing, and provides a nice API on top of the fairly complex table structure underneath.
To fetch a list of all pages in your sitemap:
$list = new \Concrete\Core\Page\PageList();
$pages = $list->getResults();
By default, this list will include all pages in your site, with the exception of:
- Aliases
- Inactive pages (e.g. drafts or pages in the trash)
- Pages that the current user cannot access, based on permissions
- System and dashboard pages
This is an array of all Page
objects, with no limit.
Basic Filtering Examples
Filtering a PageList
query involves calling a filterBy...()
function prior to getResults()
.
To only return results for a specific page type:
$list = new \Concrete\Core\Page\PageList();
$list->filterByPageTypeHandle('blog_entry');
$pages = $list->getResults();
To include pages of several types:
$list->filterByPageTypeHandle(['blog_entry', 'press_release']);
To filter by keywords (simple):
$list->filterByKeywords('foobar');
Filtering by keywords performs a simple LIKE
query against the name, description or text content of a page, as well as the textual representation of any page attributes that have been marked as "included in search index".
To perform a more advanced search on the name, description and text content fields using MySQL's FULLTEXT search indexing:
$list->filterByFulltextKeywords('foobar');
Filter by Attribute
The PageList
object contains some 'magic methods' to filter easily by attributes. Simply add a StudlyCapsed attribute handle after filterBy and pass the data into the attribute:
$list->filterByExcludeNav(true);
The attribute's type determines what kind of data it takes in its filter methods. For example, if the attribute is a topic, it can take a topic tree node:
$topicNode = \Concrete\Core\Tree\Node::getByID(10);
$list->filterByBlogEntryTopic($topicNode);
Sorting
To sort the list by the public post date:
$list = new \Concrete\Core\Page\PageList();
$list->sortByPublicDate();
$pages = $list->getResults();
Or to reverse the order:
$list->sortByPublicDateDescending();
To sort alphabetically by name:
$list->sortByName();
To sort by the order shown in the sitemap:
$list->sortByDisplayOrder();
To sort by an page attribute:
$list->sortByAttributeName();
or
$list->sortBy('ak_attribute_name', 'ASC|DSC');
Permissions and Including Atypical Pages
To list all pages while ignoring permissions:
$list->ignorePermissions();
Include unusual pages:
$list->includeInactivePages();
$list->includeAliases();
$list->includeSystemPages();
Multilingual site search
By default PageList
will only return results from the active locale siteTree. To search in all siteTrees include this:
$list->setSiteTreeToAll();
Advanced Techniques
Custom Queries
The PageList
class was completely rewritten in Concrete 5.7 on top of the Doctrine DBAL QueryBuilder. You can grab the underlying QueryBuilder object in order to operate on it directly from any PageList object:
$list = new \Concrete\Core\Page\PageList();
$list->getQueryObject()
->where('p.clsActive', 1)
->andWhere('p.clsTemplate', 0)
->orderBy('p.cDisplayOrder', 'ASC');
$pages = $list->getResults();
Subclassing
If you find yourself performing the same custom queries multiple times throughout the site, you can reduce the duplication by creating a new class that extends the built-in PageList
class.
Here's an example of a custom class that only displays pages of a certain type, with a custom attribute for handling whether pages are included:
<?php
namespace PortlandLabs\ClassifiedList;
use Concrete\Core\Page\PageList;
class ClassifiedList extends PageList
{
/** @var boolean */
protected $includeInactive = false;
public function __construct()
{
// First call the default constructor, and then add any filters and sort options
// that should occur by default
parent::__construct();
$this->ignorePermissions();
$this->filterByPageTypeHandle('classified');
$this->setItemsPerPage(10);
$this->sortByPublicDateDescending();
}
public function deliverQueryObject()
{
if (!$this->includeInactive) {
$this->filterByClassifiedIsDeactivated(false);
}
return parent::deliverQueryObject();
}
public function includeInactive()
{
$this->includeInactive = true;
}
public function filterByActive($start, $end = null)
{
if (!$end) {
$end = $start;
}
$this->filterByPublicDate(date('Y-m-d H:i:s', $end), "<=");
$this->filterByAttribute('special_offer_end_date', date('Y-m-d H:i:s', $start), ">=");
}
}
Pagination
Once you have filtered your PageList object, getResults()
will return all matching pages.
Many times, however, you'll want to retrieve just few results at a time. For this, you'll want to use the Pagination object:
$list = new \Concrete\Core\Page\PageList();
$pagination = $list->getPagination();
$pagination->setMaxPerPage(10)->setCurrentPage(2);
$results = $pagination->getCurrentPageResults();
With Permissions
If your page list is honoring permissions (as it does by default), the $pagination
object will be an instance of the Concrete\Core\Search\Pagination\PermissionablePagination
object. This means that the entire result set (up to 1000) will be loaded and then segmented, with the permissions checker run against it.
Without Permissions
If your PageList object is ignoring permissions, it simply returns a basic Concrete\Core\Search\Pagination\Pagination object, which is simpler.
Pagination functions
The Pagination
object provides several helpful functions. To get the total number of results:
echo $pagination->getTotalResults();
To get the total number of pages:
echo $pagination->getTotalPages();
To determine whether paging is necessary:
$pagination->hasNextPage();
$pagination->hasPreviousPage();
Rendering Pagination
Several common pagination styles are built-in, including Bootstrap 2, Bootstrap 3, Basic Pagination, and Concrete's default styling (which is heavily Bootstrap 3 inspired).
echo $pagination->renderDefaultView(); // Outputs HTML for Bootstrap 3, useful in the Dashboard, etc…
You can also render any pagination view supported by Pagerfanta
from your Pagination object. More information available here.