Commits

Iván Flores committed c37b68d

First Release

  • Participants
  • Parent commits e7d2347
  • Tags 0.1

Comments (0)

Files changed (3)

+#### Restate Media Plaugin - Twitter Feed API 1.1
+
+This plugin is based on this code (https://gist.github.com/MikeRogers0/5033286) by Mike Rogers
+
+#### Setup Instrucctions:
+
+1. Go to http://dev.twitter.com and login with your developer account, or
+   your new, regular account. If you are doing the latter, Twitter will 
+   automatically create a developer account for you from your regular one.
+   
+2. Hover over your username (upper right) and click "My Applications". 
+
+3. Click "Create a new application" and enter the necessary information. 
+   For the "Callback URL", enter the URL of the website on which you will 
+   be using this plugin. NOTE: the "Callback URL" is optional and is only
+   necessary if you plan to use callbacks.
+   
+4. Once your Application has been created, click on "Create my access
+   token", at the bottom of the "Details" tab on the application's page. 
+   
+At this point, you will have all of the necessary keys, secrets and tokens 
+necessary for using this plugin. If you are unsure of what to do next, 
+take a look at the example code, provided with the plugin. The code notes
+where you need to put each of the necessary tokens and makes all of the 
+necessary calls.
+

File rm-twitter-feed.php

+<?php
+/* 
+    Plugin Name: Restate Media - Twitter Feed
+    Plugin URI: http://restatemedia.com
+    Description: Plugin for displaying tweets using Twitter API 1.1 
+    Author: Iván Flores
+    Version: 1.0 
+    Author URI: http://restatemedia.com
+*/ 
+
+
+// Shortcode
+function rm_twitter_feed_shortcode( $atts ){
+	return '<ul id="twitter-feed"></ul>';
+}
+add_shortcode('twitter_feed', 'rm_twitter_feed_shortcode' ); 
+
+
+// Fields
+function rm_twitter_feed_fields() { ?>
+	<div class="wrap">
+		<?php screen_icon(); ?>
+		<h2>RM - Twitter Feed [api 1.1]</h2>
+
+			<h3>Setup Instrucctions:</h3>
+
+			<ol>
+				<li>Go to <a href="http://dev.twitter.com" target="_blank">http://dev.twitter.com</a> and login with your developer account, or
+				   your new, regular account. If you are doing the latter, Twitter will 
+				   automatically create a developer account for you from your regular one.
+				</li>
+			   
+				<li>Hover over your username (upper right) and click "My Applications".</li> 
+
+				<li>Click "Create a new application" and enter the necessary information. 
+				   For the "Callback URL", enter the URL of the website on which you will 
+				   be using this plugin. NOTE: the "Callback URL" is optional and is only
+				   necessary if you plan to use callbacks.</li>
+				   
+				<li>Once your Application has been created, click on "Create my access
+				   token", at the bottom of the "Details" tab on the application's page.</li>
+			
+			</ol>
+			<p>At this point, you will have all of the necessary keys, secrets and tokens 
+			necessary for using this plugin.
+	   		 </p>
+
+		<form method="post" action="options.php">
+			<?php settings_fields('rm_twitter_feed_options_fields'); ?>
+
+			
+			<h3>App Credentials</h3>
+			<table class="form-table">
+    		
+	    	<tr valign="top">
+	        <th scope="row">Access Token:</th>
+	        <td>
+	        	<input type="text" style="width: 400px" name="rm_twitter_feed_oauth_access_token" value="<?php echo get_option('rm_twitter_feed_oauth_access_token'); ?>" />
+	        </td>
+	        </tr>
+	        <tr valign="top">
+	        <th scope="row">Access Token Secret:</th>
+	        <td>
+	        	<input type="text" style="width: 400px" name="rm_twitter_feed_oauth_access_token_secret" value="<?php echo get_option('rm_twitter_feed_oauth_access_token_secret'); ?>" />
+	        </td>
+	        </tr>
+	       	<tr valign="top">
+	        <th scope="row">Consumer Key:</th>
+	        <td>
+	        	<input type="text" style="width: 400px" name="rm_twitter_feed_consumer_key" value="<?php echo get_option('rm_twitter_feed_consumer_key'); ?>" />
+	        </td>
+	        </tr>
+	        <tr valign="top">
+	        <th scope="row">Consumer Secret:</th>
+	        <td>
+	        	<input type="text" style="width: 400px" name="rm_twitter_feed_consumer_secret" value="<?php echo get_option('rm_twitter_feed_consumer_secret'); ?>" />
+	        </td>
+	        </tr>
+	  
+	         
+	   		 </table>
+
+
+
+			<h3>User Feed</h3>
+			<table class="form-table">
+	       	<tr valign="top">
+	        <th scope="row">Parameters:</th>
+	        <td>
+	        	<input type="text" style="width: 400px" name="rm_twitter_feed_custom" value="<?php echo get_option('rm_twitter_feed_custom'); ?>" />
+	        	<p class="description"><a href="https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline" target="_blank">List of Parameters</a> you can use.<br> Ex: <code>screen_name=RestateMedia&count=5</code></p>
+	        </td>
+	        </tr>
+	  
+	         
+	   		 </table>
+
+	   		 <p>Use the shortcode <code>[twitter_feed]</code> to insert the feed on posts, pages or direct to the template files.</p>
+
+			<?php submit_button(); ?>
+		</form>
+	</div>
+<?php }
+
+// Register Options Page
+add_action('admin_menu', 'rm_twitter_feed');
+function rm_twitter_feed() {  
+    add_options_page("RM - Twitter Feed Options", "RM - Twitter Feed", "manage_options", __FILE__, "rm_twitter_feed_fields"); 
+}  
+
+
+// Register Fields
+add_action( 'admin_init', 'rm_twitter_feed_register_fields' );
+function rm_twitter_feed_register_fields() {
+
+	register_setting( 'rm_twitter_feed_options_fields', 'rm_twitter_feed_custom');
+	register_setting( 'rm_twitter_feed_options_fields', 'rm_twitter_feed_oauth_access_token', 'sanitize_text_field');
+	register_setting( 'rm_twitter_feed_options_fields', 'rm_twitter_feed_oauth_access_token_secret', 'sanitize_text_field');
+	register_setting( 'rm_twitter_feed_options_fields', 'rm_twitter_feed_consumer_key', 'sanitize_text_field');
+	register_setting( 'rm_twitter_feed_options_fields', 'rm_twitter_feed_consumer_secret', 'sanitize_text_field');
+
+}
+
+// Create AJAX url on load 
+add_action( 'init', 'rm_tweets_enqueuer' );
+function rm_tweets_enqueuer() {
+   //wp_register_script( "tweets_script", WP_PLUGIN_URL.'/rm-twitter-feed/tweets_script.js', array('jquery') );
+	wp_register_script( "urlize", WP_PLUGIN_URL.'/rm-twitter-feed/urlize.js', array('jquery') );
+   	wp_localize_script( 'jquery', 'tweetsAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));        
+
+   wp_enqueue_script( 'jquery' );
+   wp_enqueue_script( 'urlize');
+
+}
+
+// Footer Scripts to make de AJAX Call
+add_action('wp_footer', 'rm_footer_scripts', 99);
+function rm_footer_scripts() { ?>
+
+	<script type="text/javascript">
+	jQuery(document).ready( function() {
+
+		var myquery = 'statuses/user_timeline.json?<?php echo get_option('rm_twitter_feed_custom'); ?>';
+
+		//console.log('success!');
+
+		jQuery.ajax({
+	         type : "get",
+	         dataType : "json",
+	         url : tweetsAjax.ajaxurl,
+	         data : {action: "rm_getTweets", myquery: myquery },
+	         success: function(d) {
+	    	    console.log('success!');
+	    	   
+	    	    jQuery.each(d, function(i, object) {
+					//jQuery('.twitter-feed').append('<li><p>' + object.text + '</p></li>');
+					console.log(object);
+					appendTweets(object);
+
+				}); 
+
+	         },
+	         error: function(a, b, c) {
+	         	console.log(a);
+	         	console.log(b);
+	         	console.log(c);
+	         }
+     	});
+
+
+		var twitterFeed = jQuery('#twitter-feed');
+
+     	function appendTweets(object) {
+
+     		var tweet = urlize(object.text, false, false, false, '_blank'),
+				splitTweet = tweet.split(" ");
+
+				for (var i=0;i<splitTweet.length;i++) {
+
+					if (splitTweet[i].search("@") >= 0) {
+						var user = (splitTweet[i]),
+							userLink = '<a target="_blank" href="http://twitter.com/' + user.replace("@", "") + '">' + user +'</a>',
+							tweet = tweet.replace(user, userLink);
+					}
+
+				}
+
+
+     		twitterFeed.append('<li><p>' + tweet + '</p></li>');
+     	}
+
+    });
+	</script>
+
+<?php }
+
+
+// WordPress AJAX Functions
+add_action("wp_ajax_rm_getTweets", "rm_getTweets");
+add_action("wp_ajax_nopriv_rm_getTweets", "rm_getTweets");
+function rm_getTweets() {
+
+	/**
+	 *  Usage:
+	 *  Send the url you want to access url encoded in the url paramater, for example (This is with JS): 
+	 *  /twitter-proxy.php?url='+encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=2')
+	*/
+
+	// The tokens, keys and secrets from the app you created at https://dev.twitter.com/apps
+	$config = array(
+		'oauth_access_token' => get_option('rm_twitter_feed_oauth_access_token'),
+		'oauth_access_token_secret' => get_option('rm_twitter_feed_oauth_access_token_secret'),
+		'consumer_key' => get_option('rm_twitter_feed_consumer_key'),
+		'consumer_secret' => get_option('rm_twitter_feed_consumer_secret'),
+		'use_whitelist' => true, // If you want to only allow some requests to use this script.
+		'base_url' => 'http://api.twitter.com/1.1/',
+		'whitelist' => get_option('rm_twitter_feed_custom')
+	);
+
+	// Only allow certain requests to twitter. Stop randoms using your server as a proxy.
+	$whitelist = array(
+		'statuses/user_timeline.json?' . get_option('rm_twitter_feed_custom') => true
+	);
+
+	/*
+	* Ok, no more config should really be needed. Yay!
+	*/
+
+	// We'll get the URL from $_GET[]. Make sure the url is url encoded, for example encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=10&include_rts=false&exclude_replies=true')
+	if(!isset($_GET['myquery'])){
+		die('No URL set');
+	}
+
+	$url = $_GET['myquery'];
+
+
+	if($config['use_whitelist'] && !isset($whitelist[$url])){
+		die('URL is not authorised');
+	}
+
+	// Figure out the URL parmaters
+	$url_parts = parse_url($url);
+	parse_str($url_parts['query'], $url_arguments);
+
+	$full_url = $config['base_url'].$url; // Url with the query on it.
+	$base_url = $config['base_url'].$url_parts['path']; // Url without the query.
+
+	/**
+	* Code below from http://stackoverflow.com/questions/12916539/simplest-php-example-retrieving-user-timeline-with-twitter-api-version-1-1 by Rivers 
+	* with a few modfications by Mike Rogers to support variables in the URL nicely
+	*/
+
+	function buildBaseString($baseURI, $method, $params) {
+		$r = array();
+		ksort($params);
+		foreach($params as $key=>$value){
+		$r[] = "$key=" . rawurlencode($value);
+		}
+		return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
+	}
+
+	function buildAuthorizationHeader($oauth) {
+		$r = 'Authorization: OAuth ';
+		$values = array();
+		foreach($oauth as $key=>$value)
+		$values[] = "$key=\"" . rawurlencode($value) . "\"";
+		$r .= implode(', ', $values);
+		return $r;
+	}
+
+	// Set up the oauth Authorization array
+	$oauth = array(
+		'oauth_consumer_key' => $config['consumer_key'],
+		'oauth_nonce' => time(),
+		'oauth_signature_method' => 'HMAC-SHA1',
+		'oauth_token' => $config['oauth_access_token'],
+		'oauth_timestamp' => time(),
+		'oauth_version' => '1.0'
+	);
+		
+	$base_info = buildBaseString($base_url, 'GET', array_merge($oauth, $url_arguments));
+	$composite_key = rawurlencode($config['consumer_secret']) . '&' . rawurlencode($config['oauth_access_token_secret']);
+	$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
+	$oauth['oauth_signature'] = $oauth_signature;
+
+	// Make Requests
+	$header = array(
+		buildAuthorizationHeader($oauth), 
+		'Expect:'
+	);
+	$options = array(
+		CURLOPT_HTTPHEADER => $header,
+		//CURLOPT_POSTFIELDS => $postfields,
+		CURLOPT_HEADER => false,
+		CURLOPT_URL => $full_url,
+		CURLOPT_RETURNTRANSFER => true,
+		CURLOPT_SSL_VERIFYPEER => false
+	);
+
+	$feed = curl_init();
+	curl_setopt_array($feed, $options);
+	$result = curl_exec($feed);
+	$info = curl_getinfo($feed);
+	curl_close($feed);
+
+	//Send suitable headers to the end user.
+	if(isset($info['content_type']) && isset($info['size_download'])){
+		header('Content-Type: '.$info['content_type']);
+		header('Content-Length: '.$info['size_download']);
+
+	}
+
+	echo $result;
+}
+
+?>
+var urlize = (function () {
+
+
+// From http://blog.stevenlevithan.com/archives/cross-browser-split
+// modified to not add itself to String.prototype.
+
+/*!
+ * Cross-Browser Split 1.1.1
+ * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
+ * Available under the MIT License
+ * ECMAScript compliant, uniform cross-browser split method
+ */
+
+/**
+ * Splits a string into an array of strings using a regex or string separator. Matches of the
+ * separator are not included in the result array. However, if `separator` is a regex that contains
+ * capturing groups, backreferences are spliced into the result each time `separator` is matched.
+ * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
+ * cross-browser.
+ * @param {String} str String to split.
+ * @param {RegExp|String} separator Regex or string to use for separating the string.
+ * @param {Number} [limit] Maximum number of items to include in the result array.
+ * @returns {Array} Array of substrings.
+ * @example
+ *
+ * // Basic use
+ * split('a b c d', ' ');
+ * // -> ['a', 'b', 'c', 'd']
+ *
+ * // With limit
+ * split('a b c d', ' ', 2);
+ * // -> ['a', 'b']
+ *
+ * // Backreferences in result array
+ * split('..word1 word2..', /([a-z]+)(\d+)/i);
+ * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
+ */
+var split;
+
+// Avoid running twice; that would break the `nativeSplit` reference
+split = split || function (undef) {
+
+    var nativeSplit = String.prototype.split,
+        compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
+        self;
+
+    self = function (str, separator, limit) {
+        // If `separator` is not a regex, use `nativeSplit`
+        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
+            return nativeSplit.call(str, separator, limit);
+        }
+        var output = [],
+            flags = (separator.ignoreCase ? "i" : "") +
+                    (separator.multiline  ? "m" : "") +
+                    (separator.extended   ? "x" : "") + // Proposed for ES6
+                    (separator.sticky     ? "y" : ""), // Firefox 3+
+            lastLastIndex = 0,
+            // Make `global` and avoid `lastIndex` issues by working with a copy
+            separator = new RegExp(separator.source, flags + "g"),
+            separator2, match, lastIndex, lastLength;
+        str += ""; // Type-convert
+        if (!compliantExecNpcg) {
+            // Doesn't need flags gy, but they don't hurt
+            separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
+        }
+        /* Values for `limit`, per the spec:
+         * If undefined: 4294967295 // Math.pow(2, 32) - 1
+         * If 0, Infinity, or NaN: 0
+         * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
+         * If negative number: 4294967296 - Math.floor(Math.abs(limit))
+         * If other: Type-convert, then use the above rules
+         */
+        limit = limit === undef ?
+            -1 >>> 0 : // Math.pow(2, 32) - 1
+            limit >>> 0; // ToUint32(limit)
+        while (match = separator.exec(str)) {
+            // `separator.lastIndex` is not reliable cross-browser
+            lastIndex = match.index + match[0].length;
+            if (lastIndex > lastLastIndex) {
+                output.push(str.slice(lastLastIndex, match.index));
+                // Fix browsers whose `exec` methods don't consistently return `undefined` for
+                // nonparticipating capturing groups
+                if (!compliantExecNpcg && match.length > 1) {
+                    match[0].replace(separator2, function () {
+                        for (var i = 1; i < arguments.length - 2; i++) {
+                            if (arguments[i] === undef) {
+                                match[i] = undef;
+                            }
+                        }
+                    });
+                }
+                if (match.length > 1 && match.index < str.length) {
+                    Array.prototype.push.apply(output, match.slice(1));
+                }
+                lastLength = match[0].length;
+                lastLastIndex = lastIndex;
+                if (output.length >= limit) {
+                    break;
+                }
+            }
+            if (separator.lastIndex === match.index) {
+                separator.lastIndex++; // Avoid an infinite loop
+            }
+        }
+        if (lastLastIndex === str.length) {
+            if (lastLength || !separator.test("")) {
+                output.push("");
+            }
+        } else {
+            output.push(str.slice(lastLastIndex));
+        }
+        return output.length > limit ? output.slice(0, limit) : output;
+    };
+
+    return self;
+
+}();
+
+
+
+
+
+function startswith(string, prefix) {
+    return string.substr(0, prefix.length) == prefix;
+}
+
+function endswith(string, suffix) {
+    return string.substr(string.length - suffix.length, suffix.length) == suffix;
+}
+
+// http://stackoverflow.com/a/7924240/17498
+function occurrences(string, substring) {
+    var n = 0;
+    var pos = 0;
+    while (true) {
+        pos = string.indexOf(substring, pos);
+        if (pos != -1) { 
+	    n++; 
+	    pos += substring.length;
+	} else{
+	    break;
+	}
+    }
+    return n;
+}
+
+var unquoted_percents_re = /%(?![0-9A-Fa-f]{2})/;
+
+// Quotes a URL if it isn't already quoted.
+function smart_urlquote(url) {
+    // XXX: Not handling IDN.
+    // 
+    // An URL is considered unquoted if it contains no % characters or
+    // contains a % not followed by two hexadecimal digits.
+    if (url.indexOf('%') == -1 || url.match(unquoted_percents_re)) {
+	return encodeURI(url);
+    } else {
+	return url;
+    }
+}
+
+var trailing_punctuation_django = ['.', ',', ':', ';'];
+var trailing_punctuation_improved = ['.', ',', ':', ';', '.)'];
+var wrapping_punctuation_django = [['(', ')'], ['<', '>'], ['&lt;', '&gt;']];
+var wrapping_punctuation_improved = [['(', ')'], ['<', '>'], ['&lt;', '&gt;'], 
+				     ['“', '”'], ['‘', '’']];
+var word_split_re_django = /(\s+)/;
+var word_split_re_improved = /([\s<>"]+)/;
+var simple_url_re = /^https?:\/\/\w/;
+var simple_url_2_re = /^www\.|^(?!http)\w[^@]+\.(com|edu|gov|int|mil|net|org)$/;
+var simple_email_re = /^\S+@\S+\.\S+$/;
+
+function htmlescape(html) {
+    return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
+}
+
+function convert_arguments(args) {
+    var options;
+    if (args.length == 2 && typeof(args[1]) == 'object') {
+	options = args[1];
+    } else {
+	options = {nofollow: args[1],
+		   autoescape: args[2],
+		   trim_url_limit: args[3],
+		   target: args[4]};
+    }
+    if (!('django_compatible' in options))
+	options.django_compatible = true;
+    return options;
+}
+
+function urlize(text, options) {
+    options = convert_arguments(arguments);
+    function trim_url(x, limit) {
+	if (limit === undefined)
+	    limit = options.trim_url_limit;
+	if (limit && x.length > limit)
+		return x.substr(0, limit - 3) + '...';
+	return x;
+    }
+    var safe_input = false;
+    var word_split_re = options.django_compatible ? word_split_re_django : word_split_re_improved;
+    var trailing_punctuation = options.django_compatible ? trailing_punctuation_django : trailing_punctuation_improved;
+    var wrapping_punctuation = options.django_compatible ? wrapping_punctuation_django : wrapping_punctuation_improved;
+    var words = split(text, word_split_re);
+    for (var i = 0; i < words.length; i++) { 
+	var word = words[i];
+	var match = undefined;
+	if (word.indexOf('.') != -1 ||
+	    word.indexOf('@') != -1 ||
+	    word.indexOf(':') != -1) {
+	    // Deal with punctuation.
+	    var lead = '';
+	    var middle = word;
+	    var trail = '';
+	    for (var j = 0; j < trailing_punctuation.length; j++) {
+		var punctuation = trailing_punctuation[j];
+		if (endswith(middle, punctuation)) {
+		    middle = middle.substr(0, middle.length - punctuation.length);
+		    trail = punctuation + trail;
+		}
+	    }
+	    for (var j = 0; j < wrapping_punctuation.length; j++) {
+		var opening = wrapping_punctuation[j][0];
+		var closing = wrapping_punctuation[j][1];
+		if (startswith(middle, opening)) {
+		    middle = middle.substr(opening.length);
+		    lead = lead + opening;
+		}
+		// Keep parentheses at the end only if they're balanced.
+		if (endswith(middle, closing) &&
+		    occurrences(middle, closing) == occurrences(middle, opening) + 1) {
+		    middle = middle.substr(0, middle.length - closing.length);
+		    trail = closing + trail;
+		}
+	    }
+
+	    // Make URL we want to point to.
+	    var url = undefined;
+	    var nofollow_attr = options.nofollow ? ' rel="nofollow"' : '';
+	    var target_attr = options.target ? ' target="' + options.target + '"' : '';
+	    
+	    if (middle.match(simple_url_re))
+		url = smart_urlquote(middle);
+	    else if (middle.match(simple_url_2_re))
+		url = smart_urlquote('http://' + middle);
+	    else if (middle.indexOf(':') == -1 && middle.match(simple_email_re)) {
+		// XXX: Not handling IDN.
+		url = 'mailto:' + middle;
+		nofollow_attr = '';
+	    }
+
+	    // Make link.
+	    if (url) {
+		var trimmed = trim_url(middle);
+		if (options.autoescape) {
+		    // XXX: Assuming autoscape == false
+		    lead = htmlescape(lead);
+		    trail = htmlescape(trail);
+		    url = htmlescape(url);
+		    trimmed = htmlescape(trimmed);
+		}
+		middle = '<a href="' + url + '"' + nofollow_attr + target_attr + '>' + trimmed + '</a>';
+		words[i] = lead + middle + trail;
+	    } else {
+		if (safe_input) {
+		    // Do nothing, as we have no mark_safe.
+		} else if (options.autoescape) {
+		    words[i] = htmlescape(word);
+		}
+	    }
+	} else if (safe_input) {
+	    // Do nothing, as we have no mark_safe.
+	} else if (options.autoescape) {
+	    words[i] = htmlescape(word);
+	}
+    }
+    return words.join('');
+}
+
+urlize.test = {};
+urlize.test.split = split;
+urlize.test.convert_arguments = convert_arguments;
+
+return urlize;
+})();