<?php
/**
* Abraham Williams (abraham@abrah.am) http://abrah.am
*
* @category Core
* @package XPoster
* @author Joe Dolson
* @license GPLv2 or later
* @link https://www.joedolson.com/wp-to-twitter/
*
* The first PHP Library to support WPOAuth for X.com's REST API.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require_once 'class-wp-oauth.php';
if ( ! class_exists( 'Wpt_TwitterOAuth' ) ) {
/**
* X.com WPOAuth class
*/
#[AllowDynamicProperties]
class Wpt_TwitterOAuth {
/**
* Contains the last HTTP status code returned
*
* @var status code
*/
public $http_code;
/**
* Contains the last API call.
*
* @var $url
*/
public $url;
/**
* Set up the API root URL.
*
* @var $host
*/
public $host = 'https://api.twitter.com/1.1/';
/**
* Set timeout default.
*
* @var $format
*/
public $format = 'json';
/**
* Decode returned json data.
*
* @var $decode_json
*/
public $decode_json = false;
/**
* Contains the last API call
*
* @var $last_api_call
*/
private $last_api_call;
/**
* Contains the header
*
* @var $http_header
*/
public $http_header;
/**
* Contains the body
*
* @var $body
*/
public $body;
/**
* Set API URLS
*
* @return access token endpoint.
*/
protected function access_token_url() {
return 'https://api.twitter.com/oauth/access_token';
}
/**
* Set authentication URL.
*
* @return authentication endpoint.
*/
protected function authenticate_url() {
return 'https://api.twitter.com/oauth/authenticate';
}
/**
* Set authorization URL.
*
* @return authorization endpoint.
*/
protected function authorize_url() {
return 'https://api.twitter.com/oauth/authorize';
}
/**
* Set request Token URL.
*
* @return request token ednpoint.
*/
protected function request_token_url() {
return 'https://api.twitter.com/oauth/request_token';
}
/**
* Debug helpers
*
* @return last query's http code response.
*/
public function last_status_code() {
return $this->http_code;
}
/**
* Return last API call.
*
* @return last query API call.
*/
public function last_api_call() {
return $this->last_api_call;
}
/**
* Construct TwitterWPOAuth object
*
* @param string $consumer_key Consumer key.
* @param string $consumer_secret Consumer secret.
* @param string $wp_oauth_token Token.
* @param string $wp_oauth_token_secret Token secret.
*/
public function __construct( $consumer_key, $consumer_secret, $wp_oauth_token = null, $wp_oauth_token_secret = null ) {
$this->sha1_method = new WPOAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new WPOAuthConsumer( $consumer_key, $consumer_secret );
if ( ! empty( $wp_oauth_token ) && ! empty( $wp_oauth_token_secret ) ) {
$this->token = new WPOAuthConsumer( $wp_oauth_token, $wp_oauth_token_secret );
} else {
$this->token = null;
}
}
/**
* Get a request_token from Xcom
*
* @returns a key/value array containing WPOAuth_token and WPOAuth_token_secret
*/
public function get_request_token() {
$r = $this->wp_oauth_request( $this->request_token_url() );
$token = $this->wp_oauth_parse_response( $r );
$this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
return $token;
}
/**
* Parse a URL-encoded WPOAuth response
*
* @param string $response_string String from response.
*
* @return a key/value array
*/
public function wp_oauth_parse_response( $response_string ) {
$r = array();
foreach ( explode( '&', $response_string ) as $param ) {
$pair = explode( '=', $param, 2 );
if ( count( $pair ) !== 2 ) {
continue;
}
$r[ urldecode( $pair[0] ) ] = urldecode( $pair[1] );
}
return $r;
}
/**
* Get the authorize URL
*
* @param array $token Token array.
*
* @returns a string
*/
public function getauthorize_url( $token ) {
if ( is_array( $token ) ) {
$token = $token['WPOAuth_token'];
}
return $this->authorize_url() . '?WPOAuth_token=' . $token;
}
/**
* Get the authenticate URL
*
* @param array $token Token array.
*
* @returns a string
*/
public function getauthenticate_url( $token ) {
if ( is_array( $token ) ) {
$token = $token['WPOAuth_token'];
}
return $this->authenticate_url() . '?WPOAuth_token=' . $token;
}
/**
* Exchange the request token and secret for an access token and secret, to sign API calls.
*
* @param array $token Token array.
*
* @returns array("WPOAuth_token" => the access token, "WPOAuth_token_secret" => the access secret)
*/
public function get_access_token( $token = null ) {
$r = $this->wp_oauth_request( $this->access_token_url() );
$token = $this->wp_oauth_parse_response( $r );
$this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
return $token;
}
/**
* Wrapper for POST requests
*
* @param string $url URL.
* @param array $parameters Request params.
*
* @return array decoded response.
*/
public function post( $url, $parameters = array() ) {
$response = $this->wp_oauth_request( $url, $parameters, 'POST' );
if ( 'json' === $this->format && $this->decode_json ) {
return json_decode( $response );
}
return $response;
}
/**
* Wrapper for MEDIA requests
*
* @param string $url URL.
* @param array $parameters Request params.
*
* @return decoded response.
*/
public function media( $url, $parameters = array() ) {
$response = $this->wp_oauth_request( $url, $parameters, 'MEDIA' );
if ( 'json' === $this->format && $this->decode_json ) {
return json_decode( $response );
}
return $response;
}
/**
* Wrapper for GET requests
*
* @param string $url URL.
* @param array $parameters Request params.
*
* @return decoded response.
*/
public function get( $url, $parameters = array() ) {
$response = $this->wp_oauth_request( $url, $parameters, 'GET' );
if ( 'json' === $this->format && $this->decode_json ) {
return json_decode( $response );
}
return $response;
}
/**
* Handles a status update that includes an image.
*
* @param string $url Target URL.
* @param array $args Array of arguments to send.
*
* @return boolean
*/
public function handle_media_request( $url, $args = array() ) {
// Load tmhOAuth for Media uploads only when needed: https://github.com/themattharris/tmhOAuth.
// It's not possible to upload media using WP_HTTP, so this needs to use cURL.
if ( ! class_exists( 'tmhOAuth' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'class-tmhoauth.php';
}
$auth = $args['auth'];
if ( ! $auth ) {
$ack = get_option( 'app_consumer_key' );
$acs = get_option( 'app_consumer_secret' );
$ot = get_option( 'oauth_token' );
$ots = get_option( 'oauth_token_secret' );
} else {
$ack = get_user_meta( $auth, 'app_consumer_key', true );
$acs = get_user_meta( $auth, 'app_consumer_secret', true );
$ot = get_user_meta( $auth, 'oauth_token', true );
$ots = get_user_meta( $auth, 'oauth_token_secret', true );
}
$connect = array(
'consumer_key' => $ack,
'consumer_secret' => $acs,
'user_token' => $ot,
'user_secret' => $ots,
);
$tmh_oauth = new TmhOAuth( $connect );
$media_id = $args['media'];
$attachment = $args['attachment'];
$alt_text = get_post_meta( $attachment, '_wp_attachment_image_alt', true );
/**
* Add alt attributes to uploaded images.
*
* @hook wpt_uploaded_image_alt
*
* @param {string} $alt_text Text stored in media library as alt.
* @param {int} $attachment Attachment ID.
*
* @return {string}
*/
$alt_text = apply_filters( 'wpt_uploaded_image_alt', $alt_text, $attachment );
if ( '' !== $alt_text ) {
$image_alt = json_encode(
array(
'media_id' => $media_id,
'alt_text' => array(
'text' => $alt_text,
),
)
);
$tmh_oauth->request(
'POST',
$url,
$image_alt,
true,
true,
array(
'content-type' => 'application/json',
)
);
}
return $media_id;
}
/**
* Format and sign an WPOAuth / API request
*
* @param string $url Target URL.
* @param array $args Arguments for signing.
* @param string $method Method type.
*
* @return string|array JSON encoded request or array.
*/
public function wp_oauth_request( $url, $args = array(), $method = null ) {
// Handle media requests using tmhOAuth library.
if ( 'MEDIA' === $method ) {
return $this->handle_media_request( $url, $args );
}
if ( empty( $method ) ) {
$method = empty( $args ) ? 'GET' : 'POST';
}
$req = WP_Oauth_Request::from_consumer_and_token( $this->consumer, $this->token, $method, $url, $args );
$req->sign_request( $this->sha1_method, $this->consumer, $this->token );
$response = false;
$url = null;
switch ( $method ) {
case 'GET':
$url = $req->to_url();
$response = wp_remote_get( $url );
break;
case 'POST':
// TODO: if JSON, need to authenticate, pass bearer authentication as header in query.
// TODO: add content-type when JSON.
$url = $req->get_normalized_http_url();
$args = wp_parse_args( $req->to_postdata() );
$response = wp_remote_post(
$url,
array(
'body' => $args,
'timeout' => 30,
)
);
break;
}
if ( is_wp_error( $response ) ) {
return false;
}
$this->http_code = $response['response']['code'];
$this->body = json_decode( $response['body'] );
$this->last_api_call = $url;
$this->format = 'json';
$this->http_header = $response['headers'];
return $response['body'];
}
}
}