Skip to content

RSS news feed in widget, with complete PHP source code

Do you want to display news on your classifieds website? Display local news, industry news related to your classifieds website, latest blog posts if you have blog related to your website, twitter feed converted to RSS with external service like TwitRSS.me or similar services. Any standard RSS feed will work.

RSS news widget, PHP source code

This snippet will extract news from several RSS sources and display latest news in widget. Classibase widgets can render PHP code. In this tutorial, with complete source code, you will learn how to display RSS news in widget.

Features

  • Read multiple RSS feeds - You can display combined feed using several RSS sources.
  • Load data using ajax for not blocking and slowing regular page generation.  - Sometimes loading external RSS data may take up to 5-10 seconds time. Loading feed with ajax will make your site load faster and add news widget after page fully loaded.
  • Caching loaded results. This will prevent loading RSS from source on every page request. Instead widget will cache results. Cached results will be displayed much faster.
  • Load one source at a time. If you defined several sources loading all of them at once may slow down your website. If you have 5 sources and each takes 5 seconds to load then if you load all at once it will take 25 seconds. In this widget we load one source at a time, other sources will be loaded with next page.
  • Open news in new window. You do not want your visitor to leave your site so news will open in new window when clicked.
  • Removes any URL from title text. Some RSS feeds have urls inside title which is not necessary to display. Because title will be linked to related article anyway.
  • Keep old result for short time if source is not available at time of request. This is useful if you do not want to display and cache empty result.
  • Timeout after 5 seconds if source RSS loads slowly due to slow network or error on source server. If not set the PHP default it is 60 seconds which is too much.
  • Sleep time 60 seconds between each new load from external source. This will prevent overloading server with simultaneous load requests.
  • Simultaneous source load prevention in case load requested by other client while RSS is being loaded by first request. Seconds request will show old cached result or empty result.
  • Browser cache for 1 hour to decrease number of requests to your server. Because every page will load RSS news widget as new request. Caching result in browser for 1 hour should decrease number of requests to server a up to 90% depending on website traffic.

 

RSS news Widget Code Snippet

<?php 
$cache_browser = 3600;
if(isset($_GET['_widget_rss'])){

	Benchmark::cp('load rss:BEGIN');
	
	$max = 5;
	$cache_time = 5*3600;
	$cache_time_empty = 20*60;
	$cache_time_sleep = 60;
	$save_to_db=false;	

	$rss_src = array(
		'engadget'=>'https://www.engadget.com/rss.xml',
		'wired'=>'http://www.wired.co.uk/rss/article'
	);

	$arrContextOptions=array(
		"ssl"=>array(
			"verify_peer"=>false,
			"verify_peer_name"=>false,
		),
		"http"=>array(
			"timeout" => 5,  //5 Seconds
		)
	);  

	// load result from db 
	$result = Config::option('_widget_rss',null,true);
	if(strlen($result)>10){		
		$result = @unserialize($result);
	}
	if(!$result){		
		$result = array();
	}
	/*$_result = array(
		'key'=>array(
				'src'=>'https://source.url/rss/',
				'time'=>REQUEST_TIME,
				'items'=>array(
					['date from rss x']=>array(
						'date'=>'Y-m-d',
						'title'=>'title text here',
						'link'=>'http://link.here',
					),
				)
		)	
	);*/

	// remove deleted sources 
	$result_clone = $result;
	// get last result time for not loading xml consecutively
	$last_load_time = 0;
	foreach($result_clone as $k=>$v){
		if($v['time']>$last_load_time){
			$last_load_time = $v['time'];
		}
		if(!isset($rss_src[$k])){
			// remove from result and update db 
			$save_to_db=true;
			unset($result[$k]);
		}
	}
	unset($result_clone);
	
	
	if($last_load_time<REQUEST_TIME-$cache_time_sleep){
		// load one rss data if not found or expired in DB
		foreach($rss_src as $k=>$v){		
			// check if data exists 
			if(!isset($result[$k]) || $result[$k]['time']<REQUEST_TIME-$cache_time){
				// create placeholder record with low time for not overloading server with consecutive requests
				if(isset($result[$k])){
					$result[$k]['time']=REQUEST_TIME-$cache_time+$cache_time_sleep;
				}
				else
				{
					$result[$k]=array(
						'src'=>$v,
						'time'=>REQUEST_TIME-$cache_time+$cache_time_sleep,
						'items'=>array()			
					);
				}
				Config::optionSet('_widget_rss',serialize($result),false);
				
				
				//  get this record from source					
				$result_items = array();
				Benchmark::cp('load rss:START');	
				$response = file_get_contents($v, false, stream_context_create($arrContextOptions));
				Benchmark::cp('load rss:'.$v);
				if(strlen($response)>10){
					$xml = simplexml_load_string($response);
					if($xml){
						$cnt = 0;
						foreach($xml->channel->item as $item){
							$date = $item->pubDate.'';	
							$date_time = strtotime($date);	
							// remove urml from title
							//$string = "The Third Culture: The Frontline of Global Thinkinghttp://is.gd/qFioda;via @edge";
							$regex = "@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@";
							$title = $item->title.'';
							$title = preg_replace($regex, ' ', $title);
							$title = trim($title," -");
							$result_items[$date_time]=array(
								'date'=>date("Y-m-d",$date_time),
								'title'=>$title,
								'link'=>$item->link.''					
							);
							$cnt++;
							if($cnt>=$max)
							{
								break;
							}
						}
						
					}
					//print_r($result_items);	
				}			
				
				// if no items then keep time short 
				$time = REQUEST_TIME;
				if(!$result_items)
				{
					$time -= $cache_time-$cache_time_empty;
					if(isset($result[$k]['items'])){
						// keep old items 
						$result_items = $result[$k]['items'];
					}
				}
				
				$result[$k]=array(
					'src'=>$v,
					'time'=>$time,
					'items'=>$result_items			
				);
				
				// loaded from source then break here 
				$save_to_db=true;
				break;		
			}	
		}
	}

	// store result if required 
	if($save_to_db){
		Config::optionSet('_widget_rss',serialize($result),false);
		// saved result, do not cache this 
	}elseif($cache_browser){
		// nothing to save then cache this result in browser
		header("Expires: ".gmdate("D, j M Y H:i:s", REQUEST_TIME+$cache_browser)." GMT"); // Date in the future
		header("Pragma: cache");		
		header("Cache-Control: public, max-age=".$cache_browser, true);
	}

	// now format result as html 
	$_result=array();
	foreach($result as $k=>$v){
		foreach($v['items'] as $item_k=>$item_v){
			$_result[$item_k]=$item_v;
		}
	}
	// order by key (date)
	krsort($_result); 
	$return='';
	foreach($_result as $item)
	{
		$return.='<li><a href="'.View::escape($item['link']).'" target="_blank">'.View::escape($item['title']).'</a> <i>'.View::escape($item['date']).'</i></li>';
	}
	if($return){
		$return = '<div id="_widget_rss"><ul>'.$return.'</ul></div>';
	}
	echo $return;
	Benchmark::cp('load rss:END');
	// echo '<!-- '.Benchmark::report().'-->';
	exit;
}
else
{	
	// cache result for one hour 
	if($cache_browser){
		$date_hr = floor(REQUEST_TIME/$cache_browser);
	}else{
		$date_hr=1;
	}
	?>
	<div id="_widget_rss_"></div>
	<script>
	addLoadEvent(function(){
		$.get(BASE_URL,{_widget_rss:"<?php echo $date_hr;?>"},function(data){
			// get #_widget_rss
			var $data = $(data);
			if(!$data.is('#_widget_rss')){
				$data = $('#_widget_rss:first',$(data));
			}
			$('#_widget_rss_').append($data);
		});
		button_rss_track();
	});
	
	function button_rss_track(){
		$('#_widget_rss_').on('click','a',function(e){
			// if google analytis is not loaded then continue load lined page
			if (e.isDefaultPrevented() || typeof ga !== "function") return;
			// cancel event and record outbound link
			e.preventDefault();
			var $me = $(this);
			var href = $me.attr('href');
			ga('send', {'hitType': 'event','eventCategory': 'rss','eventAction': 'rss_click','eventLabel': href,'hitCallback': loadPage});
			// redirect after one second if recording takes too long
			setTimeout(loadPage, 1000);
			// redirect to outbound page
			function loadPage() {/*document.location = href;*/window.open(href,'_blank');} 		
		});	
	}	
	</script>
	<?php 
}
?>

Instructions

To add this widget follow these steps

  1. Update RSS sources defined in $rss_src array.
  2. Navigate to "Apperance" -> "Widgets" page in admin panel and add text widget to any sidebar that you want.
  3. Paste widget snippet to Text field. Add title to the widget.
  4. Select PHP from text format.
  5. Save widget.

Visit your website front end and navigate couple pages to fully load all RSS sources. News will be displayed in widget area. You can adjust  following variables in code:

  • $max = 5; Defines number of news items to be displayed in widget.
  • $cache_time = 5*3600; Defines cache time in seconds. News will be updated after this period of time.

UPDATE 23.11.2018: Added browser caching.

If you have any questions or reviews please write in comments.

Leave a Reply

Your email address will not be published. Required fields are marked *