Anyone know if it’s possible to use custom filter logic for page sections (using the table layout)?
Usecase: We’re using Kirby as a headless CMS and have created a custom preview story (since we couldn’t find a workable preview story out-of-the-box). Part of this involves us programmatically saving a draft file to disk for published content (which our frontend reads from). These draft files are put into a folder with a specific prefix (e.g. draft-for-custom-preview/blog-entry-1.txt). We delete these when changes are saved or reverted but when they exist on disk (in-between previewing and saving/reverting) the problem is that they’re showing up in the section page’s listing (which of course we don’t want). So that’s the issue we’re trying to solve…
Another approach would be to store all of these custom preview drafts in a different directory all together. This might be a cleaner on the Kirby end, but then querying for them becomes more complicated (if even possible).
Another approach is to use a custom status, if only this was possible (this isn’t possible, is it?). (update: seems this indeed is not possible (Custom page status · Kirby Feedback))
To query pages you would need a custom section (like the pagesdisplay section plugin, but that is limited to displaying and you cannot add pages. Having said that, you could adapt it)
But if these preview pages have a different file name, filtering by template should do the job?
Thanks for your insight, texnixe. I misspoke when saying that the custom drafts are named with a different filename… the filename is the same (e.g. blog-entry.txt) but the parent folder is different (e.g. internal-preview-my-post-1/).
I’m thinking the best approach here is to save the custom drafts in their own top-level directory. I’m working on the PHP for this now but so far it’s proving challenging.
Here’s the existing code that creates/updates the custom draft within the existing parent:
// Creates a preview version of the file with the in-memory data (i.e. the data that's yet to be saved) for use
// in our Lambda function that builds a Netlify preview.
'pattern' => 'save-custom-draft',
'method' => 'POST',
'action' => function () use ($kirby) {
$pageId = $this->requestBody('pageId');
$slug = $this->requestBody('slug');
$data = $this->requestBody('data');
// Create the name, using our naming structure of `internal-preview-[slug]`
$tempName = 'internal-preview-' . $slug;
// This handles the draft ID needing to include any possible parent directories in the path so that
// it works for both top-level pages and nested ("child") pages.
$draftId = str_replace($slug, $tempName, $pageId);
$maybeExistingDraft = $kirby->page($draftId);
// Effectively get a copy of our custom draft file to update.
// If the custom draft already exists, this simply copies it.
// Otherwise, it duplicates the content file (which is either the published file or the initial draft
// file (when creating a new page in the UI, Kirby automatically makes it a draft, but keep in mind that
// this draft is different than our custom draft files, which we only use for previews).
$tempCopy = $maybeExistingDraft ? $maybeExistingDraft : $this->page($pageId)->duplicate($tempName);
// Update the duplicated file with our in-memory data
$tempCopy->update($data, $this->language(), false);
return new Response(['code' => 204]);
},
A working approach for storing the custom previews in their own top-level directory:
[
// Creates a preview version of the file with the in-memory data (i.e. the data that's yet to be saved) for use
// in our Lambda function that builds a Netlify preview.
'pattern' => 'save-custom-draft',
'method' => 'POST',
'action' => function () use ($kirby) {
try {
$pageId = $this->requestBody('pageId');
$slug = $this->requestBody('slug');
$data = $this->requestBody('data');
$draftId = '/previews/' . $pageId;
$maybeExistingDraft = $kirby->page($draftId);
$existingPage = $kirby->page($pageId);
function copyP($s1, $s2)
{
$path = pathinfo($s2);
if (!file_exists($path['dirname'])) {
mkdir($path['dirname'], 0755, true);
}
copy($s1, $s2);
}
// Effectively get a copy of our custom draft file to update.
// If the custom draft already exists, this simply copies it.
// Otherwise, it duplicates the content file (which is either the published file or the initial draft
// file (when creating a new page in the UI, Kirby automatically makes it a draft, but keep in mind that
// this draft is different than our custom draft files, which we only use for previews).
if (isset($maybeExistingDraft)) {
$tempCopy = $maybeExistingDraft;
} else {
// Note: instead of the below, it should be possible to do something like:
// ```
// $this->page($pageId)->clone([
// 'slug' => $draftId,
// 'root' => $kirby->site()->contentFileDirectory() . $draftId,
// 'dirname' => $slug,
// ]);
// ```
// This appears to work, but it results in some of the requests (via KQL)
// breaking. Seems something's not getting copied over right... the following
// is one thing I've found that breaks the request (in the KQL object):
// ```
// "author": {
// "query": "page.author.toPage()",
// "select": {
// "title": true,
// "slug": true
// }
// }
// ```
$contentFile = $this->page($pageId)->contentFile();
$customPreviewsDirRoot = $kirby->site()->contentFileDirectory();
$customDraftFile =
$customPreviewsDirRoot .
$draftId .
'/' .
$this->page($pageId)
->intendedTemplate()
->name() .
'.txt';
copyP($contentFile, $customDraftFile);
$tempCopy = $kirby->page($draftId);
}
if (isset($tempCopy)) {
// Update the duplicated file with our in-memory data
$tempCopy->update($data, $this->language(), false);
}
return new Response(['code' => 204]);
} catch (\Throwable $th) {
return new Response(['code' => 500]);
}
}
]
It’d be good to know why the clone approach breaks some KQL requests (since the alternative approach I’ve found to work is much more verbose).