Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Contentful Item Template

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Our "item" template for skills is now being used! So, let's finish it!

We already know what we want the skills to look like... so let's go steal that from templates/main/homepage.html.twig. Find the featured_skills block, copy what one of those skills looks like, and paste that into skill.html.twig. Let's also add dump(item.object) at the top:

{{ dump(item.object) }}
<a href="#" class="text-center skill-item-container p-3">
<h3>Folding in Cheese</h3>
<div class="p-3 mt-3 skill-img">
<img src="{{ asset('images/pup-cup.png') }}" width="auto" height="80" alt="grater skill image">
</div>
</a>

We've created an item template before, so we know item.object should give us the underlying "object" that represents this Contentful entry.

If we head over and refresh... awesome! This dumps a ContentfulEntry object. And, though you can't see it from here, this class has a get() method we can use to read any of the underlying data from Contentful.

For skills, if we dig a little... we have fields like title and shortDescription. Let's use those! For example, in the <h3>, say {{ item.object.get('title') }}:

{{ dump(item.object) }}
<a href="#" class="text-center skill-item-container p-3">
<h3>{{ item.object.get('title') }}</h3>
... lines 4 - 6
</a>

And... yup! That worked!

For the <img src="">, replace the asset() stuff with item.object.get('image'), followed by .file.url, which is specific to Contentful. Also fill in the alt attribute with item.object.get('title'):

<a href="{{ path('cmf_routing_object', {'_route_object': item.object}) }}" class="text-center skill-item-container p-3">
<h3>{{ item.object.get('title') }}</h3>
<div class="p-3 mt-3 skill-img">
<img src="{{ item.object.get('image').file.url }}" width="auto" height="80" alt="{{ item.object.get('title')}} skill image">
</div>
</a>

The last thing we need to update is the URL. But, hmm. If we had created a "skill show" page in Symfony, we could use the Twig path() function to link to that route! However, each skill page is actually created via a dynamic route thanks to the Contentful bundle. And, to create those routes, it uses something called the CMF routing system.

So, to link, we need to use that system. Say path('cmf_routing_object') and pass _route_object set to item.object:

<a href="{{ path('cmf_routing_object', {'_route_object': item.object}) }}" class="text-center skill-item-container p-3">
... lines 2 - 5
</a>

If you were using Sylius or Ibexa CMS, you would use some function from their system to create the link: this is specific to the CMF routing system.

Head over and try that. Yes! And if we click the link... double yes!

Let's celebrate by removing the dump(). We can also delete this featured_skills block from our homepage template: We won't need that at all anymore. But let's remake this <h2> inside of the layouts admin first. To do that, add a Title block called "Featured Skills", make that "H2"... and give it those same CSS classes: text-center mb-4.

The Grid is already in a container... but we want all of this in a container. So add a Column, wrap that in a Container, move the Grid and Title blocks inside of it... then we won't need a Container on the Grid anymore. Delete the "Features Skills" block... then finally hit "Publish and continue editing". While we're waiting, delete that block also from the Twig template.

And now... yes! It looks perfect!

The Advertisement Item View

Okay, while we're talking about item views, let's customize the item template for our other content type inside of Contentful: Advertisement. We're only rendering that in one place, on the individual skill page... right over here. Let's go check that out.

Publish this layout... then edit the individual skill layout. Earlier, we used the Contentful Entry Field block to render the advertisement field, which is a "referenced entity". Yup, if you modify a skill in Contentful, down on the bottom, the "Advertisement" field allows you to choose from the Advertisements in our system.

Click on the Twig icon of the web debug toolbar... search for "item", and scroll down.. No surprise: it's using the standard Contentful "item" template. And, good news, we already know how to override that!

Head over to our configuration, copy the contentful_entry/skill section, and paste it below. Replace skill with ad for the section name and template... and update the content_type to advertisement... because that's the internal name of that type in Contentful:

netgen_layouts:
... lines 2 - 12
view:
item_view:
... lines 15 - 21
# default = frontend
default:
... lines 24 - 33
contentful_entry/ad:
template: '@nglayouts/item/contentful_entry/ad.html.twig'
match:
item\value_type: 'contentful_entry'
contentful\content_type: 'advertisement'
... lines 39 - 46

Ok! Let's go add that template. In contentful_entry, create a new file called ad.html.twig... and then just print some text: Advertisement:

Moment of truth. Head back over and refresh. We got it! That was easy!

For the real template contents, I'll just paste them in. Once again, we use item.object.get() to read the url field. There's also an image field and a shortText field:

<a href="{{ item.object.get('url') }}" class="p-3 text-center ad-item-container" target="_blank">
<h3>Sponsored Product</h3>
<img src="{{ item.object.get('image').file.url }}" width="auto" height="200" alt="Ad image">
<p class="pt-3">{{ item.object.get('shortText') }}</p>
</a>

And now... we've got it!

Next: What if we wanted to create a Grid of items... but make that one Grid look different than every other Grid on the site? We can do that by creating an extra "block view" for an existing block.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.0.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.13", // 2.13.3
        "easycorp/easyadmin-bundle": "^4.4", // v4.4.1
        "netgen/layouts-contentful": "^1.3", // 1.3.2
        "netgen/layouts-standard": "^1.3", // 1.3.1
        "pagerfanta/doctrine-orm-adapter": "^3.6",
        "sensio/framework-extra-bundle": "^6.2", // v6.2.8
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/console": "5.4.*", // v5.4.14
        "symfony/dotenv": "5.4.*", // v5.4.5
        "symfony/flex": "^1.17|^2", // v2.2.3
        "symfony/framework-bundle": "5.4.*", // v5.4.14
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "5.4.*", // v5.4.6
        "symfony/runtime": "5.4.*", // v5.4.11
        "symfony/security-bundle": "5.4.*", // v5.4.11
        "symfony/twig-bundle": "5.4.*", // v5.4.8
        "symfony/ux-live-component": "^2.x-dev", // 2.x-dev
        "symfony/ux-twig-component": "^2.x-dev", // 2.x-dev
        "symfony/validator": "5.4.*", // v5.4.14
        "symfony/webpack-encore-bundle": "^1.15", // v1.16.0
        "symfony/yaml": "5.4.*", // v5.4.14
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.3
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "5.4.*", // v5.4.11
        "symfony/maker-bundle": "^1.47", // v1.47.0
        "symfony/stopwatch": "5.4.*", // v5.4.13
        "symfony/web-profiler-bundle": "5.4.*", // v5.4.14
        "zenstruck/foundry": "^1.22" // v1.22.1
    }
}