Templates & overrides
All rendering flows through plain PHP templates that resolve WooCommerce-style:
{child theme}/thewpfeeds/{name}.php
{parent theme}/thewpfeeds/{name}.php
{plugin}/templates/{name}.php ← shipped defaults
Copy any shipped template into a thewpfeeds/ folder in your theme and edit. You only copy what you change; everything else falls through to the plugin.
The template files
| Template | Receives | Responsibility |
|---|---|---|
feed.php |
$feed, $items, $layout, $args |
Outer wrapper; delegates to layout-{$layout}.php |
layout-grid.php, layout-list.php |
same | The loop structure; calls thewpfeeds_item() per item |
item.php |
$item, $feed |
One card — the file you'll override 90% of the time |
item-youtube.php |
$item, $feed |
Provider default for YouTube (thumbnail + play overlay) |
empty.php |
$feed, $args |
No-items state; error details shown to admins only |
The item hierarchy
Different content wants different markup — a video is not a LinkedIn post. Items resolve through their own hierarchy, most specific first:
item-{feed-slug}.php e.g. item-yt-tutorials.php → one specific feed
item-{provider}.php e.g. item-youtube.php → all feeds of that type
item.php → everything else
Each name is tried through the full theme → plugin chain before falling to the next. This solves both directions:
- Two feeds, different types (LinkedIn + YouTube on one page): each gets type-appropriate markup automatically — the shipped
item-youtube.phprenders video cards, LinkedIn falls toitem.php. - Two feeds, same type, styled differently (multiple YouTube channels): add
item-{slug}.phpper feed. Feeds without one keep the provider default.
For styling-only differences you don't need a template at all — the wrapper carries the feed slug as a class:
.thewpfeeds--yt-events .thewpfeeds__item { /* ... */ }
Custom layouts
Layout names are open-ended. Drop thewpfeeds/layout-carousel.php in your theme and pass carousel as the layout (block sidebar, feed default, or render args) — no registration, no plugin changes. A layout receives the collection and loops it:
<?php /* {theme}/thewpfeeds/layout-carousel.php */ ?>
<div class="my-carousel" data-carousel>
<?php foreach ( $items as $item ) : ?>
<div class="my-carousel__slide"><?php thewpfeeds_item( $item, $feed ); ?></div>
<?php endforeach; ?>
</div>
The escaping contract
Item getters return raw values. Escaping happens in templates — esc_html(), esc_url(), esc_attr() — exactly where WordPress developers expect to do it. The shipped templates demonstrate the discipline; $item->imageTag() is the one helper that returns pre-escaped HTML.
Template versioning
Every shipped template carries an @version header. It only changes when the template's contract changes (new variables, changed structure) — cosmetic edits don't bump it. If you keep overrides long-term, diff against the shipped file when the version moves.