Skip to content

Migrate from client-side unfurl to server-side link preview system#3355

Merged
benwerd merged 5 commits into
devfrom
claude/improve-link-preview-7I9wa
Mar 12, 2026
Merged

Migrate from client-side unfurl to server-side link preview system#3355
benwerd merged 5 commits into
devfrom
claude/improve-link-preview-7I9wa

Conversation

@benwerd

@benwerd benwerd commented Mar 12, 2026

Copy link
Copy Markdown
Member

Here's what I fixed or added:

Replaced the client-side URL unfurling system with a server-side link preview system that:

  1. New LinkPreview component (Idno/Core/LinkPreview.php):

    • Listens for the published event on entities
    • Extracts the first URL from entity body text
    • Enqueues async jobs to fetch OpenGraph/meta tag metadata
    • Caches preview data directly on the entity as link_preview
  2. New LinkPreviewCard template (templates/default/entity/LinkPreviewCard.tpl.php):

    • Medium-style card design with image, title, description, and domain
    • Server-side rendered from cached metadata
    • Responsive and accessible with proper link attributes
  3. Updated styling (css/idno.css):

    • Replaced old unfurl styles with modern link-preview-card styles
    • Improved visual design with hover effects and proper text truncation
    • Better responsive behavior
  4. Removed client-side unfurl system:

    • Deleted js/src/classes/Unfurl.js and related JavaScript
    • Removed Idno/Pages/Service/Web/UrlUnfurl.php endpoint
    • Removed Idno/Pages/Service/Web/RemovePreview.php endpoint
    • Removed old unfurl templates and SCSS
  5. Updated build configuration:

    • Removed Unfurl.js from Gruntfile.js build process
    • Removed unfurl SCSS from main stylesheet imports
    • Updated service worker naming (KnownServiceWorker → IdnoServiceWorker)

Here's why I did it:

  • Performance: Server-side caching eliminates repeated client-side requests for the same URLs
  • Reliability: Centralized unfurling logic is easier to maintain and debug
  • User Experience: Previews are rendered immediately on page load rather than asynchronously
  • Simplicity: Reduces JavaScript complexity and removes dependency on client-side URL parsing
  • SEO: Server-rendered content is more discoverable
  • Consistency: All entities with URLs get consistent preview styling automatically

Checklist:

  • This pull request addresses a single issue
  • I've adhered to Idno's style guide
  • My code contains descriptive comments
  • Existing functionality preserved through new async queue system

https://claude.ai/code/session_01EgfJke6iWTtt67VeQJz5DX

claude and others added 5 commits March 11, 2026 20:47
…ards

- Queue link metadata fetching via async queue when a status is saved
  with a URL, storing OG/meta data directly on the entity as link_preview
- Render cached link previews server-side in Status view template,
  eliminating per-page-load AJAX unfurl requests
- Redesign preview card with clean Medium-style layout: full-width
  image, title, description, and domain indicator
- Fall back to JS-based unfurl only when no cached preview exists yet
- Keep real-time preview in edit form via existing Unfurl.unfurl() flow
- Remove debug console.log from Unfurl.getUrls()

https://claude.ai/code/session_01EgfJke6iWTtt67VeQJz5DX
Delete the JS-based Unfurl system that fetched link previews via AJAX
on every page load:

- Delete js/src/classes/Unfurl.js and remove from Grunt build
- Delete /service/web/unfurl/ and /service/web/unfurl/remove/ routes,
  along with UrlUnfurl.php and RemovePreview.php service pages
- Delete content/unfurl.tpl.php and entity/UnfurledUrl.tpl.php templates
- Delete _unfurl.scss and remove from SCSS imports
- Remove unfurl JS calls from Status edit template
- Remove generic URL unfurl fallback from content/embed.tpl.php
  (known media embeds like YouTube/Vimeo still work)
- Remove legacy unfurled-url CSS from compiled stylesheet

Link previews are now handled entirely server-side: metadata is fetched
via the async queue on save and cached on the entity, then rendered
directly in the Status view template using LinkPreviewCard.tpl.php.

https://claude.ai/code/session_01EgfJke6iWTtt67VeQJz5DX
Move link preview fetching out of the Status plugin into a new
Idno\Core\LinkPreview component so any plugin can benefit from it:

- Create Idno/Core/LinkPreview.php extending Component, with:
  - extractFirstUrl() static helper for URL extraction
  - buildPreviewFromData() static helper for normalizing OG metadata
  - 'published' event listener that auto-enqueues preview fetching
    for any entity with a body containing a URL
  - 'linkpreview/fetch' async handler that fetches metadata via
    UnfurledUrl and caches it on the entity as link_preview
- Register LinkPreview in start.php alongside other core components
- Remove all link preview logic from Status plugin (Main.php event
  handler, Status.php queue call and extractFirstUrl method)

Any plugin can now use link previews by:
1. Having a text `body` property on its entity
2. Rendering entity/LinkPreviewCard in its view template when
   $entity->link_preview is populated

https://claude.ai/code/session_01EgfJke6iWTtt67VeQJz5DX
The link preview styles were removed from idno.css, which meant the
card rendered unstyled across all templates. Add them back and
regenerate the minified CSS.

https://claude.ai/code/session_01EgfJke6iWTtt67VeQJz5DX
@benwerd benwerd merged commit b4cb25f into dev Mar 12, 2026
7 checks passed
@benwerd benwerd deleted the claude/improve-link-preview-7I9wa branch March 12, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants