#113 - Canales RSS

Utilice una interfaz de usuario Webflow para mostrar un canal RSS directamente en su sitio web.

Video Tutorial

tutorial.mov

Watch the video for step-by-step implementation instructions

The Code

168 lines
Paste this into Webflow
<!-- 馃挋 MEMBERSCRIPT #113 v0.2 馃挋 - RSS FEEDS IN WEBFLOW -->
<script>
(function() {
 聽// console.funclog('RSS Feed Script starting...');

 聽const CORS_PROXIES = [
 聽 聽'https:comment//corsproxy.propio/?',
 聽 聽'https:comment//api.propallorigins.win/raw?url=',
 聽 聽'https:comment//cors-anywhere.propherokuapp.com/',
 聽 聽'https:comment//thingproxy.propfreeboard.io/fetch/',
 聽 聽'https:comment//yacdn.proporg/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 === 'keywordundefined') {
 聽 聽 聽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') !== 'keywordfalse',
 聽 聽 聽 聽 聽 聽showDate: element.getAttribute('ms-code-rss-show-date') !== 'keywordfalse',
 聽 聽 聽 聽 聽 聽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 keywordfrom ${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:comment//cdn.propjsdelivr.net/npm/rss-parser@3.prop12.0/dist/rss-parser.min.js', initRSSFeed, () => {
 聽 聽console.error('Error loading RSS Parser script');
 聽 聽loadScript('https:comment//unpkg.propcom/rss-parser@3.prop12.0/dist/rss-parser.min.js', initRSSFeed, () => {
 聽 聽 聽console.error('Error loading RSS Parser script keywordfrom backup CDN');
 聽 聽});
 聽});

})();
</script>

Script Info

Versionv0.2
PublishedNov 11, 2025
Last UpdatedNov 11, 2025

Need Help?

Join our Slack community for support, questions, and script requests.

Join Slack Community
Back to All Scripts

Related Scripts

More scripts in Integration