Hi, I’m trying to sort some articles based on a select field (form) but it doesn’t work yet.
This is the controller:
<?php
return function($site, $pages, $page) {
// return all children if nothing is selected
$articles = $page->children()->listed()->flip();
// if there is a post request, sort the articles collection
if(r::is('POST') && $data = get()) {
$articles = page()->children()->listed()->sortBy(function ($data) {
return $data;
}, 'desc');
};
return compact( 'articles');
};
here’s the select field inside the template:
<section class="subnav">
<form id="filters" method="post">
<select name="sort" onchange="this.form.submit()">
<option selected value="">Sort by</option>
<option<?php e(isset($data['title']) && $data['title'] == $title, ' selected') ?> value="<?= $title ?>">
Title</option>
<option<?php e(isset($data['year']) && $data['year'] == $year, ' selected') ?> value="<?= $year ?>">
Year</option>
</select>
</form>
</section>
There are several issues with your form and controller:
Form:
<section class="subnav">
<form id="filters" method="post">
<select name="sort" onchange="this.form.submit()">
<option selected value="">Sort by</option>
<option<?php e( isset($sortField) && $sortField === 'title', ' selected') ?> value="title">
Title</option>
<option<?php e(isset($sortField )&& $sortField === 'year', ' selected') ?> value="year">
Year</option>
</select>
</form>
</section>
Controller:
return function($site, $pages, $page) {
$sortField = null;
// return all children if nothing is selected
$articles = $page->children()->listed()->flip();
// if there is a post request, sort the articles collection
if(R::is('POST') && get('sort')) {
$sortField = esc(get('sort'));
$articles = $articles->sortBy($sortField, 'desc');
};
return compact( 'articles', 'sortField');
};
If this is not self explanatory, don’t hesitate to ask for explanations. You might want to consider using a GET instead of a POST request to prevent the browser popup when a page with a post request is reloaded.
Additionally, you might want to make sure you only get one of two values:
$sortField = in_array(get('sort'), ['title', 'year']) ? get('sort') : null;
Thanks! It works so far. I’m slowly getting more familiar with it.
Is there a way to include ‘asc’ and ‘desc’ for each value into the same field?
You either need a second form field for the direction or you have to duplicate the options, i.e. title-desc, title-asc etc.
The Duplicate Version seems the best to me, but I’m not sure if I’m on the right track here:
options:
<option<?php e( isset($sortField) && $sortField === "'title','asc'", ' selected') ?> value="title-asc">
Title-asc</option>
controller:
<?php
return function($site, $pages, $page) {
$sortField = null;
// return all children if nothing is selected
$articles = $page->children()->listed()->flip();
// if there is a post request, sort the articles collection
if(R::is('GET') && get('sort')) {
$sortField = esc(get('sort'));
$articles = $articles->sortBy($sortField);
};
return compact( 'articles', 'sortField');
};
<section class="subnav">
<form id="filters" method="GET">
<select name="sort" onchange="this.form.submit()">
<option selected value="">Sort by</option>
<option<?php e(isset($sortString) && $sortString === 'title-asc', ' selected') ?> value="title-asc">Title asc</option>
<option<?php e(isset($sortString) && $sortString === 'title-desc', ' selected') ?> value="title-desc">Title desc</option>
<option<?php e(isset($sortString) && $sortString === 'year-asc', ' selected') ?> value="year-asc">Year asc</option>
<option<?php e(isset($sortString) && $sortString === 'year-desc', ' selected') ?> value="year-desc">Year desc</option>
</select>
</form>
</section>
<?php
use Kirby\Cms\R;
use Kirby\Toolkit\Str;
return function($site, $pages, $page) {
$sortField = null;
// return all children if nothing is selected
$articles = $page->children()->listed()->flip();
// if there is a post request, sort the articles collection
if(get('sort')) {
$sortString = get('sort');
$sortField = Str::split($sortString, '-')[0];
$direction = Str::split($sortString, '-')[1];
$sortField = in_array($sortField, ['title', 'year'] ) ? $sortField : null;
$direction = in_array($direction, ['desc', 'asc'] ) ? $direction : null;
$articles =$articles->sortBy($sortField, $direction);
};
return compact( 'articles', 'sortString');
};
Awesome! First, it gave me an error, so i added I added $sortString = null;
into the controller.
Thanks @texnixe !