Tokr for Craft CMS

Usage

Rendering a feed

{{ craft.tokr.render('homepage') }}

That is the whole integration. Layout, columns, captions and click behaviour all come from the feed's settings, so changing how it looks is a control-panel job, not a deploy.

Pass extra variables through to the template if you need them:

{{ craft.tokr.render('homepage', { heading: 'Latest on TikTok' }) }}

The Twig API

CallReturns
craft.tokr.render('handle')Rendered markup
craft.tokr.render('handle', { … })Same, with extra template variables
craft.tokr.feed('handle')A Feed model
craft.tokr.feeds()Every feed
craft.tokr.videos('handle')A feed's Video models
craft.tokr.account('@username')An Account, by username or ID
craft.tokr.accounts()Every connected account

Video

videoId, caption, captionHtml, title, description, coverImageUrl, url, embedUrl, duration, durationFormatted, aspectRatio, width, height, likeCount, commentCount, shareCount, viewCount, postedAt, account.

caption is TikTok's title when there is one and the description otherwise. captionHtml is the same string HTML-escaped, then with #hashtags and @mentions turned into links.

Account

name, username, handle, displayName, avatarUrl, bioDescription, profileUrl, isVerified, followerCount, followingCount, likesCount, videoCount, isConnected, dateRefreshed.

handle is the username with the @. isConnected is false once the refresh token has expired and the account needs reconnecting by hand.

Building your own markup

{% set feed = craft.tokr.feed('homepage') %}
{% set account = feed.account %}

<h2>{{ account.displayName }} — {{ account.followerCount|number }} followers</h2>

<ul class="my-grid">
    {% for video in feed.videos %}
        <li>
            <a href="{{ video.url }}" target="_blank" rel="noopener">
                <img src="{{ video.coverImageUrl }}"
                     alt="{{ video.caption }}"
                     loading="lazy">
                <span>{{ video.durationFormatted }}</span>
            </a>
            <p>{{ video.captionHtml }}</p>
            <p>{{ video.likeCount|number }} likes · {{ video.postedAt|date('M j') }}</p>
        </li>
    {% endfor %}
</ul>

Reading feed.videos is what triggers a staleness check, so a hand-built feed refreshes on the same schedule as a rendered one.

Overriding the template

Create _tokr/feed.twig in your own templates folder. Tokr renders that instead of its own, passing feed, account and videos. Copy the shipped one as a starting point:

cp vendor/justinholtweb/craft-tokr/src/templates/_frontend/feed.twig templates/_tokr/feed.twig

This is the middle ground between render() and writing everything yourself: you keep the lightbox, the load-more button and the stylesheet, and change only the markup.

Refreshing

By default, the first front-end request after a feed goes stale queues a refresh job and renders from what is already stored. Only one job is queued per interval, however many requests arrive.

For anything with real traffic, use cron instead:

*/30 * * * * cd /path/to/project && php craft tokr/refresh
CommandDoes
php craft tokr/refreshRefresh every stale account
php craft tokr/refresh --forceRefresh every account regardless
php craft tokr/refresh/account @usernameRefresh one account
php craft tokr/refresh/account 3Same, by ID

If you go the cron route, turn Refresh in the background off so front-end requests never queue anything.

tokr/refresh exits non-zero if any account failed, so cron will tell you when a token has died.

In the control panel

Tokr → Accounts lists every connected account with its video count, last refresh and status. Open one to rename it, refresh it immediately, see the most recent thumbnails, or disconnect it.

Disconnecting revokes Tokr's access with TikTok and deletes that account's stored videos and its feeds. It is not a pause button.