Programatically add file/image to page/field

I am creating pages from CSV files. I also have a folder with images that are referenced by filename in the CSVs. Both under ‘/assets/’

So looping the CSV I can get the file with something like this in a loop:

asset('assets/mediaimport/'.$mainImage)

Now I’d like to bring one or several of those into the page on creation time, or aftewards with update. Specifically into two files fields, one multiple, one single.

Can I get an example or a page from the docs etc, please?

Thank you

You cannot link a file in the assets folder to a files field, for that you would need a file object. A file object, however, is tied to a page. So you could either put those files into the site or a specific mediafolder page, or create a page folder for the virtual page where those files could live (like in this example: Merging content sources | Kirby CMS).

Thanks @texnixe

Sorry, my question was actually about ‘uploading’ the file to the page folder programatically and then use it in the files field.

I found the “Uploading files from frontend” cookbook, and was trying to adapt part of the code, something like this:

    $img = asset('assets/mediaimport/'.$mainImage);
    try {               
        $file = page('myPage')->createFile([
            'source'   => $img,
            'filename' => $img->filename(),
        ]);

        page('myPage')->update([
            'filesfield' => Data::encode([$img->filename()], 'yaml')
        ])

    } catch (Exception $e) {
        $e->getMessage();
    }

Should this work? edit: it does not :slight_smile:

Can it be adapted to run on page creation? This is not critical, tho.

Thank you

Sorry for the misunderstanding, I thought you were using virtual pages, not actually creating them from a csv file.

As source, you need the path to the file instead of an asset object:

$img = 'assets/mediaimport/' . $mainImage;

//...
 $file = page('myPage')->createFile([
            'source'   => $img,
            'filename' => $mainImage,
        ]);

Thank you,

Hmm… but then , when I update the files field, should I also use merely the filename? so $mainImage?

Thanks

Oh, yes, sorry, left that part out.

Thanks again,

I can’t make it work. I must be doing something wrong. Maybe related to this being a multilang website?

This is the code I am using:

$p = page('fairs')->findPageOrDraft(str::slug($title . formatDate($f['Date Start'], 'd/m/Y', 'Y')));
echo $p->slug() . 'exists' . '<br />';
$img = 'assets/mediaimport/'.$mainImage;
try {               
    $file = $p->createFile([
        'source'   => $img,
        'filename' => $mainImage,
    ]);

    $p->update([
        'cover' => Data::encode([$mainImage], 'yaml')
    ]);

} catch (Exception $e) {
    $e->getMessage();
}

Do you get an error? You are authenticating, aren’t you ($kirby->impersonate())?

I don’t seem to get an error.

Yes, I am impersonating as kirby. Here is more complete code (not all of it)

// Fairs
foreach ($fairs as $f) {
    $title = $f['Title'];
    $artists = $f['Artists'];
    $otherArtists = $f['Other Artists'];
    $mainImage = $f['Main Image'];
    $location = $f['Location'];
    $dateStart = formatDate($f['Date Start']);
    $dateEnd = formatDate($f['Date End']);
    $installationViews = $f['Installation views'];
    $logo = $f['Logo'];
    
    if (!page('fairs')->findPageOrDraft(str::slug($title . formatDate($f['Date Start'], 'd/m/Y', 'Y')))) {
   
        page('fairs')->createChild([
            'slug' => str::slug($title . formatDate($f['Date Start'], 'd/m/Y', 'Y')),
            'template' => 'fair',
            'content' => [
                'title' => $title,
                'artists' => parseArtists($artists, $otherArtists),
                'venue' => $location,
                'startdate' => $dateStart,
                'enddate' => $dateEnd
            ]                    
        ]);

    } else {
        $p = page('fairs')->findPageOrDraft(str::slug($title . formatDate($f['Date Start'], 'd/m/Y', 'Y')));
        echo $p->slug() . ' already exists' . '<br />';
        $img = 'assets/mediaimport/'.$mainImage;
        try {               
            $file = $p->createFile([
                'source'   => $img,
                'filename' => $mainImage,
            ]);
   
            $p->update([
                'cover' => Data::encode([$mainImage], 'yaml')
            ]);

        } catch (Exception $e) {
            $e->getMessage();
        }
    }
    
}

…is $img a correct accessible path here ?

This code works for me. For the test, I put the file attention-sharks.jpg into assets/images (testing this in the about.php template in a starterkit):

<?php
$kirby->impersonate('kirby');
$path = 'assets/images/attention-sharks.jpg';
try {
    $file = $page->createFile([
        'source'   => $path,
        'filename' => 'attention-sharks.jpg',
        'template' => 'image',
    ]);

    $page->update([
        'cover' => Data::encode([$file->filename()], 'yaml')
    ]);

} catch (Exception $e) {
    $e->getMessage();
}

Yes, ok

I AM getting an exception, I dumped $e, this:

Kirby\Exception\LogicException Object
(
    [data:protected] => Array
        (
        )

    [httpCode:protected] => 400
    [details:protected] => Array
        (
        )

    [isTranslated:protected] => 
    [message:protected] => The file could not be created
    [string:Exception:private] => 
    [code:protected] => error.logic
    [file:protected] => /home/jaume/public_html/dev/nb/kirby/src/Cms/FileActions.php
    [line:protected] => 201
    [trace:Exception:private] => Array
        (
            [0] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/FileActions.php
                    [line] => 121
                    [function] => Kirby\Cms\{closure}
                    [class] => Kirby\Cms\File
                    [type] => ::
                )

            [1] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/FileActions.php
                    [line] => 219
                    [function] => commit
                    [class] => Kirby\Cms\File
                    [type] => ->
                )

            [2] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/HasFiles.php
                    [line] => 67
                    [function] => create
                    [class] => Kirby\Cms\File
                    [type] => ::
                )

            [3] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/site/templates/default.php
                    [line] => 186
                    [function] => createFile
                    [class] => Kirby\Cms\Page
                    [type] => ->
                )

            [4] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Filesystem/F.php
                    [line] => 410
                    [args] => Array
                        (
                            [0] => /home/jaume/public_html/dev/nb/site/templates/default.php
                        )

                    [function] => include
                )

            [5] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Filesystem/F.php
                    [line] => 387
                    [function] => loadIsolated
                    [class] => Kirby\Filesystem\F
                    [type] => ::
                )

            [6] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Toolkit/Tpl.php
                    [line] => 36
                    [function] => load
                    [class] => Kirby\Filesystem\F
                    [type] => ::
                )

            [7] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/Template.php
                    [line] => 171
                    [function] => load
                    [class] => Kirby\Toolkit\Tpl
                    [type] => ::
                )

            [8] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/Page.php
                    [line] => 1061
                    [function] => render
                    [class] => Kirby\Cms\Template
                    [type] => ->
                )

            [9] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/App.php
                    [line] => 713
                    [function] => render
                    [class] => Kirby\Cms\Page
                    [type] => ->
                )

            [10] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/kirby/src/Cms/App.php
                    [line] => 1086
                    [function] => io
                    [class] => Kirby\Cms\App
                    [type] => ->
                )

            [11] => Array
                (
                    [file] => /home/jaume/public_html/dev/nb/index.php
                    [line] => 5
                    [function] => render
                    [class] => Kirby\Cms\App
                    [type] => ->
                )

        )

    [previous:Exception:private] => 
    [xdebug_message] => ( ! ) Kirby\Exception\LogicException: The file could not be created in /home/jaume/public_html/dev/nb/kirby/src/Cms/FileActions.php on line 201
Call Stack
#TimeMemoryFunctionLocation
10.0002363048{main}(  ).../index.php:0
20.0040777392Kirby\Cms\App->render(  ).../index.php:5
30.0083955744Kirby\Cms\App->io(  ).../App.php:1086
40.0084955904Kirby\Cms\Page->render(  ).../App.php:713
50.0090958920Kirby\Cms\Template->render(  ).../Page.php:1061
60.0091959016Kirby\Toolkit\Tpl::load(  ).../Template.php:171
70.0091975544Kirby\Filesystem\F::load(  ).../Tpl.php:36
80.0091975544Kirby\Filesystem\F::loadIsolated(  ).../F.php:387
90.00941003776include( '/home/jaume/public_html/dev/nb/site/templates/default.php' ).../F.php:410
100.01821359824Kirby\Cms\Page->createFile(  ).../default.php:186
110.01831434848Kirby\Cms\File::create(  ).../HasFiles.php:67
120.02151538280Kirby\Cms\File->commit(  ).../FileActions.php:219
130.02661581560Kirby\Cms\File::Kirby\Cms\{closure:/home/jaume/public_html/dev/nb/kirby/src/Cms/FileActions.php:194-219}(  ).../FileActions.php:121

)

…folders seem writable, permissions look good, pages were created using this method and file, and I can update them via the panel

The error is thrown when either the source does not exist or the target file already exists or if the file cannot be copied to the target location (probably due to permissions).

Are you familiar with xDebug? Then I would do a step debug to see where exactly it fails

Content folder and subfolders are -rw-rw-r-- and belong to www-data and/or have this as group, which is the usual in my setup.

The images are certainly not in the folders.

Could this be related to the fact that all this pages are still _drafts ? edit> no, does not seem so…

Thanks

Could you set a file template and create that with an accept function that allows certain file types.

Are the files particularly large?

Ok, it is solved. The path to files was not correct, small typo.

I am confused as the asset() function didn’t seem to have a problem with the provided path, which threw me off track.

Probably human error in any case.

Thank you again