1

I'm trying to output the video files from within a block but get a Calling unknown method: craft\elements\db\AssetQuery::url() error when using the following:

{{ block.video.videoFileWebm.url }}

Assets in this volume have public URLs so I'm not sure why this isn't working.

FULL CODE

{% if block.video %}

                <video {% if block.video.videoAutoplay %}autoplay{% endif %} {% if block.video.videoLoop %}loop{% endif %} 
                                                    
                    {% if block.video.videoThumbnail %}
                    {% set optimizedImages = block.video.videoThumbnail.one().imageVariants16by9 %}
                    poster="{{ optimizedImages.srcset() }}"
                    {% endif %} muted>

                    {% if block.video.videoFileWebm %}
                        <source src="{{ block.video.videoFileWebm.url }}" type="video/webm">
                    {% endif %}
                    {% if block.video.videoFileOgg %}
                        <source src="{{ block.video.videoFileOgg.url }}" type="video/ogg">
                    {% endif %}
                    {% if block.video.videoFileMp4 %}
                        <source src="{{ block.video.videoFileMp4.url }}" type="video/mp4">
                    {% endif %}
                    
                    <p>This browser does not support the video element.</p>
                </video>

            {% endif %}
  • 1
    Just to clarify, is "video" a block type in a matrix, or is it a matrix field in an entry? I'm confused because you're doing block.video when it looks like you mean entry.videoBlocks, more specifically entry.videoBlocks.one()? – James Smith Sep 28 at 13:00
  • ...Or is "video" an entries select field in a matrix block? Either way you need to add some eager loading. Check your deprecation errors in Utilities and you'll see what needs fixing. – James Smith Sep 28 at 15:30
3

Asset fields return like an array so they can potentially have more than one item, you need to request the first item only with .one() (as opposed to requesting .all())

//First check if the asset field has more than zero items
{% if block.video.videoFileWebm|length %}
    // Retrieve the first and only item in the asset field
    <source src="{{ block.video.videoFileWebm.one().url }}" type="video/webm">
{% endif %}

I would also set block.video to a variable to clean up the code a bit and maybe speed it up a little.

| improve this answer | |
  • 1
    It's not really accurate to say that "asset fields presume that you may have more than one item", it's more the case that element queries need to be executed - whether that's .one() or .all() or .ids() or any of the other execution methods. – James Smith Sep 28 at 13:39
  • @JamesSmith you're right, that was badly written, updated! – dmatthams Sep 28 at 13:53
  • Sorry for splitting hairs, but still not quite right - Calling an asset field without one of the execution methods will not return an array - it'll return an element query object: that query then needs to be executed before you can access the result - which in this case would be an Asset object. – James Smith Sep 28 at 14:03
  • Hey, I'm happy with it – it's easy to understand for all levels, but feel free to edit if you want. – dmatthams Sep 28 at 14:23
0

You haven't executed your element queries. You'll need to call .one() on each related element, or, better, use eager loading to do the whole lot in one go:

I've assumed in the example below that 'video' is an entry select field type inside a matrix block type called 'video' inside a matrix field called 'matrixBlocks':

{% set matrixBlocks = entry.matrixBlocks.with([    
    'video:video.videoThumbnail',
    'video:video.videoFileWebm',
    'video:video.videoFileOgg',
    'video:video.videoFileMp4',
]).all() %}

{% for block in matrixBlocks %}
    {% if block.type == 'video' and block.video|length %}
        {% set videoEntry = block.video[0] %}
        <video {{ videoEntry.videoAutoplay ? 'autoplay' }} {{ videoEntry.videoLoop ? 'loop'}}
            {% if videoEntry.videoThumbnail %}
                {% set optimizedImages = videoEntry.videoThumbnail[0].imageVariants16by9 %}
                poster="{{ optimizedImages.srcset() }}"
            {% endif %} muted>

            {% if videoEntry.videoFileWebm %}
                <source src="{{ videoEntry.videoFileWebm[0].url }}" type="video/webm">
            {% endif %}
            {% if videoEntry.videoFileOgg %}
                <source src="{{ videoEntry.videoFileOgg[0].url }}" type="video/ogg">
            {% endif %}
            {% if videoEntry.videoFileMp4 %}
                <source src="{{ videoEntry.videoFileMp4[0].url }}" type="video/mp4">
            {% endif %}
            
            <p>This browser does not support the video element.</p>
        </video>
    {% endif %}
{% endfor %}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.