Published Tuesday 10th March 2015
This is an old post and Twitter's API is no longer freely accessible. We've kept it though, because it might still be useful to somebody.
It used to be pretty easy to output a Twitter feed onto your website, but since Twitter decided to close down their public feeds (both RSS and XML), and introduce OAuth into their API, doing this became a bit of a headache. This happened quite some time ago now but there still seems to be a large number of websites out there with broken Twitter outputs so here's a quick tutorial to get you up and running again.
For the record, I tend to recommend doing this server-side rather than using any of the available Javascript options, because this results in static HTML that Google etc can parse, making Twitter outputs a good way to keep your pages constantly updating which is great for SEO. Additionally, Javascript relies on client-side support which makes it a poor choice for anything other than fancying-up your website, assuming you care about accessibility.
<?php
$screen_name = 'Your Twitter Name';
$count = 1; // How many tweets to output
$retweets = 0; // 0 to exclude, 1 to include
// Populate these with the keys/tokens you just obtained
$oauthAccessToken = '';
$oauthAccessTokenSecret = '';
$oauthConsumerKey = '';
$oauthConsumerSecret = '';
// First we populate an array with the parameters needed by the API
$oauth = array(
'count' => $count,
'include_rts' => $retweets,
'oauth_consumer_key' => $oauthConsumerKey,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $oauthAccessToken,
'oauth_version' => '1.0'
);
$arr = array();
foreach($oauth as $key => $val)
$arr[] = $key.'='.rawurlencode($val);
// Then we create an encypted hash of these values to prove to the API that they weren't tampered with during transfer
$oauth['oauth_signature'] = base64_encode(hash_hmac('sha1', 'GET&'.rawurlencode('https://api.twitter.com/1.1/statuses/user_timeline.json').'&'.rawurlencode(implode('&', $arr)), rawurlencode($oauthConsumerSecret).'&'.rawurlencode($oauthAccessTokenSecret), true));
$arr = array();
foreach($oauth as $key => $val)
$arr[] = $key.'="'.rawurlencode($val).'"';
// Next we use Curl to access the API, passing our parameters and the security hash within the call
$tweets = curl_init();
curl_setopt_array($tweets, array(
CURLOPT_HTTPHEADER => array('Authorization: OAuth '.implode(', ', $arr), 'Expect:'),
CURLOPT_HEADER => false,
CURLOPT_URL => 'https://api.twitter.com/1.1/statuses/user_timeline.json?count='.$count.'&include_rts='.$retweets,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
));
$json = curl_exec($tweets);
curl_close($tweets);
// $json now contains the response from the Twitter API, which should include however many tweets we asked for.
// Loop through them for output
foreach(json_decode($json) as $status) {
// Convert links back into actual links, otherwise they're just output as text
$enhancedStatus = htmlentities($status->text, ENT_QUOTES, 'UTF-8');
$enhancedStatus = preg_replace('/http:\/\/t.co\/([a-zA-Z0-9]+)/i', '<a href="http://t.co/$1">http://$1</a>', $enhancedStatus);
$enhancedStatus = preg_replace('/https:\/\/t.co\/([a-zA-Z0-9]+)/i', '<a href="https://t.co/$1">http://$1</a>', $enhancedStatus);
// Finally, output a simple paragraph containing the tweet and a link back to the Twitter account itself. You can format/style this as you like.
?>
<p>"<?php echo $enhancedStatus; ?>"<br /><a href="https://twitter.com/intent/user?screen_name=<?php echo $screen_name; ?>">@<?php echo $screen_name; ?></a></p>
<?php
}
?>
If you want the link back to open in a classic Twitter pop-up, add this Javascript to your page too:
<script type="text/javascript" src="//platform.twitter.com/widgets.js"></script>
Blog posts are written by individuals and do not necessarily depict the opinions or beliefs of QWeb Ltd or its current employees. Any information provided here might be biased or subjective, and might become out of date.
Jane, Tuesday 22nd December 2015 12:50
Thank you, I looked everywhere for such a simple solution.
Intoxication, Tuesday 5th July 2016 12:00
Thank you for such a simple solution.
Please is it possible to have the twitter profile image displayed as well?
Ric, Tuesday 5th July 2016 12:44
Profile images are available via another API endpoint, https://api.twitter.com/1.1/users/show.json
If you therefore replace the two url instances in the above code with the new endpoint, strip out the count and include_rts values from the $oauth array, and add in the required screen_name value to the end of that array and as a parameter to the CURLOPT_URL value, the new response should include a profile_image_url part.
More information here: https://dev.twitter.com/rest/reference/get/users/show
And a working example here: http://pastebin.com/1XVq8GTW
Intoxication, Tuesday 5th July 2016 14:53
Worked perfectly.
Thank you so much. You are a legend.
Ric, Tuesday 5th July 2016 15:01
No worries. If you need anything further do get in touch.
vijay, Monday 26th September 2016 07:22
how to execute this program
Ric, Monday 26th September 2016 10:01
This should work on any Curl enabled PHP server, Vijay.
valerio, Thursday 11th May 2017 14:17
dev.twitter.com doesn’t have a login. i think the right place is https://apps.twitter.com
valerio, Thursday 11th May 2017 14:25
is there a way to use this php code in a simple html page? what would you suggest?
Ric, Thursday 11th May 2017 14:52
dev.twitter.com actually still works, but you’ve to sign in to the regular Twitter front before heading there. You should then see links to create/manage the apps associated to that account. You’re right though, apps.twitter.com is the same place.
If you’re running an nginx + Apache set-up, chances are your .html pages are being served by nginx without any PHP parsing, and for performance it’s a good idea to keep it that way. In which case you won’t be able to include PHP code directly on those pages I’m afraid. You could however add a Javscript to call a PHP script on page load, which could in turn respond with the HTML to output. jQuery.get() would be my approach for that.
https://api.jquery.com/jQuery.get/
Sirisha Garapati, Wednesday 14th June 2017 09:20
Thank you for the article.
Jason, Thursday 3rd August 2017 09:08
Hi,
Great article, thank you. Is there a way to get the expanded url to display under the tweet please?
Thanks in advance
Ric, Thursday 3rd August 2017 10:43
You’ll find an array of urls within the entities object for that, one for each of the shorturls used in the post.
For example if you posts includes the shorturl t.co/abc then in the returned json data you should see something like this:
$status->entities->urls[0]->url => ‘t.co/abc’
$status->entities->urls[0]->expanded_url => ‘www.google.com’
If your post includes 2 urls then you’d see this:
$status->entities->urls[0]->url => ‘t.co/abc’
$status->entities->urls[0]->expanded_url => ‘www.google.com’
$status->entities->urls[1]->url => ‘t.co/abcdef’
$status->entities->urls[1]->expanded_url => ‘www.amazon.com’
And so on.
Jason, Thursday 3rd August 2017 11:18
Fantastic, thank you so much for your help.
Regards
Jason
Erik, Monday 7th August 2017 21:55
Very useful script. It just works. Thank you!
Two questions though:
1) how to filter for #hashtags? (yes, it is possible to filter *after* you have received the tweets, but I’m assuming Twitter has an API for that)
2) how to obtain tweet metadata like creation time and coordinates using your script as a starting point?
Thanks in advance!
Regards,
Erik
Ric, Monday 7th August 2017 23:08
Twitter has a search endpoint which I believe works exclusively on hashtags, though I could be wrong about that.
https://dev.twitter.com/rest/reference/get/search/tweets
Regarding metadata, if you just replace lines 51 – 59 of the above script with a print_r($status); you’ll see the available metadata from the user_timeline endpoint that this script uses.
Bahram, Saturday 2nd December 2017 19:06
Very useful, thank you so much.
jatinder, Monday 4th December 2017 14:24
It worked fine, but i need to get tweet posted date. how i get posted date in yours this code…
Ric, Monday 4th December 2017 14:55
In the example above, $status->created_at should contain a value for that which you can pass through strtotime() to convert to a Unix timestamp.
Inayat Cassambai, Tuesday 17th July 2018 16:51
Hi,
The script works a charm, but i have one query.
How do i pull in the media data for each tweet? So if i have an image i can output that as well.
Thank you.
Ric, Tuesday 17th July 2018 17:19
If images are available within a tweet, you should see a $status->entities->media array that contains those. It expect it’s the media_url value that you’d want from that, to then just render as an img src.
https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object#media
Inayat Cassambai, Wednesday 18th July 2018 09:12
Thanks for the reply Ric.
Just been looking through the docs, and the API we’re querying doesn’t seem to have any parameters for media entities unfortunately.
https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline
Tis a shame as i feel like that should be necessary to have. Unless i’m missing something.
Although what’s interesting is, one of my colleagues has successfully pulled in images from their tweets by passing the tweet_mode=extended parameter.
https://api.twitter.com/1.1/statuses/user_timeline.json?tweet_mode=extended&screen_name=$username&count=$count&include_rts=$retweet
Even though that’s not mentioned in the parameters list in the docs, that seems to have worked for him. I’ve tried adding that to your snippet but it didn’t work, probably because i’m not adding something to your authentication array too.
Ric, Wednesday 18th July 2018 09:32
That’s strange. We’ve definitely integrated Twitter inclusive of posted media somewhere and the code would have been somewhat similar to the above, but for the life of me I can’t think where we did that now.
Twitter do keep changing their API so it’s entirely possible that the parameter you’ve found is how you were supposed to do this originally and they’ve since separated the endpoints out but left that param in for compatibility with old scripts. I’d be tempted to just go with that approach for the time being, but yes you would need to add to the oAuth array too, in the same order that you’ve added it to the actual call, just like the count and include_rts params are included.
Luis, Saturday 5th December 2020 12:56
Im trying to modify this code to send a simple text tweet. Tríed but Im stuck :(
Ric, Sunday 6th December 2020 16:31
Hi Luis. You'll need to submit to update.json instead of user_timeline.json but the process should be fairly similar:
https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-update
WilliamNow, Tuesday 26th October 2021 23:23
Good article! We will be linking to this particularly great article on our site. Keep up the good writing.
LeotaOnerb, Sunday 6th August 2023 09:54
Do you mind if I quote a couple of your posts as long as I provide credit and sources back to your weblog? My blog is in the very same area of interest as yours and my users would definitely benefit from some of the information you present here. Please let me know if this ok with you. Thanks a lot!
Ric, Sunday 6th August 2023 10:39
You're welcome to quote, with citation, any of our content.
Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text. You won't be added to any mailing list, and your details won't be shared with any third party.