#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

"We've been using Memberstack for a long time, and it has helped us achieve things we would have never thought possible using Webflow. It's allowed us to build platforms with great depth and functionality and the team behind it has always been super helpful and receptive to feedback"

Jamie Debnam
39 Digital

"Been building a membership site with Memberstack and Jetboost for a client. Feels like magic building with these tools. As someone who’s worked in an agency where some of these apps were coded from scratch, I finally get the hype now. This is a lot faster and a lot cheaper."

Félix Meens
Webflix Studio

"One of the best products to start a membership site - I like the ease of use of Memberstack. I was able to my membership site up and running within a day. Doesn't get easier than that. Also provides the functionality I need to make the user experience more custom."

Eric McQuesten
Health Tech Nerds
Off World Depot

"My business wouldn't be what it is without Memberstack. If you think $30/month is expensive, try hiring a developer to integrate custom recommendations into your site for that price. Incredibly flexible set of tools for those willing to put in some minimal efforts to watch their well put together documentation."

Riley Brown
Off World Depot

"The Slack community is one of the most active I've seen and fellow customers are willing to jump in to answer questions and offer solutions. I've done in-depth evaluations of alternative tools and we always come back to Memberstack - save yourself the time and give it a shot."

Abdij Burtis
Health Tech Nerds
Slack

Need help with this MemberScript? Join our Slack community!

Word lid van de Memberstack community Slack en stel uw vragen! Verwacht een snel antwoord van een teamlid, een Memberstack expert of een mede-communitylid.

Word lid van onze Slack