#113 - RSS Feeds v0.2

Use a Webflow UI to display an RSS feed directly on your Website.

Bekijk demo

<!-- 💙 MEMBERSCRIPT #113 v0.2 💙 - RSS FEEDS IN WEBFLOW -->
<script>
(function() {
  // console.log('RSS Feed Script starting...');

  const CORS_PROXIES = [
    'https://corsproxy.io/?',
    'https://api.allorigins.win/raw?url=',
    'https://cors-anywhere.herokuapp.com/',
    'https://thingproxy.freeboard.io/fetch/',
    'https://yacdn.org/proxy/'
  ];

  function loadScript(src, onLoad, onError) {
    const script = document.createElement('script');
    script.src = src;
    script.onload = onLoad;
    script.onerror = onError;
    document.head.appendChild(script);
  }

  async function fetchWithFallback(url) {
    for (const proxy of CORS_PROXIES) {
      try {
        const response = await fetch(proxy + encodeURIComponent(url));
        if (response.ok) {
          return await response.text();
        }
      } catch (error) {
        console.warn(`Failed to fetch with proxy ${proxy}:`, error);
      }
    }
    throw new Error('All CORS proxies failed');
  }

  function initRSSFeed() {
    if (typeof RSSParser === 'undefined') {
      console.error('RSSParser is not defined.');
      return;
    }

    const parser = new RSSParser({
      customFields: {
        item: [
          ['media:content', 'mediaContent', {keepArray: true}],
          ['media:thumbnail', 'mediaThumbnail', {keepArray: true}],
          ['enclosure', 'enclosure', {keepArray: true}],
        ]
      }
    });

    document.querySelectorAll('[ms-code-rss-feed]').forEach(element => {
      const url = element.getAttribute('ms-code-rss-url');
      const limit = parseInt(element.getAttribute('ms-code-rss-limit')) || 5;

      fetchWithFallback(url)
        .then(str => parser.parseString(str))
        .then(feed => {
          renderRSSItems(element, feed.items.slice(0, limit), {
            showImage: element.getAttribute('ms-code-rss-show-image') !== 'false',
            showDate: element.getAttribute('ms-code-rss-show-date') !== 'false',
            dateFormat: element.getAttribute('ms-code-rss-date-format') || 'short',
            target: element.getAttribute('ms-code-rss-target') || '_self'
          });
        })
        .catch(err => {
          console.error('Error fetching or parsing RSS feed:', err);
          element.textContent = `Failed to load RSS feed from ${url}. Error: ${err.message}`;
        });
    });
  }

  function renderRSSItems(element, items, options) {
    const templateItem = element.querySelector('[ms-code-rss-item]');
    if (!templateItem) return;

    element.innerHTML = ''; // Clear existing items

    items.forEach(item => {
      const itemElement = templateItem.cloneNode(true);

      const title = itemElement.querySelector('[ms-code-rss-title]');
      if (title) {
        const titleLength = parseInt(title.getAttribute('ms-code-rss-title-length')) || Infinity;
        title.textContent = truncate(item.title, titleLength);
      }

      const description = itemElement.querySelector('[ms-code-rss-description]');
      if (description) {
        const descriptionLength = parseInt(description.getAttribute('ms-code-rss-description-length')) || Infinity;
        description.textContent = truncate(stripHtml(item.content || item.description), descriptionLength);
      }

      const date = itemElement.querySelector('[ms-code-rss-date]');
      if (date && options.showDate && item.pubDate) {
        date.textContent = formatDate(new Date(item.pubDate), options.dateFormat);
      }

      const img = itemElement.querySelector('[ms-code-rss-image]');
      if (img && options.showImage) {
        const imgUrl = getImageUrl(item);
        if (imgUrl) {
          img.src = imgUrl;
          img.alt = item.title;
          img.removeAttribute('srcset');
        }
      }

      const linkElement = itemElement.querySelector('[ms-code-rss-link]');
      if (linkElement) {
        linkElement.setAttribute('href', item.link);
        linkElement.setAttribute('target', options.target);
      }

      element.appendChild(itemElement);
    });
  }

  function getImageUrl(item) {
    const sources = ['mediaContent', 'mediaThumbnail', 'enclosure'];
    for (let source of sources) {
      if (item[source] && item[source][0]) {
        return item[source][0].$ ? item[source][0].$.url : item[source][0].url;
      }
    }
    return null;
  }

  function truncate(str, length) {
    if (!str) return '';
    if (length === Infinity) return str;
    return str.length > length ? str.slice(0, length) + '...' : str;
  }

  function stripHtml(html) {
    const tmp = document.createElement('DIV');
    tmp.innerHTML = html || '';
    return tmp.textContent || tmp.innerText || '';
  }

  function formatDate(date, format) {
    if (!(date instanceof Date) || isNaN(date)) return '';
    const options = format === 'long' ? 
          { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' } : 
    undefined;
    return format === 'relative' ? getRelativeTimeString(date) : date.toLocaleDateString(undefined, options);
  }

  function getRelativeTimeString(date, lang = navigator.language) {
    const timeMs = date.getTime();
    const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);
    const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];
    const units = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'];
    const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));
    const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
    const rtf = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' });
    return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
  }

  loadScript('https://cdn.jsdelivr.net/npm/rss-parser@3.12.0/dist/rss-parser.min.js', initRSSFeed, () => {
    console.error('Error loading RSS Parser script');
    loadScript('https://unpkg.com/rss-parser@3.12.0/dist/rss-parser.min.js', initRSSFeed, () => {
      console.error('Error loading RSS Parser script from backup CDN');
    });
  });

})();
</script>

Het Make.com-scenario maken

1. Download de JSON blauwdruk hieronder om het te leren.

2. Navigeer naar Make.com en maak een nieuw scenario...

3. Klik op het kleine vakje met 3 stippen en vervolgens op Import Blueprint...

4. Upload je bestand en voila! Je bent klaar om je eigen accounts te koppelen.

Hulp nodig met deze MemberScript?

Alle Memberstack-klanten kunnen om hulp vragen in de 2.0 Slack. Houd er rekening mee dat dit geen officiële functies zijn en dat ondersteuning niet kan worden gegarandeerd.

Word lid van de 2.0 Slack
Versie-opmerkingen

v0.2 - CORS Proxy Rotation

Changed the script to try multiple different CORS proxies if one fails or is slow.

Attributen
Beschrijving
Attribuut
Geen items gevonden.
Gidsen / Handleidingen
Geen items gevonden.
Les
Wat is Memberstack?

Auth & betalingen voor Webflow sites

Voeg logins, abonnementen, gated content en nog veel meer toe aan uw Webflow site - eenvoudig en volledig aanpasbaar.

Meer informatie