Prepend collection to collection

How to prepend a collection to another collection, so we ensure the first is placed at the beggining of the second ?


Considering the page collections, I think prepend() or merge() methods will do the trick. Especially merge().


prepend got me an exception, I assumed because the description refers to ‘an element’ and not a collection as in merge.

Using merge did not seem to respect the order, as in one collection before the other.

The code I am using this with is a old’ish, a bit convoluted and I am resisting the urge to rewrite it, but let me reproduce it here anyway, it is a page method:

    'sortedProgrammesPanel' => function () {
        // Sorts LISTED 'programme' pages by 'publicationDate' of their last child, 
        // or by their own publicationDate if they don't have children.
		$sortedProgrammesPanel = new Pages();
		$theChildren = new Pages();

		foreach(site()->children()->filterBy('intendedtemplate', 'programme')->listed() as $p) {
			if ($p->hasChildren()) {
				$theChildren->append($p->children()->last()); // appends the last children
			} else { // if no children, append the parent itself

        // Sort
		$theChildren = $theChildren->sortBy('publicationDate', 'desc');

        // Now loop $theChildren to sort programme pages
		foreach($theChildren as $c) {
			if ($c->intendedTemplate() == 'programme') { // If it is a programme without children
				$sortedProgrammesPanel->append($c); // Append the programme itself			
			} else {
				$sortedProgrammesPanel->append($c->parent()); // If it is an update append the parent programme

        // Prepend draft programmes to the collection and return it
		$sortedProgrammesPanel->merge(site()->children()->filterBy('intendedtemplate', 'programme')->drafts());
		return $sortedProgrammesPanel->indexOf($this);

This page method is used in query language as such:

    type: pages
    headline: Programmes
    status: all
    sortable: false
    sortBy: sortedProgrammesPanel
      - programme
    image: false
    width: 1/2

In this pages section in the panel I get the drafts mixed between the listed programme pages, and not at the beggining or end of the list, which is what I am attempting to achieve

Thank you

If I got the problem right.

  1. I think you don’t need to sort the collection in section (sortBy: sortedProgrammesPanel), you have already listed on PHP side.

  2. Try to use the merge method on drafts.

$drafts     = site()->children()->filterBy('intendedtemplate', 'programme')->drafts();
$programmes = $drafts->merge($sortedProgrammesPanel);

Let’s clean this up first. All these lines can be replaced with:

$sortedChildren = site()->children()->listed()->filterBy('intendedTemplate', 'programme')->sortBy( function( $item ) {
      if ( $item->hasChildren () ) {
        return $item->children()->last()->publicationDate()->toDate();
      return $item->publicationDate()->toDate();
}, 'desc');

Thank you both,

@ahmetbora As far as I understood you, this is not a collection but a page method that I pass to sortBy: on site blueprint to sort the programmes in a particular order.

@texnixe Danke.

The following works well.


Kirby::plugin('plagasul/page-methods', [
	'pageMethods' => [
		'sortedProgrammesPanel' => function () {
			$drafts = site()->drafts()->filterBy('intendedtemplate', 'programme');
			$sortedProgrammesPanel = site()->children()->listed()->filterBy('intendedTemplate', 'programme')->sortBy( function( $item ) {
				if ( $item->hasChildren () ) {
					return $item->children()->last()->publicationDate()->toDate();
					return $item->publicationDate()->toDate();
			, 'desc');
			return $drafts->merge($sortedProgrammesPanel)->indexOf($this);

Merging listed programmes into the drafts, as suggested by @ahmetbora effectively prepends listed programmes to drafts so we get: Drafts, Listed programmes. Merging drafts into listed programmes, prepends drafts, so we get: Listed programmes, Drafts.

So that is the way to control prepending or appending a collection into another.