Filter page list to only show the latest page for each unique author

Hello, Im trying to filter a pagelist programmatically so that it only shows one page for each unique author. That is to exclude pages with duplicate authors and only keep the most recent one. Thought I should check with you concrete veterans here on the forums to see if anyone of you have any suggestion of how to achieve this.

Thanks in advance!
Martin

Think you have found a bug? Instead of posting about it here, make an issue on Github here:

There are 3 ways I can think of:
1- if you want to only showing the latest post by 1 specific author on a page. Say itā€™s the authorā€™s page. Filter the list by user ID, order by date and grab the first one.
2- if you want to show a whole list of latest post by each author, order the list by user ID than run a foreach loop on it and compare dates. Unfortunately you canā€™t sort by more than 1 parameter
3- grab the SQL query generated by the PageList object and modify it to add a second sorting parameter and return only 1 result by author then copy the get method from the object and use it to return your page objects.

@mnakalay #2 is close. @svbrf is wanting to show a list of ā€œstoriesā€, newest first. Each individual author will have their latest post ONLY in the list. Iā€™m thinking build an array of user idā€™s as each new author is stumbled upon to thereafter check if a user has a page in the list already etc. Iā€™m going to stab at this one and will post the code for further improvement!

I recently did a similar extension to the page list class as @mnakalay #3 to list pages containing forms built with Form Reform for a ā€˜Find my Formsā€™ dashboard page. The tricky part was making sure that a page with N form component blocks on it was only listed once. I can imagine a ā€˜most recent by authorā€™ extension to a page list being a similar SQL structure.

Having said that, as @enlil suggests, variations of #2 would be easier to code, but could be tricky to paginate and could be expensive if there are 10 authors and the most recent by one of them is 1000 posts old. For a limited number of authors not requiring pagination, #2 would not fall into either of such problem areas.

OK, So Iā€™m up well past my bedtime this morning. Got this nasty addiction to PHP Iā€™m dealing with :rofl: 2 for 1, 1 for 2. However you look at it, one is paginated, the other is not. Enjoy :wink:

// View All
$list = new \Concrete\Core\Page\PageList();
$list->filterByPageTypeHandle('blog_entry');
$list->sortByPublicDate();

$uniqueAuthors = [];
$expr = $list->getQueryObject()->expr();
foreach ($list->getResults() as $p) {
	if (in_array($p->getCollectionUserID(), $uniqueAuthors)) {
		$list->getQueryObject()->andWhere($expr->neq('p.cID', $p->getCollectionID()));
	} else {
		$uniqueAuthors[] = $p->getCollectionUserID();
	}
	// Exclude Current Page
	//$list->getQueryObject()->andWhere($expr->neq('p.cID', Page::getCurrentPage()->getCollectionID()));
}

$pages = $list->getResults();
foreach ($pages as $p) {
	echo $p->getCollectionName() . '<br>';
}





// Paginated
$list = new \Concrete\Core\Page\PageList();
$list->filterByPageTypeHandle('blog_entry');
$list->sortByPublicDate();

$uniqueAuthors = [];
$expr = $list->getQueryObject()->expr();
foreach ($list->getResults() as $p) {
	if (in_array($p->getCollectionUserID(), $uniqueAuthors)) {
		$list->getQueryObject()->andWhere($expr->neq('p.cID', $p->getCollectionID()));
	} else {
		$uniqueAuthors[] = $p->getCollectionUserID();
	}
	// Exclude Current Page
	//$list->getQueryObject()->andWhere($expr->neq('p.cID', Page::getCurrentPage()->getCollectionID()));
}

$list->setItemsPerPage(1);
$pagination = $list->getPagination();
$pages = $pagination->getCurrentPageResults();
if ($pagination->haveToPaginate()) {
	
	$options = array(
		'prev_message'        => t('ā† Back'),
		'next_message'        => t('Next ā†’'),
	);
	$pagination = $pagination->renderDefaultView($options);
}

foreach ($pages as $p) {
	echo $p->getCollectionName() . '<br>';
}

echo $pagination;

@JohntheFish only thing atm that trips me up with pagination is getting at the seoCanonical class from a view to clean up the pesky page 1 url

Worked out of the box, Im impressed! Marked as solution.

I am not 100% convinced there would be a real boost in performance but I think the final Query would be lighter done this way:

$queries = [];

foreach ($list->getResults() as $p) {
	if (!isset($queries[$p->getCollectionUserID()])) {
		$queries[$p->getCollectionUserID()] = $expr->eq('p.cID', $p->getCollectionID());
	}
}

$list->getQueryObject()->expr()->orX(...$queries);
1 Like