Introduction
Twitter terminated its old API, and all of my Twitter tutorials have stopped working! So, here is a follow up to show you how easy is it to retrieve user timeline and hashtag with Twitter REST API 1.1. Of course, I don't just stop there. I integrated my previously written script and modified it to work with Grid-A-Licious plugin to create something that's similar with Pinterest.
Before we start, we need to have all the ingredients ready.
- You need to create an application. https://dev.twitter.com/apps.
- Once you've done that, you need to get your consumer key, consumer secret, access token and access token secret.
- For security reason, Twitter OAuth is done through server side, in this tutorial, we're using PHP. To keep things simple, we are using Twitter Library called CodeBird-PHP.
- To make all the tweets we retrieve pretty, we will be using Grid-A-Licious
Once you have all that, we are good to good. This tutorial is a modified version of my previous old Twitter API - Create a Twitter Feed With Hash Tag And Cache Support. However, we won't implement cache control here just to make it easier to understand.
HTML
Alright, first stop. Since all HTML Markup will be generated by jQuery, we only need a div
with an id called #jstwitter
<div id="jstwitter"></div> <div class="item"> {IMG} <div class="tweet-wrapper"> <span class="text">{TEXT}</span> <span class="time"> <a href="{URL}" target="_blank">{AGO}</a> </span> by <span class="user">{USER}</span> </div> </div>
CSS
I keep CSS really simple, because in the end, I don't think you will be using mine, you probably will style it up according to your website design. So, I spice thing up a little bit. I'm going to create Pinterest style with Grid-A-Licious.
#jstwitter { position: relative; } #jstwitter .item { -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; -webkit-box-shadow:0 0 3px 1px rgba(100,100,100,0.2); -moz-box-shadow:0 0 3px 1px rgba(100,100,100,0.2); box-shadow:0 0 3px 1px rgba(100,100,100,0.2); overflow:hidden; background: #fff; } #jstwitter .tweet-wrapper { padding:10px; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box; line-height:16px; } #jstwitter .item a { text-decoration: none; color: #03a8e5; } #jstwitter .item img { width:100%; } #jstwitter .item a:hover { text-decoration: underline; } #jstwitter .item .text { display:block; } #jstwitter .item .time, #jstwitter .tweet .user { font-style: italic; color: #666666; }
PHP
I keep it really simple. We're not going to write our own PHP OAuth authentication, we will be using a Twitter Library called CodeBird-PHP. CodeBird makes it ridiculously easy to get authenticated. You may want to read more about it - CodeBird Documentation. As long as you get all the keys, tokens and secrets right, you should have any problems at all.
I have write inline comment in the following PHP script. If you want to add cache control to beat the rate limits in Twitter API. Here is the place you need to modify it.
<? //We use already made Twitter OAuth library //https://github.com/mynetx/codebird-php require_once ('codebird.php'); //Twitter OAuth Settings $CONSUMER_KEY = '...'; $CONSUMER_SECRET = '...'; $ACCESS_TOKEN = '...'; $ACCESS_TOKEN_SECRET = '...'; //Get authenticated Codebird::setConsumerKey($CONSUMER_KEY, $CONSUMER_SECRET); $cb = Codebird::getInstance(); $cb->setToken($ACCESS_TOKEN, $ACCESS_TOKEN_SECRET); //retrieve posts $q = $_POST['q']; $count = $_POST['count']; $api = $_POST['api']; //https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline //https://dev.twitter.com/docs/api/1.1/get/search/tweets $params = array( 'screen_name' => $q, 'q' => $q, 'count' => $count ); //Make the REST call $data = (array) $cb->$api($params); //Output result in JSON, getting it ready for jQuery to process echo json_encode($data); ?>
Javascript / jQuery
Lastly, the Javascript. We called the PHP we just created. Depend on the parameters, I have made it so you can either search for hashtag, or load a user timeline. It send the parameters to the PHP file above, and PHP script get us authenticated, and PHP returns Twitter data in JSON format. The following scripts read the data and parse them in to HTML markup.
For more information about the Twitter Object, you can read it here.
$(function() { JQTWEET = { // Set twitter hash/user, number of tweets & id/class to append tweets // You need to clear tweet-date.txt before toggle between hash and user // for multiple hashtags, you can separate the hashtag with OR, eg: // hash: '%23jquery OR %23css' search: '%23heroes2013', //leave this blank if you want to show user's tweet user: 'quenesstestacc', //username numTweets: 21, //number of tweets appendTo: '#jstwitter', useGridalicious: true, template: '<div class="item">{IMG}<div class="tweet-wrapper"><span class="text">{TEXT}</span>\ <span class="time"><a href="{URL}" target="_blank">{AGO}</a></span>\ by <span class="user">{USER}</span></div></div>', // core function of jqtweet // https://dev.twitter.com/docs/using-search loadTweets: function() { var request; // different JSON request {hash|user} if (JQTWEET.search) { request = { q: JQTWEET.search, count: JQTWEET.numTweets, api: 'search_tweets' } } else { request = { q: JQTWEET.user, count: JQTWEET.numTweets, api: 'statuses_userTimeline' } } $.ajax({ url: 'grabtweets.php', type: 'POST', dataType: 'json', data: request, success: function(data, textStatus, xhr) { if (data.httpstatus == 200) { if (JQTWEET.search) data = data.statuses; var text, name, img; try { // append tweets into page for (var i = 0; i < JQTWEET.numTweets; i++) { img = ''; url = 'http://twitter.com/' + data[i].user.screen_name + '/status/' + data[i].id_str; try { if (data[i].entities['media']) { img = '<a href="' + url + '" target="_blank"><img data-src="' + data[i].entities['media'][0].media_url + '" /></a>'; } } catch (e) { //no media } $(JQTWEET.appendTo).append( JQTWEET.template.replace('{TEXT}', JQTWEET.ify.clean(data[i].text) ) .replace('{USER}', data[i].user.screen_name) .replace('{IMG}', img) .replace('{AGO}', JQTWEET.timeAgo(data[i].created_at) ) .replace('{URL}', url ) ); } } catch (e) { //item is less than item count } if (JQTWEET.useGridalicious) { //run grid-a-licious $(JQTWEET.appendTo).gridalicious({ gutter: 13, width: 200, animate: true }); } } else alert('no data returned'); } }); }, /** * relative time calculator FROM TWITTER * @param {string} twitter date string returned from Twitter API * @return {string} relative time like "2 minutes ago" */ timeAgo: function(dateString) { var rightNow = new Date(); var then = new Date(dateString); if ($.browser.msie) { // IE can't parse these crazy Ruby dates then = Date.parse(dateString.replace(/( \+)/, ' UTC$1')); } var diff = rightNow - then; var second = 1000, minute = second * 60, hour = minute * 60, day = hour * 24, week = day * 7; if (isNaN(diff) || diff < 0) { return ""; // return blank string if unknown } if (diff < second * 2) { // within 2 seconds return "right now"; } if (diff < minute) { return Math.floor(diff / second) + " seconds ago"; } if (diff < minute * 2) { return "about 1 minute ago"; } if (diff < hour) { return Math.floor(diff / minute) + " minutes ago"; } if (diff < hour * 2) { return "about 1 hour ago"; } if (diff < day) { return Math.floor(diff / hour) + " hours ago"; } if (diff > day && diff < day * 2) { return "yesterday"; } if (diff < day * 365) { return Math.floor(diff / day) + " days ago"; } else { return "over a year ago"; } }, // timeAgo() /** * The Twitalinkahashifyer! * http://www.dustindiaz.com/basement/ify.html * Eg: * ify.clean('your tweet text'); */ ify: { link: function(tweet) { return tweet.replace(/\b(((https*\:\/\/)|www\.)[^\"\']+?)(([!?,.\)]+)?(\s|$))/g, function(link, m1, m2, m3, m4) { var http = m2.match(/w/) ? 'http://' : ''; return '<a class="twtr-hyperlink" target="_blank" href="' + http + m1 + '">' + ((m1.length > 25) ? m1.substr(0, 24) + '...' : m1) + '</a>' + m4; }); }, at: function(tweet) { return tweet.replace(/\B[@ï¼ ]([a-zA-Z0-9_]{1,20})/g, function(m, username) { return '<a target="_blank" class="twtr-atreply" href="http://twitter.com/intent/user?screen_name=' + username + '">@' + username + '</a>'; }); }, list: function(tweet) { return tweet.replace(/\B[@ï¼ ]([a-zA-Z0-9_]{1,20}\/\w+)/g, function(m, userlist) { return '<a target="_blank" class="twtr-atreply" href="http://twitter.com/' + userlist + '">@' + userlist + '</a>'; }); }, hash: function(tweet) { return tweet.replace(/(^|\s+)#(\w+)/gi, function(m, before, hash) { return before + '<a target="_blank" class="twtr-hashtag" href="http://twitter.com/search?q=%23' + hash + '">#' + hash + '</a>'; }); }, clean: function(tweet) { return this.hash(this.at(this.list(this.link(tweet)))); } } // ify }; });
And finally, you run the script like this:
$(function () { // start jqtweet! JQTWEET.loadTweets(); });
Conclusion
That's it my friend. If you have knowledge in both backend and frontend, web development can be easier. We can reuse a lot of scripts, for example, we use CodeBird, Gridalicious, my previous Twitter scripts. What we did right here, we use it, modify it, and bang, we have a working beautiful twitter feed interface.
I hope you will find this tutorial useful, if you have any question, don't hesitate to drop us a comment. :)
Comments will be moderated and
rel="nofollow"
will be added to all links. You can wrap your coding with[code][/code]
to make use of built-in syntax highlighter.All the keys are correct
I just implemented this within a wordpress theme; however, I am receiving the following php error:
"Fatal error: Class 'Codebird' not found in grabtweets.php on line 14"
line 14:
Note: I have also updated codebird.php to the most recent version (2.5.0-dev).
Thoughts?
Update the code with Codebird to:
I've created the application in my twitter account, changed the keys in grabtweets.php and the username in the js file. I get no errors and a blank page.
Any ideas, or can you tell me how I could troubleshoot?
You can also use console.log(data) (chrome and firefox) to check if it returns any data in line 45.
( ! ) Notice: Undefined index: q in C:\wamp\www\sandbox\vcard\twitter\grabtweets.php on line 20
( ! ) Notice: Undefined index: count in C:\wamp\www\sandbox\vcard\twitter\grabtweets.php on line 21
( ! ) Notice: Undefined index: api in C:\wamp\www\sandbox\vcard\twitter\grabtweets.php on line 22
( ! ) Fatal error: Method name must be a string in C:\wamp\www\sandbox\vcard\twitter\grabtweets.php on line 33
I ran grabtweets.php directly and got a parse error (Parse error: syntax error, unexpected T_STRING). It's referring to this line "namespace Codebird;".
I've since found out namespace requires php 5.3. I'm not sure I can upgrade our php so might need to find another solution. Thanks.
@Kasia & @Jessie: The version of PHP you're running could be the reason why it doesn't work. I'm running PHP5.3.6.
@Jessie, you might want to disable PHP error notices.
Update the code to:
I've created the application in my twitter account, i wanna make program application for get Trending Topic World Wide (TTWW) and count how much tweet on TTWW.
Anybody help me how to count incoming tweets on TTWW ? I'm using PHP 5.2.4 and Twitter API v1.1. Thanks.
Just wanted to add that this code didn't work for me at all. Upon further inspection of Codebird.php the author has started to use namespaces, and as such your code needs modification.
Codebird\Codebird::setConsumerKey($CONSUMER_KEY, $CONSUMER_SECRET);
$cb = Codebird\Codebird::getInstance();
If you notice, I have prepended "Codebird\" before line #13 and #14.
I hope it helps people who were unable to get it working due to the Fatal Error: class Codebird not found. If you look closely at the error message, it's not about the include, or not being able to find the file, it's about the class not being found. Class can't be found because classpath is incorrect. You must include the namespace in the entire classpath. I hope that helps.
Awesome post- I was wondering if there is a way to do the same thing through instagrams api. I know you can use instagram to post via twitter, however since the photos are not hosted on twitter it just comes up with a post and link rather than a photo.
It worked, however when I tried to add a link (href) to the profile {PHO} thumbnail it stopped working, see code below:
I had to include another CSS div (items) as the profile thumbnail was stretching to 100% of the item div. Also how would you align the profile image and user name inline on this code?
I've also hit the rate limit for the API, how do I get around this?
Thanks for all your help
And add this two replaces:
Look for Jonas' answer posted on Mon, 17th June 2013.
I've done everything I can possibly think to try and get this to work but to no avail. Am I right in thinking that jquery.jstwitter.js must be located in the same folder as codebird.php and grabtweets.php?
I'm running php 5.3.25 http://www.mdwoodman.co.uk/phpinfo.php and cannot seem to get anything but error500's when attempting to run www.mdwoodman.co.uk/grabtweets.php
Any help would be hugely appreciated!
Thanks
You can go to page 4 and read previous comment, apparently if you are using PHP5.3 you need to modify the following line (add slashes):
$data = (array) $cb->$api($params);
I have no experience with php so wouldn't know where to begin as far as correcting that code, do you have any suggestions? Thanks,
Matt
PHP Fatal error: Method name must be a string in /var/www/vhosts/mdwoodman.co.uk/httpdocs/grabtweets.php on line 33
Try to comment line33 out see if it still throw an error and start debugging it from there.
it seems that it is not allowed to use $api as the name of the function.
Any workaround of $api?
Matt