Docs: Tracker
Tracker
The Template API calls for Feedback's Tracker — trackers(), trackerItems(), trackerItem(), trackerRoadmap(), trackerSimilar() and trackerForm() — with their shapes, errors and views.
Feedback's Tracker is where visitors suggest, vote on and follow ideas and fixes. Six calls give a theme its data, all new in Tilspire 1.18.0 and all escaped (E): echo them as they are. While Feedback or its tracker is off, each call answers error: 'module', [] or null; nothing throws on a public page. Examples use $esc, the shipped theme's escaper: static fn ($v): string => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8').
trackers() #
Returns the trackers this visitor may see, in the site's order, as a list of {key, name, description, url, closed, counts{open, planned, in_progress, done, closed}, suggest_state, suggest_notice}. Counts cover the items this visitor may see. suggest_state is open, or why suggesting is not offered: signin, verify, denied, closed, flood, or paused while the Feedback licence has lapsed (reading and voting go on). suggest_notice is the language key to print, null when open.
<?php foreach ($this->trackers() as $t): ?>
<a href="<?= $t['url'] ?>"><?= $t['name'] ?></a> (<?= (int) $t['counts']['open'] ?> open)
<?= $this->action('tracker.suggest', $t) ?>
<?php endforeach; ?>
trackerItems($query = []) #
Returns one page of a tracker's items as {items, total, page, pages, per_page, tracker, error}. Query keys:
tracker— its key; default the tracker this page's route shows.tab—topmost voted (the default),newnewest,roadmapplanned and in progress,donedone and declined.category,type,status— keys.statusreplaces the tab's buckets.q— words in the title.pageandper_page—per_pageis 1 to 50; the default is the site's setting.
An item is {tracker, number, ref, title, url, type{key,label}, status{key,label,bucket}, category{key,name}|null, votes, comments, author, created, updated, locked, voted, can_vote, vote_state, vote_notice}. The envelope's tracker is the trackers() entry plus tabs ({key, label, url, current}, label a language key), categories, types and statuses. error is null or one of module, tracker (an unknown tracker and one this visitor may not see are the same answer), category, type and status (likewise), query, option, or the option at fault.
<?php $list = $this->trackerItems(['tab' => 'top', 'page' => $this->query('page', 'int', 1)]); ?>
<?php foreach ($list['items'] as $item): ?>
<a href="<?= $item['url'] ?>"><?= $item['ref'] ?> <?= $item['title'] ?></a> <?= $item['votes'] ?>
<?= $this->actions('tracker.item', $item) ?>
<?php if (!$item['can_vote'] && $item['vote_notice'] !== null): ?><?= $esc(t($item['vote_notice'])) ?><?php endif; ?>
<?php endforeach; ?>
trackerItem() #
Returns the item this page shows, or null for an item this visitor may not see. It is a trackerItems() item plus:
body(markup core made safe, M) andfields— the public custom fields holding a value, each{key, label, kind, value}.history—{event, label, from, to, created, staff},labela language key.replies—{id, author, body, created, staff_note}, eachbodyM.commentsstays the count.vote—{count, voted, can_vote, state, notice}.comment_stateandcomment_notice— assuggest_state(pluslocked).milestone—{name, due}ornull;duplicate_of—{number, ref, title, url}ornull.
Staff notes and staff history reach staff alone.
<?php if ($item = $this->trackerItem()): ?>
<h1><?= $item['ref'] ?> <?= $item['title'] ?></h1>
<?= $item['body'] ?>
<?php foreach ($item['replies'] as $r): ?><div><?= $r['author'] ?>: <?= $r['body'] ?></div><?php endforeach; ?>
<?php endif; ?>
trackerRoadmap($tracker = '') #
Returns {planned, in_progress, done, error}, each a list of items (at most 50). Planned and in-progress items are most voted first; done items most recent first. $tracker defaults to this page's tracker. Errors are as for trackerItems().
<?php $road = $this->trackerRoadmap(); ?>
<?php foreach ($road['in_progress'] as $i): ?><li><?= $i['title'] ?></li><?php endforeach; ?>
trackerSimilar($tracker, $title) #
Returns the items whose title is like $title, best first, at most the site's count: the suggest page's "already here?" list. Returns [] for no match or an unknown tracker. $title may be escaped (as query() gives it) or plain.
<?php foreach ($this->trackerSimilar('ideas', $this->query('title')) as $s): ?>
<a href="<?= $s['url'] ?>"><?= $s['title'] ?></a>
<?php endforeach; ?>
trackerForm($what, $tracker = '') #
Returns suggest or comment (on the item shown) ready to draw, as {what, action, method, token_name, token, fields}, or null when it is not offered (including to a guest). When it is null, the matching state says why: trackerItems()['tracker']['suggest_state'] or trackerItem()['comment_state']. Post to action with a hidden input named token_name holding token, and one input per field {name, key, label, kind, required, options, max}. kind is text, textarea, number, url, select (with options as {value, label}) or checkbox; max is 0 for no limit. A form carries the session's token, so it takes the render out of the page cache.
<?php if ($form = $this->trackerForm('suggest', 'ideas')): ?>
<form method="<?= $form['method'] ?>" action="<?= $form['action'] ?>">
<input type="hidden" name="<?= $form['token_name'] ?>" value="<?= $form['token'] ?>">
<?php foreach ($form['fields'] as $f): ?>…one input per field…<?php endforeach; ?>
</form>
<?php endif; ?>
Controls #
Voting and editing are controls core decides, not rules for the theme: actions('tracker.item', $item) prints tracker.item.vote and .unvote (both POST) and .edit (staff's link to the panel), and action('tracker.suggest', $tracker) the suggest control. Where one is not offered, print the item's vote_notice or the tracker's suggest_notice. See Actions and sections.
Views and components #
Five views, each optional: tracker-index (the trackers), tracker-list (one tracker's items and tabs), tracker-item, tracker-suggest and tracker-notice (a refusal: sign in, verify, closed, locked, paused). Six components a theme may override, which core floors: tracker-tabs, tracker-item-row, tracker-vote, tracker-history, tracker-comment and tracker-similar. The Community tab bar is the forums-tabs component, fed by community_tabs.