Stop Hand-Picking Related Content: Let Sulu's Smart Content Do It
Sulu's Smart Content replaces hand-picked page lists with rule-driven selections — data source, filters, sorting, limit — that stay fresh automatically as new matching pages are published.
18 Aug 2026, 00:38 UTC

The editorial chore nobody wants
Every content-heavy site has the same recurring task: someone has to keep "related articles", "latest news", or "featured case studies" sections up to date. Hand-picked lists go stale the moment a new page is published, and editors end up re-editing landing pages just to swap out old links.
Sulu, the Symfony-based CMS, ships with a content type built exactly for this: Smart Content. Instead of editors selecting individual pages, they define rules — a data source, filters, sorting, and a limit — and Sulu resolves the matching pages automatically at render time. Publish a new page that matches the rules, and it shows up in the list without anyone touching the landing page again.
How Smart Content actually works
In Sulu, pages are defined by XML templates, and each template's properties determine the fields editors see in the admin. Smart Content is one of those property types. When an editor configures a Smart Content block, they pick:
- Data source — where to look, typically a parent page whose children are candidates.
- Filters — tags, categories, or page types that narrow the candidate set.
- Sorting — for example, newest first by publication date.
- Limit — the maximum number of items to resolve.
There is also a "present as" option: a dropdown of rendering variants (say, one-column vs. two-column) whose selected value is passed to your Twig template, so editors control layout without touching code.
The key behavioral point: the query resolves when the page renders, and the result is cached along with the page output. You get dynamic content without a database query on every request.
Worked example: a "related articles" block
Assume a Sulu 2.x project (check with composer show sulu/sulu — property names and view-data structure differ between major versions). First, declare the property in your page template XML:
<property name="related" type="smart_content">
<meta>
<title lang="en">Related articles</title>
</meta>
<params>
<param name="provider" value="pages"/>
<param name="types" value="article"/>
<param name="present_as"
type="collection"
value="one,two"/>
<param name="limit" value="6"/>
</params>
</property>Then render the resolved pages in Twig. The Smart Content view data is exposed on the content property; exact keys depend on your version, so dump the variable once ({{ dump(view.related) }}) to confirm the structure before writing the loop:
{% if view.related.pages is defined and view.related.pages|length %}
<section class="related related--{{ view.related.presentAs }}">
{% for page in view.related.pages %}
<article>
<a href="{{ sulu_content_path(page.url) }}">
{{ page.title }}
</a>
<p>{{ page.excerptTitle|default('') }}</p>
</article>
{% endfor %}
</section>
{% endif %}Editors then open the page in the admin, choose the data source (e.g., the "/articles" parent page), optionally restrict by tag or category, pick a presentation variant, and set the limit. From then on, the block maintains itself.
Trade-offs and limits
Smart Content is deliberately not a general-purpose query builder. It resolves pages (and, in some setups, other registered providers) — if you need to join across custom entities or apply business-logic filtering, you will still write a custom controller or repository query instead.
Two practical cautions:
- Always set a limit. A broad data source with no cap can resolve dozens of pages, making both rendering and the admin preview unwieldy.
- Version drift is real. Property parameters, filter options, and Twig view-data keys changed between Sulu 1.x and 2.x. Treat any example XML (including this one) as a starting point and confirm against your installed version's documentation.
Verify it before you ship it
A quick local check takes minutes. Create a template with the smart_content property, publish a few article pages under your chosen data source, and confirm they render in the Twig output. Then publish one more matching article and clear the cache (bin/websiteconsole cache:clear in the website context, or your project's equivalent) to confirm the new page appears. If it shows up, your filters, sorting, and template loop are all wired correctly.
The actionable takeaway: anywhere your editors are manually curating lists of pages that share a parent, tag, or type, replace that picker with Smart Content. You trade a small amount of upfront template work for sections that never go stale — and one less recurring chore on the editorial calendar.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.