---
title: Smart Grid | Advanced YOOtheme Pro Content Grid
description: Create smart content grids in YOOtheme Pro with favourites, ratings, filters, search, social feeds, Joomla articles and ZOO support.
url: https://www.yoozecase.com/smart-grid
---

# Smart Grid

We 've created a beast

**Latest Version**

**Release date**

15 May 2026

**Made for**

Joomla

**Price**

[Demo page](https://www.yoozecase.com/smart-grid-demo)

Ever wish your site could remember what each visitor loves? Smart Grid makes it happen. Every card it shows gets a heart and a 5-star rating - visitors save what they like with a tap, filter the page down to just their favourites in a click, and show you what's actually worth the time. Then fill those cards with anything: your Joomla articles, your ZOO items, hand-picked highlights, or live posts from eight social platforms. One drag-and-drop YOOtheme Pro element, one Joomla install, zero code - and easily the most epic grid you'll ever add to a page.

![Smart Grid](https://www.yoozecase.com/files/smart-grid.png)

---

## Description

**Give every card a heart and a rating and watch your site finally remember the people who visit.**

Start with the part nobody else gives you: a website that remembers people. Smart Grid puts a little heart on every card it displays. A visitor taps it to save that card - think of it like a bookmark or a wishlist - and from then on they can filter the whole page down to just the things they loved, in a single click. Add the built-in 5-star rating widget and they can score what they like too, the way you'd rate a film or a product online. Those ratings stick around, so you can finally see what your audience actually values - and if you use ZOO, the averages can write straight back into your content. No third-party service, no spreadsheet, no guesswork. Your site remembers, and your visitors feel seen.

So what goes on those cards? Whatever you want - and this is where jaws hit the floor. A YOOtheme Pro "element" is just a block you drag onto a page, Smart Grid is that block, except it can pull its cards from four completely different places. Hand-pick them one by one. Or point it at your Joomla articles and let it build the grid for you (it even notices a YouTube link inside an article and turns that card into a playable video). Or wire it into ZOO, the heavy-duty content app. Or - the showstopper - feed it live posts from eight social platforms at once: YouTube, Bluesky, Mastodon, Reddit, Vimeo, Spotify, SoundCloud and TikTok. You never touch a line of code. You pick a source from a dropdown and the cards appear.

From there it just keeps over-delivering. Twelve one-click layout presets mean it looks designed, not assembled. Cards flip to reveal more, spotlight tiers show off your best content, and media plays right on the card - with only one video or song ever playing at a time, so nothing talks over itself. Visitors filter by tag, search as they type, and page through smoothly. You can even earn from it: drop in Google ads, including native "in-feed" cards that blend into the grid instead of screaming "banner" - and a bonus RSS Feed element rides along in the same download for clean news feeds.

And it's built like grown-ups built it: it heals its own database tables, survives the cheapest shared hosting, shrugs off flaky APIs, and is properly security-hardened. It speaks six languages out of the box and installs from a single zip - no FTP, no cPanel, no phpMyAdmin. Drag it on, pick a source, pick a preset, and you're live before your coffee cools. You came for a grid. You're leaving with a site that remembers, rewards, and sells - quite possibly the most epic plugin you'll ever buy, and we say that with our whole chest.

---

#### Top voted

';
 }
 html += '

';
 if (oc.title) {
 html += '

##### ' + escapeHtml(oc.title) + '

';
 }
 if (oc.text) {
 html += '

' + escapeHtml(oc.text).replace(/\n/g, '
') + '

';
 }
 html += '

';
 }

 // Auto winner(s) - top N from the already vote-sorted features
 if (mode === 'auto_winner' || mode === 'both') {
 var n = oc.winnerCount | 0;
 if (n ';
 for (var i = 0; i ' +
 (w.image_url ? '

![](https://www.yoozecase.com/' + escapeHtml(w.image_url) + ')

' : '') +
 '' + (i + 1) + '' +
 '' + escapeHtml(w.title) + '' +
 '' + getIcon(this.cfg.voteIcon) + ' ' + (w.votes | 0) + '' +
 '';
 }
 html += '';
 }
 }

 if (html === '') {
 this.elOutcome.hidden = true;
 return;
 }
 this.elOutcome.innerHTML = html;
 this.elOutcome.hidden = false;
 };

 /**
 * Roadmap view (v3.2.0): renders the items as status columns, in the
 * canonical status order from cfg.statuses. Each column is an  inside
 * the existing .yc-fb-list ';
 }
 return html;
 };

 Board.prototype.renderItem = function (f, index) {
 var disabled = this.cfg.isClosed ? 'disabled' : '';
 var voted = f.voted ? ' yc-voted' : '';
 var descHtml = f.description
 ? '

' + escapeHtml(f.description).replace(/\n/g, '
') + '

'
 : '';
 var thumbHtml = f.image_url
 ? '

![](https://www.yoozecase.com/' + escapeHtml(f.image_url) + ')

'
 : '';

 // Status workflow (v3.0.0): badge for any non-default status. The
 // roadmap view (v3.2.0) skips the badge - the column already
 // communicates the status, a badge would be redundant noise.
 var st = (f.status || 'open');
 var labels = this.cfg.statusLabels || {};
 var statusBadge = (!this.isRoadmap && st && st !== 'open' && labels[st])
 ? '' + escapeHtml(labels[st]) + ''
 : '';

 // Design themes (v3.1.0): arena / neon / pixel render extra per-item
 // furniture - rank number, avatar (image or initials), a "leader" pill
 // on rank 1, and a "votes" label. Classic/colour themes are untouched.
 var t = this.cfg.theme || 'light';
 var themed = (t === 'arena' || t === 'neon' || t === 'pixel');
 var rank = (typeof index === 'number') ? (index + 1) : 0;
 var rankHtml = '', leaderHtml = '', avatarHtml = '', votesLabel = '';
 if (themed) {
 rankHtml = '' + pad2(rank) + '';
 if (rank === 1) {
 leaderHtml = '' + escapeHtml(this.cfg.leaderLabel || 'Leader') + '';
 }
 if (f.image_url) {
 avatarHtml = '

![](https://www.yoozecase.com/' + escapeHtml(f.image_url) + ')

';
 } else {
 avatarHtml = '

' + escapeHtml(initialsOf(f.title)) + '

';
 }
 votesLabel = '' + escapeHtml(this.cfg.votesLabel || 'votes') + '';
 }

 // Moderation overlay: subtle corner buttons, only when canModerate.
 // Buttons appear on hover/focus (styled in CSS). Even in customizer
 // preview we render them when canModerate is true so the moderator
 // can see what visitors with moderation rights will see.
 var modHtml = '';
 if (this.cfg.canModerate) {
 var parts = [];
 var hideTitle = escapeHtml(this.t('hideTitle', 'Hide this feature'));
 var deleteTitle = escapeHtml(this.t('deleteTitle', 'Delete this feature'));
 if (this.cfg.allowSoftHide) {
 parts.push(
 ''
 );
 }
 if (this.cfg.allowHardDelete) {
 parts.push(
 ''
 );
 }
 if (parts.length || (this.cfg.statuses && this.cfg.statuses.length)) {
 var sParts = parts.slice();
 if (this.cfg.statuses && this.cfg.statuses.length) {
 var opts = '';
 for (var si = 0; si ' + escapeHtml(sl) + '';
 }
 var setStatus = escapeHtml(this.t('setStatus', 'Set status'));
 sParts.push(
 ''
 );
 }
 modHtml = '';
 }
 }

 var mediaHtml = themed ? avatarHtml : thumbHtml;
 return (
 '' +
 leaderHtml +
 rankHtml +
 '' +
 mediaHtml +
 '

' +
 '

##### ' + escapeHtml(f.title) + '

' +
 statusBadge +
 descHtml +
 '

' +
 modHtml +
 ''
 );
 };

 /**
 * Detects whether a JSON response looks like a CSRF/token rejection.
 * Two cases:
 * 1. com_ajax-level rejection (Joomla's auto-token-check on POST): top
 * level message contains the JINVALID_TOKEN_NOTICE text and HTTP
 * status is typically 403.
 * 2. Plugin-level rejection from requireToken(): payload.error === "Invalid token".
 */
 Board.prototype.isTokenError = function (status, raw, payload) {
 if (status === 403) return true;
 var hay = '';
 try { hay = JSON.stringify(raw || {}) + '|' + JSON.stringify(payload || {}); } catch (e) {}
 return /invalid (security )?token/i.test(hay);
 };

 /**
 * Fetch a fresh CSRF token from the server. Updates this.cfg.csrfToken so
 * the next call (and any future calls in this Board's lifetime) use the
 * correct one. Cache-bust with a timestamp so no upstream CDN caches the
 * response.
 */
 Board.prototype.fetchFreshToken = function () {
 var self = this;
 var url = this.cfg.ajaxUrl + '&task=token&_=' + Date.now();
 return fetch(url, {
 method: 'GET',
 credentials: 'same-origin',
 headers: { 'Accept': 'application/json', 'Cache-Control': 'no-cache' }
 })
 .then(function (r) { return r.json(); })
 .then(function (data) {
 var p = self.unwrapAjax(data);
 if (p && p.ok === true && typeof p.token === 'string' && p.token.length >= 16) {
 self.cfg.csrfToken = p.token;
 return p.token;
 }
 throw new Error('No fresh token in response');
 });
 };

 /**
 * Generic POST-with-token helper. Builds FormData from a plain object,
 * adds the current token, posts. On 403 / token-error response, fetches a
 * fresh token and retries exactly once.
 *
 * @param {string} task The task name (appended to URL and body)
 * @param {object} fields Key-value form fields (no token)
 * @return {Promise

## Changelog

---

v3.20.0
 Breaking 16/07/2026

Changed

- ZOO button labels, "only these link elements" mode: the picker rows are now the buttons, in row order (row 1 = first/left, row 2 = second/right, row 3 = full-width below), each with its own label and "open in new window". The same link on two rows makes two buttons; the Show primary/second toggles no longer hide listed rows. Auto mode (toggle off) is unchanged.

v3.19.0
 Breaking 16/07/2026

Added

- ZOO buttons: an opt-in "only these link elements" mode (render buttons only for the link elements you pick, in that order) and a per-link "open in new window" option. Off by default, so existing grids are unchanged.

v3.18.3
 Breaking 16/07/2026

Changed

- Restored 5px top/bottom padding on buttons and eased wrapped-label line spacing to 1.35.

v3.18.2
 Breaking 16/07/2026

Changed

- Tightened the line spacing between wrapped button-label lines.

v3.18.1
 Breaking 16/07/2026

Changed

- Buttons sharing a row are now equal height, with the shorter label vertically centred.

v3.18.0
 Breaking 16/07/2026

Added

- ZOOlanders Link Pro support: each link in a (repeatable) Link Pro element becomes its own button.

v3.17.6
 Breaking 16/07/2026

Fixed

- Placeholder ZOO link values ("http://#") no longer render as dead buttons; feed detection now also matches feed hosts (rss.*, feeds.*, feedburner).

v3.17.5
 Breaking 16/07/2026

Changed

- Diagnostic build: added ?sgdebug=1 dumps of ZOO link elements and resolved buttons (no behaviour change).

v3.17.4
 Breaking 16/07/2026

Fixed

- Applied the ZOO link double-escape fix to multi-button URLs too (v3.17.3 covered only the item URL / clickable title).

v3.17.3
 Breaking 16/07/2026

Fixed

- ZOO item links rendered double-escaped: the DOM href literally contained
- New `_pdRawUrl()` helper additionally normalises ZOO link-element values
