{"id":1398,"date":"2010-05-07T23:21:52","date_gmt":"2010-05-07T21:21:52","guid":{"rendered":"http:\/\/planetozh.com\/blog\/?p=1398"},"modified":"2010-05-08T01:06:57","modified_gmt":"2010-05-07T23:06:57","slug":"how-to-embed-a-tweet-in-wordpress-a-complete-oembed-tutorial","status":"publish","type":"post","link":"https:\/\/planetozh.com\/blog\/2010\/05\/how-to-embed-a-tweet-in-wordpress-a-complete-oembed-tutorial\/","title":{"rendered":"How to Embed a Tweet in WordPress: a Complete oEmbed Tutorial"},"content":{"rendered":"<p>A few days ago, Twitter published a <a href=\"http:\/\/media.twitter.com\/blackbird-pie\/\">new tool<\/a> that lets you embed a tweet on your site, simplifying the old school way: take a screenshot, crop the picture, upload it, embed it.<\/p>\n<p>The problem is: this Twitter tool is way too lame. Basically you need to cut and paste a lengthy code snippet full of HTML and CSS. How ugly. Compared to the way you can embed a Youtube video in WordPress (just pasting a video URL, on its own line) this is seriously cumbersome.<\/p>\n<p>Hey, wouldn&#39;t it be cool if you can embed a tweet just as easily? You would just paste its URL and let WordPress transforms it into a nicely presented tweet with links and everything? OK, let&#39;s do a plugin for this. And guess what, it&#39;s going to be fairly easy, using WordPress&#39; oEmbed API implementation.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/planetozh.com\/blog\/wp-content\/uploads\/2010\/05\/embed-tweet.jpg\" alt=\"\" title=\"embed-tweet\" width=\"528\" height=\"257\" class=\"aligncenter size-full wp-image-1400\" srcset=\"https:\/\/planetozh.com\/blog\/wp-content\/uploads\/2010\/05\/embed-tweet.jpg 528w, https:\/\/planetozh.com\/blog\/wp-content\/uploads\/2010\/05\/embed-tweet-300x146.jpg 300w\" sizes=\"auto, (max-width: 528px) 100vw, 528px\" \/><br \/>\n<!--more--><\/p>\n<h2>What is oEmbed<\/h2>\n<p>When you paste a Youtube video URL, raw (not hyperlinked) and on its own line, WordPress transforms it into an embedded video. Why? Basically, there&#39;s something in WordPress that says &quot;every time you see a URL like <tt>http:\/\/www.youtube.com\/watch?v=*<\/tt>, ask <tt>http:\/\/www.youtube.com\/oembed<\/tt> what to do with it&quot;.<\/p>\n<p>In short, <a href=\"http:\/\/www.oembed.com\/\">oEmbed<\/a> is a simple API that lets you define a URL pattern (used by a <em>consumer<\/em>) and the URL of a script (the <em>provider<\/em>) that will generate a clean HTLM out of it.<\/p>\n<p>Twitter does not support (yet) oEmbed, so we will have to handle this on our own: transform a WordPress blog into a oEmbed provider.<\/p>\n<h2>Register your blog as an oEmbed provider<\/h2>\n<p>First, let&#39;s register our blog as an oEmbed provider, to replace all URLs like <tt>http:\/\/twitter.com\/ozh\/status\/13156561<\/tt> into a cool piece of HTML. If you can breathe and walk at the same time, you&#39;re qualified to do this: all we need is a single function call. The function to be used here is <tt>wp_oembed_add_provider( $pattern, $url_of_service)<\/tt>.<\/p>\n<div id=\"ig-sh-1\" class=\"syntax_hilite\">\n\n\t\t<div class=\"toolbar\">\n\n\t\t<div class=\"view-different-container\">\n\t\t\t\t\t\t<a href=\"#\" class=\"view-different\">&lt; View <span>plain text<\/span> &gt;<\/a>\n\t\t\t\t\t<\/div>\n\n\t\t<div class=\"language-name\">php<\/div>\n\n\t\t\n\t\t<br clear=\"both\">\n\n\t<\/div>\n\t\n\t<div class=\"code\">\n\t\t<ol class=\"php\" style=\"font-family:monospace\"><li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ Return the internal URL that will handle the oEmbed requests (ie yourblog.com\/blog\/?ozh_tweet=1)<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">function ozh_tweetembed_internal_oembed_url() {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; return trailingslashit( home_url() ) . '?ozh_tweet=1';<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">}<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ Register this internal URL as an oEmbed provider for twitter URLs<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">function ozh_tweetembed_add_oembed_provider() {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ http:\/\/twitter.com\/ozh\/statuses\/1234567<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; wp_oembed_add_provider( 'http:\/\/twitter.com\/*\/status\/*', ozh_tweetembed_internal_oembed_url() );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">}<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">add_action( 'init', 'ozh_tweetembed_add_oembed_provider' );<\/div><\/li>\n<\/ol>\t<\/div>\n\n<\/div>\n\n<p>OK, so far, we&#39;re telling WP that everytime something looks like <tt>http:\/\/twitter.com\/*\/status\/*<\/tt>, it will have to ask <tt>yourblog.com\/blog\/?ozh_tweet=1<\/tt> what to do with it.<\/p>\n<h2>Catch URLs that will contain ?ozh_tweet=1<\/h2>\n<p>Since we&#39;re now expecting WP to do something particular when called with <tt>?ozh_tweet=1<\/tt>, we have to hijack this URL:<\/p>\n<div id=\"ig-sh-2\" class=\"syntax_hilite\">\n\n\t\t<div class=\"toolbar\">\n\n\t\t<div class=\"view-different-container\">\n\t\t\t\t\t\t<a href=\"#\" class=\"view-different\">&lt; View <span>plain text<\/span> &gt;<\/a>\n\t\t\t\t\t<\/div>\n\n\t\t<div class=\"language-name\">php<\/div>\n\n\t\t\n\t\t<br clear=\"both\">\n\n\t<\/div>\n\t\n\t<div class=\"code\">\n\t\t<ol class=\"php\" style=\"font-family:monospace\"><li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ Register 'ozh_tweet' as a query var so we can check if ?ozh_tweet=1<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">function ozh_tweetembed_add_tweet_query_var( $query_vars ) {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $query_vars[] = 'ozh_tweet';<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; return $query_vars;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">}<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">add_filter('query_vars', 'ozh_tweetembed_add_tweet_query_var');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ As early as possible, check for query var 'ozh_tweet' and maybe shortcut everything<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">function ozh_tweetembed_get_tweet_query_var() {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $tweet = get_query_var( 'ozh_tweet' );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if( $tweet ) {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; \/\/ Make something with the oEmbed request<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; ozh_tweetembed_handle_oembed_request();<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; \/\/ Now die, we don't want a blog page<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; die();<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; }<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">}<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">add_action( 'template_redirect', 'ozh_tweetembed_get_tweet_query_var' );<\/div><\/li>\n<\/ol>\t<\/div>\n\n<\/div>\n\n<p>So, at this point, every time WP sees a line matching <tt>http:\/\/twitter.com\/*\/status\/*<\/tt>, it will ask <tt>yourblog.com\/blog\/?ozh_tweet=1&url=the_tweet_url&some_other_var=...<\/tt> what to do with it. So, what to do with it?<\/p>\n<h2>Handling the oEmbed request itself<\/h2>\n<p>Now for the fun part: the function that handles the oEmbed request and return the expected formatted output.<\/p>\n<p>Basically, we&#39;re going to:<\/p>\n<ol>\n<li>Guess the tweet id<\/li>\n<li>Poll the Twitter API for information about this tweet, get a JSON response<\/li>\n<li>Parse the JSON response, make something pretty with this it<\/li>\n<li>Return that pretty thing into a JSON response<\/li>\n<\/ol>\n<p>Vamos, muchachos:<\/p>\n<div id=\"ig-sh-3\" class=\"syntax_hilite\">\n\n\t\t<div class=\"toolbar\">\n\n\t\t<div class=\"view-different-container\">\n\t\t\t\t\t\t<a href=\"#\" class=\"view-different\">&lt; View <span>plain text<\/span> &gt;<\/a>\n\t\t\t\t\t<\/div>\n\n\t\t<div class=\"language-name\">php<\/div>\n\n\t\t\n\t\t<br clear=\"both\">\n\n\t<\/div>\n\t\n\t<div class=\"code\">\n\t\t<ol class=\"php\" style=\"font-family:monospace\"><li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ Handle the oEmbed requests<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ The oEmbed request is something like:<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/ yourblog.com\/blog\/?ozh_tweet=1&amp;url=http:\/\/twitter.com\/ozh\/statuses\/123456&amp;...<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">\/\/<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">function ozh_tweetembed_handle_oembed_request() {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $url = esc_url( $_GET['url'] );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if( !$url )<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; die('URL missing');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; preg_match( '!http:\/\/twitter.com\/([^\/]+)\/status\/(\\d+)!', $url, $matches );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $author &nbsp;= $matches[1];<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $tweetid = $matches[2];<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; unset( $matches );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ From this point, we fetch content from Twitter and print a JSON string.<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ If something goes wrong (like, Twitter unreachable) then we'll simply print anything but JSON<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ and let WP handle the response.<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ fetch http:\/\/api.twitter.com\/1\/statuses\/show\/$tweet.json<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $apiurl = 'http:\/\/api.twitter.com\/1\/statuses\/show\/'.$tweetid.'.json';<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if ( !$result = wp_remote_retrieve_body( wp_remote_get( $apiurl, array('timeout' =&gt; 15) ) ) )<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; die( &quot;could not fetch $apiurl&quot; );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ Check that JSON is well formed<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $result = trim( $result );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if ( !$data = json_decode($result) )<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; die( &quot;Data was not JSON&quot; );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ Now extract a few variables from the $data object<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $text = $data-&gt;text;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $created_at = date('d M Y g:i a', strtotime( $data-&gt;created_at ) );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if( !empty($data-&gt;source) )<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; $source = 'via '.$data-&gt;source;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; if( !empty($data-&gt;in_reply_to_screen_name) ) {<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; $in_reply_to_screen_name = $data-&gt;in_reply_to_screen_name;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; $in_reply_to_status_id &nbsp; = $data-&gt;in_reply_to_status_id;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; $inreply = &quot;in reply to &lt;a href='http:\/\/twitter.com\/$in_reply_to_screen_name\/status\/$in_reply_to_status_id'&gt;@$in_reply_to_screen_name&lt;\/a&gt;&quot;;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; }<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $name = $data-&gt;user-&gt;name;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $screen_name = $data-&gt;user-&gt;screen_name;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $profile_image = $data-&gt;user-&gt;profile_image_url;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ Make up some HTML with the tweet info<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $html = &lt;&lt;&lt;HTML<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&lt;div class=&quot;tweet&quot;&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &lt;div class=&quot;text&quot;&gt;$text&lt;\/div&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &lt;div class=&quot;meta&quot;&gt;$created_at $source $inreply&lt;\/div&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &lt;hr\/&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &lt;div class=&quot;pic&quot;&gt;&lt;a href=&quot;http:\/\/twitter.com\/$screen_name&quot;&gt;&lt;img src=&quot;$profile_image&quot;&gt;$name&lt;\/a&gt;&lt;\/div&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&lt;\/div&gt;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">HTML;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp;<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ Put everything into a regular array<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; $json = array(<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; 'version' =&gt; '1.0',<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; 'type' &nbsp; &nbsp;=&gt; 'rich',<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; 'width' &nbsp; =&gt; 1337, \/\/ this parameter is mandatory according to the oEmbed specs, but we're not using it<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; 'height' &nbsp;=&gt; 1337, \/\/ same.<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; &nbsp; &nbsp; 'html' &nbsp; &nbsp;=&gt; trim( $html ),<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; \/\/ Now output a JSON response &nbsp; <\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; header('Cache-Control: no-cache, must-revalidate');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; header('Content-type: application\/json');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; header('Content-Disposition: attachment; filename=&quot;oembed.json&quot;');<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">&nbsp; &nbsp; echo json_encode( $json );<\/div><\/li>\n<li style=\"font-weight: normal;vertical-align:top\"><div style=\"font: normal normal 1em\/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top\">}<\/div><\/li>\n<\/ol>\t<\/div>\n\n<\/div>\n\n<p>And&#8230; That&#39;s it. Now just paste a tweet URL and let WordPress do the job. For your convenience, get the whole plugin we&#39;ve just dissected in a single file<\/p>\n<div class=\"download\">\nDownload the plugin <a href=\"https:\/\/planetozh.com\/blog\/wp-content\/uploads\/2010\/05\/ozh-oembed-tweet.php_.txt\">ozh-oembed-tweet.php.txt<\/a><br \/>\n(save as .php then put in your plugins folder)\n<\/div>\n<h2>Further improvements and remarks<\/h2>\n<p>This simple &quot;proof of concept&quot; plugin returns very basic HTML, you&#39;d need to make it prettier (use the tweet background, CSS style it). Just modify the &quot;$html =&quot; starting at line 44 or, even cooler, add an interface to the plugin where you can define a template for the tweet output. If you want some inspiration, I do something like this in my plugin <a href=\"https:\/\/planetozh.com\/blog\/my-projects\/wordpress-plugin-better-feed-rss\/\">Better Feed<\/a> where the user can customize feed item footer with a simple templating system.<\/p>\n<p>When WordPress makes an oEmbed request, it does it once and stores its result in the postmeta table. Twitter has that feature we all know and don&#39;t care about any longer: unreliability. Notice the timeout parameter I&#39;ve added to the remote request (line 21), this is really needed. Still, if you blog cannot fetch the tweet from Twitter&#39;s API, it will store a dummy postmeta entry (<tt>{{unknown}}<\/tt>) and won&#39;t replace the tweet URL. A proper plugin should test for the postmeta value and re-poll the Twitter API if applicable.<\/p>\n<p>Twitter does not support oEmbed, but another site does it for them: <a href=\"http:\/\/oohembed.com\/\">Ooh Embed<\/a>. So, technically, a plugin to embed tweets using the oEmbed API would require just three lines, register oohembed.com as a producer. But that wouldn&#39;t be fun :) (and I don&#39;t know how reliable is oohembed.com)<\/p>\n<p>Technically again, you could use more efficiently function <tt>wp_embed_register_handler()<\/tt> to deal with the oEmbed request without having to sending an extra HTTP request to your own site. But that would probably make a confusing example of the general mechanism of the API, with a consumer sending a request to a producer.<\/p>\n<p>Any other comment or idea of something cool to do with Twitter and oEmbed? Use the comment form <span title=\"low pitched voice\">belllowwww<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A few days ago, Twitter published a new tool that lets you embed a tweet on your site, simplifying the old school way: take a screenshot, crop the picture, upload it, embed it. The problem is: this Twitter tool is way too lame. Basically you need to cut and paste a lengthy code snippet full of HTML and CSS. How\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[367,371,85,292,245],"class_list":["post-1398","post","type-post","status-publish","format-standard","hentry","category-published","tag-how-to","tag-oembed","tag-plugins","tag-twitter","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts\/1398","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/comments?post=1398"}],"version-history":[{"count":0,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts\/1398\/revisions"}],"wp:attachment":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/media?parent=1398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/categories?post=1398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/tags?post=1398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}