Skip to content
● Critical PHP security fixes are out: update PHP on your Grav sites. What to do →

Render thumbnail in Flex object list view

field

Started by gravinator 2 months ago · 5 replies · 618 views
2 months ago

I'm creating a blog based on the flex objects with the following fields:

YAML
 admin:
    menu:
      list:                
        title: News
        icon: fa-newspaper-o
    list:
      fields:
        published:
          field:
            type: toggle
            label: Active
          width: 5
        news_title:
          field:
            label: Name
          link: edit
        news_date:
          field:
            label: Date
            type: datetime
        news_image:
          field:
            type: field
            label: Photo

All the columns renders except the photo - which shows [object Object].

Is there any way to render object as image (preferable thumbnail)?

last edited 09/04/26 by gravinator
2 months ago

Field is file (I tried thumbnail in as seen in some examples)

1 month ago

I'd also like to know how to display images in the Flex Objects list view within the Admin2 plugin.

According to the official docs, we can build a custom admin page, but building and maintaining full-featured UI components from scratch is quite difficult.

https://learn.getgrav.org/20/api/developer-guide#custom-admin-pages

If there's a way to configure image previews in the standard Admin2 list view via blueprints, I'd really appreciate it if someone could share how to do it.

3 weeks ago

Hello!
I created a thumbnail list on a custom admin page. You can navigate to it from the sidebar and view a list of thumbnails. Clicking a thumbnail takes you to the editing page for that object.
Since it's not a full-featured UI (no search, sorting, or pagination), you'll need to configure it using the options in the fetch method.

PHP
use RocketTheme\Toolbox\Event\Event;
(...)
    public function onApiSidebarItems(Event $event): void
    {
        $items = $event['items'] ?? [];
        $items[] = [
            'id'       => 'news',
            'plugin'   => 'news',
            'label'    => 'My Custom Thumbnail List',
            'icon'     => 'fa-newspaper-o',
            'route'    => '/plugin/news',
        ];
        $event['items'] = $items;
    }
    public function onApiPluginPageInfo(Event $event): void
    {
        if ($event['plugin'] !== 'news') {
            return;
        }

        $event['definition'] = [
            'id'        => 'news',
            'plugin'    => 'news',
            'title'     => 'My Custom Thumbnail List',
            'icon'      => 'fa-newspaper-o',
            'page_type' => 'component',
        ];
    }
JS
// user/plugins/news/admin-next/pages/news.js
const TAG = window.__GRAV_PAGE_TAG
customElements.define(TAG, class extends HTMLElement {
    async connectedCallback() {
        const root = this.attachShadow({ mode: 'open' });
        root.innerHTML = '<div>Loading...</div>'

        try {
            const baseUrl = window.__GRAV_API_SERVER_URL || '';
            const prefix = window.__GRAV_API_PREFIX || '';
            const token = window.__GRAV_API_TOKEN || '';
            const type = 'news';

            const endpoint = `${baseUrl}${prefix}/flex-objects/${type}`;

            const response = await fetch(endpoint, {
                method: 'GET',
                headers: {
                  'Accept': 'application/json',
                  'X-API-Token': token,
                }
            });

            if (!response.ok) {
                throw new Error(`API error: ${response.status} ${response.statusText}`);
            }

            const res = await response.json();
            const items = res.data || [];

            root.innerHTML = '<div id="grid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(120px, 1fr));"></div>'
            const gridEl = root.querySelector("#grid");
            items.forEach(item => {
                const newsImage = item.news_image;
                if (!newsImage || typeof newsImage !== 'object') {
                    return;
                }
                const images = Object.values(newsImage)
                if (images.length === 0) {
                    return;
                }
                const imagePath = `${baseUrl}/user/data/${type}/${item.key}/${images[0].path}`;
                const a = document.createElement('a');
                const editUrl = `${baseUrl}${window.__GRAV_ADMIN_BASE}/flex-objects/${type}/${item.key}`;
                a.href = editUrl;
                a.addEventListener('click', e => {
                    e.preventDefault();
                    window.__GRAV_NAVIGATE(editUrl);
                });
                const img = document.createElement('img');
                img.src = imagePath;
                img.style.width = '120px';
                img.style.height = 'auto';
                a.appendChild(img);
                gridEl.appendChild(a);
            });

        } catch (error) {
            window.__GRAV_TOAST.error('Failed to load news list');
        }
    }
});
2 weeks ago

news_image is most likely stored as an object/array, which is why the Flex list is displaying [object Object] instead of the actual image.

The standard Flex object list does not automatically render image/file objects as thumbnails just from the blueprint configuration. A good workaround is to store or expose only the image path/filename in the list, or create a small custom Admin template/component that reads the image URL and renders it with an <img> tag.

For example, if news_image contains the uploaded image path, the custom list output could render something like:

TWIG
<img src="{{ image_url }}" style="width:60px;height:60px;object-fit:cover;">

If you want to keep everything inside the standard Flex list, you could also try using a filepicker field so the stored value is simpler, but for an actual thumbnail preview, a custom renderer/template is usually the better solution.

So the issue is not with the image itself — it is because the list is trying to print the whole object as text. You need to extract the image URL/path and render that value as an image.

last edited 10/05/26 by bde

Suggested topics

Topic Participants Replies Views Activity
Support · by webmasterodp, 2 weeks ago
4 211 2 weeks ago
Support · by nwhitfield, 2 weeks ago
2 187 2 weeks ago
Support · by stell, 3 weeks ago
5 432 2 weeks ago
Support · by Gravver, 4 weeks ago
6 408 4 weeks ago
Support · by Marcel, 1 month ago
2 451 4 weeks ago