Hello,
I am finishing an archive website. The media has been made available site-wide so that editors can upload all files in one place and tag them (location, theme etc), and then after use it in pages. To link a piece of media to a page, they create a new block and select the file.
Now as a last thing, i need to make a page where users can filter media by tags WHILE being able to see what pages this media is used in.
I looked around the var_dump for blocks, but it seems that there aren’t many points to grab there? I also didn’t see the information i need. It is actually quite challenging, because i cannot seem to get a url from the block. I also get the sense that i have to scrub both the files AND the pages separately AND THEN do some sort of comparison?
Am i way off, or is there something built into kirby to make this easier?
My prototype code is below, just a general structure of the way i’m thinking about this…
<?php foreach ($site->files() as $file) :
foreach ($file->tags()->split() as $tagcheck) :
if ($tagcheck === $currenttag) :
//add $file->url() to array x;
endif;
endforeach;
endforeach ?>
<?php foreach ($page->children() as $card) :
foreach ($card->media()->toBlocks() as $mediablock) :
//add $mediablock-url() and $mediablock->parentpagetitle to array i
endforeach;
//return array for each page
endforeach ?>
if array x[a] === array[i]{
return file + title
}
<div>
<img src="<?= $file->url() ?>" alt="<?= $file->title() ?>">
As seen on <?= $file->parentpagetitle() ?>
</div>
I guess with the first part, you want to filter your files by tag. Then can be achieved a lot easier.
<?php
$files = $site->files();
$tag = param('tag'); // or `get('tag')` if you use query syntax
if ($tag) {
$files = $files->filterBy('tags', $tag, ',');
}
// Then loop through the files and get information about the file
foreach ($files as $file) {
// whatever else you want to do here
// get information about pages in which file is used
$usedIn = $file->getUsageInformation('text'); // pass the fieldname of the blocks field here
foreach ($usedIn as $p {
// link to page with $page->url();
}
}
With this general structure in place, we create a file method call getUsageInformation() in a plugin.
/site/plugins/file-methods/index.php:
<?php
use Kirby\Cms\App;
App::plugin('texnixe/file-methods', [
'fileMethods' => [
'getUsageInformation' => function (string $fieldName) {
$blocks = new Kirby\Cms\Blocks();
$pages = new Kirby\Cms\Pages();
$index = site()->index();
$fields = $index->pluck($fieldName);
foreach ($fields as $field) {
$blocksForFile = $field->toBlocks()->filter(fn ($block) => $block->type() === 'image' && $block->image()->toFile() === $this); // if you are not on PHP 8, you have to modify the code a bit
$blocks->add($blocksForFile);
}
foreach ($blocks as $block) {
$pages->add($block->parent());
}
return $pages;
}
]
]);
The code above assumes that you always use the same field name for the blocks field in all pages.
Although, I’m wondering why you use a blocks field to link media to a page? Unless that is within other blocks, of course.
@texnixe Thank you for the thoughtful reply. Much appreciated.
I am indeed using the same field for the blocks field in all pages (because all pages use the same blueprint), so your method is able to go through the pages but I think it also creates the problem where the function is unable to differentiate between pages where the respective block is?
I am currently getting back the titles of all pages with blocks, not the title of the pages where the block is contained.
Also in response to this
Although, I’m wondering why you use a blocks field to link media to a page? Unless that is within other blocks, of course.
I am using blocks to link media to a page, because the pages are made up of multiple media items that the editor can give a desired order to. I’m basically mostly using blocks as a page-building interface.
I tried adding individual clauses, but this one for example doesn’t work.
Sorry for so many questions, just finding hte block structure hard to navigate. I have tried almost all block methods and none work, your $block->image() for example is not even listed.
I implemented the function and it is working for 2/3 block types. However, i have an issue with one of them…
There are audio, images and videos. For videos, I am using vimeo to host the files so what i do is add screenshots of the video to the site-wide files, and under the file blueprint there is a toggle to ask: video? y/n and then add the URL
In the individual pages there is a block type video, so the editor selects this and chooses out of the site-wide files the screenshot for the corresponding video (which will say video=yes and insert the corresponding vimeo embed)
The question is then, how can i account for this in the getUsageInformation function?
Right that’s true, but isn’t it a problem that i am checking a url and not a file?
This is my video blueprint, i also tried $filefield = ‘image’
# Video block
name: Video
icon: video
preview: image
fields:
# Cover image
info:
type: info
headline: Video block
text: |
You can select or add the cover image for a video block
image:
label: Cover image
type: files
# Image upload options
uploads:
parent: site
template: media-file
# Query only cover images for select option
options: query
query: site.files.filterBy('template', 'media-file').filterBy('toggle', true)
Well, you are looping through files, so you have an image that belongs to a video. This file is referenced in a video block type and the field in the block is called image.
Sadly doesn’t work and doesn’t throw any errors. What do you recommend for step debugging? I don’t know what else to do, i am mostly a javascript developer.