WordPress video timeline with horizontal click navigation
Published 5 min read
Horizontal timelines look straightforward on paper: a row of dated points, a panel above that changes when you click one. The design shows up on brand history pages, documentary episode guides, podcast series archives, and educational course outlines. Building it in WordPress without a page builder is where the complications start.
The plugin registers a Timeline Entry post type in the WordPress admin. Each entry gets a title, a date, a short description, and a video URL. A [timeline] shortcode renders them as a scrollable horizontal bar; clicking any point highlights it and loads the corresponding video and description in a panel above, with no page reload.
One video per entry, all entries loading at once, no category filters. For a company history page with twenty milestones or a podcast archive with fifty episodes it is the right size. For a catalogue that will grow past roughly two hundred entries, a build with lazy-loading fits better.
Entries in the admin, shortcode on the page
Each Timeline Entry post has a meta box with four fields: a date picker stored as YYYY-MM-DD, a description textarea, a video URL text input, and an integer sort-order field for breaking ties between entries that share the same date. The post title becomes the heading shown in the content panel.
Add [timeline] to any page. The shortcode queries all published Timeline Entry posts ordered ascending by the date meta field, builds the horizontal bar from those results, and marks the first entry active on load. No additional configuration or widget area is needed.
Clicking a point without an AJAX call
All entry data, including the pre-rendered video embed HTML, is written into the page as a JSON variable when the shortcode renders. When a visitor clicks a point in the bar, the panel content is swapped by overwriting the panel element's innerHTML from that local data. Nothing goes back to the server on click.
The active entry index is a plain JavaScript variable that resets to zero on each page load. No state is written to localStorage or the URL, so opening the same link always starts on the first entry. Sharing a link to a specific entry is not supported in this build.
What oEmbed covers and where it hands off
The shortcode calls wp_oembed_get() on each entry's video URL at render time and stores the resulting iframe HTML in the data array. That function covers YouTube, Vimeo, and every provider in WordPress's built-in oEmbed list. If the URL is not on that list, wp_oembed_get() returns false and the panel shows a plain linked URL instead of an embed.
WordPress caches oEmbed results after the first fetch, so a cold render that hits fifty YouTube URLs is slow once. Subsequent page loads pull from cache. On a shared host where outbound HTTP is slow, pre-warming the cache by visiting the page after adding all entries is worth doing before sharing the link.
The two-hundred-entry ceiling
Every published Timeline Entry is included in the shortcode output in one pass. Each one contributes its oEmbed HTML and metadata to the JSON data array embedded in the page source. Past roughly two hundred entries the initial page weight becomes noticeable, and the cold-cache oEmbed generation time on a shared host gets long.
For archives that grow over time, the practical answer is to keep older entries unpublished or split into separate pages with separate shortcodes. Lazy-loading entries on click would solve the problem properly but is a different build.
What you get
Included
- Timeline Entry post type with date, description, video URL, and sort-order fields
- Horizontal scrollable navigation bar with click-to-activate entries and date labels
- Content panel that swaps title, description, and video embed on click without page reload
- Server-side oEmbed rendering for YouTube, Vimeo, and all WordPress-supported providers
- Plain linked URL fallback when a video URL is not supported by oEmbed
Not included
- Lazy-loading entries for timelines that grow past roughly two hundred items
- Multiple separate timelines on the same site from a single post type
- Fallback image display when no video URL is provided
- Video autoplay when switching between entries
- Deep-linking to a specific timeline entry from a URL parameter
Questions
Can I show an image instead of a video for some entries?
Not in this build. If the video URL field is empty or unsupported, the panel shows the title and description with a plain linked URL. An image attachment field that appears when no video URL is set can be added with a second build.
Can I run two separate timelines on the same site?
The shortcode queries all published Timeline Entry posts each time. There is no category or group field to separate them. Two independent timelines on one site need a second plugin with a different post type name.
Build it in Steem
The button opens the builder with this guide's prompt filled in, so you can change anything before it runs. Nothing is built, and nothing is charged, until you send it.
Read the prompt (163 words)
Build a WordPress plugin that registers a Timeline Entry custom post type. Each entry needs four meta fields in the admin: a date input stored as YYYY-MM-DD, a description textarea, a video URL text input, and an integer sort order for tie-breaking entries with the same date. Add a [timeline] shortcode that queries all published Timeline Entry posts ordered ascending by date and renders a horizontal scrollable navigation bar above a content panel. Each point in the bar shows the entry date. Clicking a point highlights it in the bar and loads the entry title, description, and video embed in the panel above without a page reload. The first entry is active on load. Use wp_oembed_get() to convert video URLs to iframe HTML at render time; if it returns false, show a plain linked URL. Write all entry data into the page as a JSON variable and swap the panel content using JavaScript with no AJAX calls on click. Make the layout responsive.
Steem