WP to Twitter - Version 3.3.3

Version Description

  • Removed: upgrade paths from version 2.4.x
  • Removed: support for YOURLS version 1.3
  • Removed: support for Twitter Friendly Links (plug-in not updated in 8 years)
  • Removed: Ability to enable the Goo.gl URL shortener (see: https://developers.google.com/url-shortener/)
  • Removed: fallback functions required for PHP 4 support.
  • Add 'show images' as option in feeds.
  • Support for alt attributes displayed in Feeds
  • Improved URL generation to link to searched Tweets.
  • Improve parsing of URLs in Tweets.
  • Don't save URLs if no shortener used or shortener returns no value.
  • Option to ignore stored URLs when sending Tweets.
  • Code now conforms with WordPress PHP standards with the exception of four deprecated functions.
Download this release

Release Info

Developer joedolson
Plugin Icon 128x128 WP to Twitter
Version 3.3.3
Comparing to
See all releases

Code changes from version 3.3.2 to 3.3.3

{tmhOAuth → classes}/cacert.pem RENAMED
File without changes
tmhOAuth/tmhOAuth.php → classes/class-tmhoauth.php RENAMED
@@ -1,7 +1,19 @@
1
  <?php
 
 
 
 
 
 
 
 
 
2
 
 
 
 
3
  /**
4
- * tmhOAuth
5
  *
6
  * An OAuth 1.0A library written in PHP.
7
  * The library supports file uploading using multipart/form as well as general
@@ -9,18 +21,24 @@
9
  *
10
  * @author themattharris
11
  * @version 0.7.5
 
12
  *
13
  * 20 February 2013
14
  */
15
- class tmhOAuth {
16
  const VERSION = '0.7.5';
17
 
 
 
 
 
 
18
  var $response = array();
19
 
20
  /**
21
- * Creates a new tmhOAuth object
22
  *
23
- * @param string $config , the configuration to use for this request
24
  *
25
  * @return void
26
  */
@@ -30,13 +48,13 @@ class tmhOAuth {
30
  $this->auto_fixed_time = false;
31
  $this->buffer = null;
32
 
33
- // default configuration options
34
  $this->config = array_merge(
35
  array(
36
- // leave 'user_agent' blank for default, otherwise set this to
37
- // something that clearly identifies your app
38
  'user_agent' => '',
39
- // default timezone for requests
40
  'timezone' => 'UTC',
41
  'use_ssl' => true,
42
  'host' => 'api.twitter.com',
@@ -46,41 +64,38 @@ class tmhOAuth {
46
  'user_secret' => '',
47
  'force_nonce' => false,
48
  'nonce' => false,
49
- // used for checking signatures. leave as false for auto
50
  'force_timestamp' => false,
51
  'timestamp' => false,
52
- // used for checking signatures. leave as false for auto
53
-
54
- // oauth signing variables that are not dynamic
55
  'oauth_version' => '1.0',
56
  'oauth_signature_method' => 'HMAC-SHA1',
57
- // you probably don't want to change any of these curl values
58
  'curl_connecttimeout' => 30,
59
  'curl_timeout' => 10,
60
  // for security this should always be set to 2.
61
  'curl_ssl_verifyhost' => 2,
62
  // for security this should always be set to true.
63
  'curl_ssl_verifypeer' => true,
64
- // you can get the latest cacert.pem from here http://curl.haxx.se/ca/cacert.pem
65
  'curl_cainfo' => dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'cacert.pem',
66
  'curl_capath' => dirname( __FILE__ ),
67
  'curl_followlocation' => false,
68
- // whether to follow redirects or not
69
-
70
- // support for proxy servers
71
  'curl_proxy' => false,
72
- // really you don't want to use this if you are using streaming
73
  'curl_proxyuserpwd' => false,
74
- // format username:password for proxy, if required
75
  'curl_encoding' => '',
76
- // leave blank for all supported formats, else use gzip, deflate, identity
77
-
78
- // streaming API
79
  'is_streaming' => false,
80
  'streaming_eol' => "\r\n",
81
  'streaming_metrics_interval' => 60,
82
  // header or querystring. You should always use header!
83
- // this is just to help me debug other developers implementations
84
  'as_header' => true,
85
  'debug' => false,
86
  ),
@@ -116,13 +131,13 @@ class tmhOAuth {
116
  * Generates a random OAuth nonce.
117
  * If 'force_nonce' is true a nonce is not generated and the value in the configuration will be retained.
118
  *
119
- * @param string $length how many characters the nonce should be before MD5 hashing. default 12
120
- * @param string $include_time whether to include time at the beginning of the nonce. default true
121
  *
122
  * @return void value is stored to the config array class variable
123
  */
124
  private function create_nonce( $length = 12, $include_time = true ) {
125
- if ( $this->config['force_nonce'] == false ) {
126
  $sequence = array_merge( range( 0, 9 ), range( 'A', 'Z' ), range( 'a', 'z' ) );
127
  $length = $length > count( $sequence ) ? count( $sequence ) : $length;
128
  shuffle( $sequence );
@@ -139,21 +154,21 @@ class tmhOAuth {
139
  * @return void value is stored to the config array class variable
140
  */
141
  private function create_timestamp() {
142
- $this->config['timestamp'] = ( $this->config['force_timestamp'] == false ? time() : $this->config['timestamp'] );
143
  }
144
 
145
  /**
146
  * Encodes the string or array passed in a way compatible with OAuth.
147
  * If an array is passed each array value will will be encoded.
148
  *
149
- * @param mixed $data the scalar or array to encode
150
  *
151
  * @return $data encoded in a way compatible with OAuth
152
  */
153
  private function safe_encode( $data ) {
154
  if ( is_array( $data ) ) {
155
  return array_map( array( $this, 'safe_encode' ), $data );
156
- } else if ( is_scalar( $data ) ) {
157
  return str_ireplace(
158
  array( '+', '%7E' ),
159
  array( ' ', '~' ),
@@ -168,14 +183,14 @@ class tmhOAuth {
168
  * Decodes the string or array from it's URL encoded form
169
  * If an array is passed each array value will will be decoded.
170
  *
171
- * @param mixed $data the scalar or array to decode
172
  *
173
  * @return string $data decoded from the URL encoded form
174
  */
175
  private function safe_decode( $data ) {
176
  if ( is_array( $data ) ) {
177
  return array_map( array( $this, 'safe_decode' ), $data );
178
- } else if ( is_scalar( $data ) ) {
179
  return rawurldecode( $data );
180
  } else {
181
  return '';
@@ -196,12 +211,12 @@ class tmhOAuth {
196
  'oauth_signature_method' => $this->config['oauth_signature_method'],
197
  );
198
 
199
- // include the user token if it exists
200
  if ( $this->config['user_token'] ) {
201
  $defaults['oauth_token'] = $this->config['user_token'];
202
  }
203
 
204
- // safely encode
205
  foreach ( $defaults as $k => $v ) {
206
  $_defaults[ $this->safe_encode( $k ) ] = $this->safe_encode( $v );
207
  }
@@ -212,7 +227,7 @@ class tmhOAuth {
212
  /**
213
  * Extracts and decodes OAuth parameters from the passed string
214
  *
215
- * @param string $body the response body from an OAuth flow method
216
  *
217
  * @return array the response body safely decoded to an array of key => values
218
  */
@@ -233,7 +248,7 @@ class tmhOAuth {
233
  * Prepares the HTTP method for use in the base string by converting it to
234
  * uppercase.
235
  *
236
- * @param string $method an HTTP method such as GET or POST
237
  *
238
  * @return void value is stored to the class variable 'method'
239
  */
@@ -247,7 +262,7 @@ class tmhOAuth {
247
  *
248
  * Ref: 3.4.1.2
249
  *
250
- * @param string $url the request URL
251
  *
252
  * @return void value is stored to the class variable 'url'
253
  */
@@ -259,17 +274,17 @@ class tmhOAuth {
259
  $host = $parts['host'];
260
  $path = isset( $parts['path'] ) ? $parts['path'] : false;
261
 
262
- $port or $port = ( $scheme == 'https' ) ? '443' : '80';
 
 
263
 
264
- if ( ( $scheme == 'https' && $port != '443' )
265
- || ( $scheme == 'http' && $port != '80' )
266
- ) {
267
  $host = "$host:$port";
268
  }
269
 
270
- // the scheme and host MUST be lowercase
271
  $this->url = strtolower( "$scheme://$host" );
272
- // but not the path
273
  $this->url .= $path;
274
  }
275
 
@@ -278,31 +293,31 @@ class tmhOAuth {
278
  * Multipart parameters are ignored as they are not defined in the specification,
279
  * all other types of parameter are encoded for compatibility with OAuth.
280
  *
281
- * @param array $params the parameters for the request
282
  *
283
  * @return void prepared values are stored in the class variable 'signing_params'
284
  */
285
  private function prepare_params( $params ) {
286
- // do not encode multipart parameters, leave them alone
287
  if ( $this->config['multipart'] ) {
288
  $this->request_params = $params;
289
  $params = array();
290
  }
291
 
292
- // signing parameters are request parameters + OAuth default parameters
293
  $this->signing_params = array_merge( $this->get_defaults(), (array) $params );
294
 
295
- // Remove oauth_signature if present
296
- // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
297
  if ( isset( $this->signing_params['oauth_signature'] ) ) {
298
  unset( $this->signing_params['oauth_signature'] );
299
  }
300
 
301
  // Parameters are sorted by name, using lexicographical byte value ordering.
302
- // Ref: Spec: 9.1.1 (1)
303
  uksort( $this->signing_params, 'strcmp' );
304
 
305
- // encode. Also sort the signed parameters from the POST parameters
306
  foreach ( $this->signing_params as $k => $v ) {
307
  $k = $this->safe_encode( $k );
308
 
@@ -315,7 +330,7 @@ class tmhOAuth {
315
  $kv[] = "{$k}={$v}";
316
  }
317
 
318
- // auth params = the default oauth params which are present in our collection of signing params
319
  $this->auth_params = array_intersect_key( $this->get_defaults(), $_signing_params );
320
  if ( isset( $_signing_params['oauth_callback'] ) ) {
321
  $this->auth_params['oauth_callback'] = $_signing_params['oauth_callback'];
@@ -327,12 +342,12 @@ class tmhOAuth {
327
  unset( $_signing_params['oauth_verifier'] );
328
  }
329
 
330
- // request_params is already set if we're doing multipart, if not we need to set them now
331
  if ( ! $this->config['multipart'] ) {
332
  $this->request_params = array_diff_key( $_signing_params, $this->get_defaults() );
333
  }
334
 
335
- // create the parameter part of the base string
336
  $this->signing_params = implode( '&', $kv );
337
  }
338
 
@@ -354,9 +369,9 @@ class tmhOAuth {
354
  private function prepare_base_string() {
355
  $url = $this->url;
356
 
357
- # if the host header is set we need to rewrite the basestring to use
358
- # that, instead of the request host. otherwise the signature won't match
359
- # on the server side
360
  if ( ! empty( $this->custom_headers['Host'] ) ) {
361
  $url = str_ireplace(
362
  $this->config['host'],
@@ -368,7 +383,7 @@ class tmhOAuth {
368
  $base = array(
369
  $this->method,
370
  $url,
371
- $this->signing_params
372
  );
373
  $this->base_string = implode( '&', $this->safe_encode( $base ) );
374
  }
@@ -399,9 +414,9 @@ class tmhOAuth {
399
  * Signs the request and adds the OAuth signature. This runs all the request
400
  * parameter preparation methods.
401
  *
402
- * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
403
- * @param string $url the request URL without query string parameters
404
- * @param array $params the request parameters as an array of key=value pairs
405
  * @param string $useauth whether to use authentication when making the request.
406
  *
407
  * @return void
@@ -411,7 +426,7 @@ class tmhOAuth {
411
  $this->prepare_url( $url );
412
  $this->prepare_params( $params );
413
 
414
- // we don't sign anything is we're not using auth
415
  if ( $useauth ) {
416
  $this->prepare_base_string();
417
  $this->prepare_signing_key();
@@ -420,7 +435,9 @@ class tmhOAuth {
420
  base64_encode(
421
  hash_hmac(
422
  'sha1', $this->base_string, $this->signing_key, true
423
- ) ) );
 
 
424
 
425
  $this->prepare_auth_header();
426
  }
@@ -430,17 +447,17 @@ class tmhOAuth {
430
  * Make an HTTP request using this library. This method doesn't return anything.
431
  * Instead the response should be inspected directly.
432
  *
433
- * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
434
- * @param string $url the request URL without query string parameters
435
- * @param array $params the request parameters as an array of key=value pairs. Default empty array
436
- * @param string $useauth whether to use authentication when making the request. Default true
437
- * @param string $multipart whether this request contains multipart data. Default false
438
- * @param array $headers any custom headers to send with the request. Default empty array
439
  *
440
  * @return int the http response code for the request. 0 is returned if a connection could not be made
441
  */
442
  public function request( $method, $url, $params = array(), $useauth = true, $multipart = false, $headers = array() ) {
443
- // reset the request headers (we don't want to reuse them)
444
  $this->headers = array();
445
  $this->custom_headers = $headers;
446
 
@@ -462,15 +479,14 @@ class tmhOAuth {
462
  * Make a long poll HTTP request using this library. This method is
463
  * different to the other request methods as it isn't supposed to disconnect
464
  *
465
- * Using this method expects a callback which will receive the streaming
466
- * responses.
467
  *
468
- * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
469
- * @param string $url the request URL without query string parameters
470
- * @param array $params the request parameters as an array of key=value pairs
471
  * @param string $callback the callback function to stream the buffer to.
472
  *
473
- * @return void
474
  */
475
  public function streaming_request( $method, $url, $params = array(), $callback = '' ) {
476
  if ( ! empty( $callback ) ) {
@@ -513,8 +529,8 @@ class tmhOAuth {
513
  /**
514
  * Utility function to create the request URL in the requested format
515
  *
516
- * @param string $request the API method without extension
517
- * @param string $format the format of the response. Default json. Set to an empty string to exclude the format
518
  *
519
  * @return string the concatenation of the host, API version, API method and format
520
  */
@@ -522,7 +538,7 @@ class tmhOAuth {
522
  $format = strlen( $format ) > 0 ? ".$format" : '';
523
  $proto = $this->config['use_ssl'] ? 'https:/' : 'http:/';
524
 
525
- // backwards compatibility with v0.1
526
  if ( isset( $this->config['v'] ) ) {
527
  $this->config['host'] = $this->config['host'] . '/' . $this->config['v'];
528
  }
@@ -537,19 +553,19 @@ class tmhOAuth {
537
  return implode( '/', array(
538
  $proto,
539
  $this->config['host'],
540
- $request . $format
541
  ) );
542
  }
543
 
544
  /**
545
  * Public access to the private safe decode/encode methods
546
  *
547
- * @param string $text the text to transform
548
- * @param string $mode the transformation mode. either encode or decode
549
  *
550
  * @return string $text transformed by the given $mode
551
  */
552
- public function transformText( $text, $mode = 'encode' ) {
553
  return $this->{"safe_$mode"}( $text );
554
  }
555
 
@@ -557,12 +573,12 @@ class tmhOAuth {
557
  * Utility function to parse the returned curl headers and store them in the
558
  * class array variable.
559
  *
560
- * @param object $ch curl handle
561
- * @param string $header the response headers
562
  *
563
  * @return string the length of the header
564
  */
565
- private function curlHeader( $ch, $header ) {
566
  $this->response['raw'] .= $header;
567
 
568
  list( $key, $value ) = array_pad( explode( ':', $header, 2 ), 2, null );
@@ -589,14 +605,14 @@ class tmhOAuth {
589
  *
590
  * This function calls the previously defined streaming callback method.
591
  *
592
- * @param object $ch curl handle
593
- * @param string $data the current curl buffer
594
  *
595
  * @return int the length of the data string processed in this function
596
  */
597
- private function curlWrite( $ch, $data ) {
598
  $l = strlen( $data );
599
- if ( strpos( $data, $this->config['streaming_eol'] ) === false ) {
600
  $this->buffer .= $data;
601
 
602
  return $l;
@@ -631,23 +647,23 @@ class tmhOAuth {
631
  * Makes a curl request. Takes no parameters as all should have been prepared
632
  * by the request method
633
  *
634
- * the response data is stored in the class variable 'response'
635
  *
636
  * @return int the http response code for the request. 0 is returned if a connection could not be made
637
  */
638
  private function curlit() {
639
  $this->response['raw'] = '';
640
 
641
- // method handling
642
  switch ( $this->method ) {
643
  case 'POST':
644
  break;
645
  default:
646
- // GET, DELETE request so convert the parameters to a querystring
647
  if ( ! empty( $this->request_params ) ) {
648
  foreach ( $this->request_params as $k => $v ) {
649
  // Multipart params haven't been encoded yet.
650
- // Not sure why you would do a multipart GET but anyway, here's the support for it
651
  if ( $this->config['multipart'] ) {
652
  $params[] = $this->safe_encode( $k ) . '=' . $this->safe_encode( $v );
653
  } else {
@@ -661,7 +677,7 @@ class tmhOAuth {
661
  break;
662
  }
663
 
664
- // configure curl
665
  $c = curl_init();
666
  curl_setopt_array( $c, array(
667
  CURLOPT_USERAGENT => $this->config['user_agent'],
@@ -674,29 +690,29 @@ class tmhOAuth {
674
  CURLOPT_PROXY => $this->config['curl_proxy'],
675
  CURLOPT_ENCODING => $this->config['curl_encoding'],
676
  CURLOPT_URL => $this->url,
677
- // process the headers
678
- CURLOPT_HEADERFUNCTION => array( $this, 'curlHeader' ),
679
  CURLOPT_HEADER => false,
680
  CURLINFO_HEADER_OUT => true,
681
  ) );
682
 
683
- if ( $this->config['curl_cainfo'] !== false ) {
684
  curl_setopt( $c, CURLOPT_CAINFO, $this->config['curl_cainfo'] );
685
  }
686
 
687
- if ( $this->config['curl_capath'] !== false ) {
688
  curl_setopt( $c, CURLOPT_CAPATH, $this->config['curl_capath'] );
689
  }
690
 
691
- if ( $this->config['curl_proxyuserpwd'] !== false ) {
692
  curl_setopt( $c, CURLOPT_PROXYUSERPWD, $this->config['curl_proxyuserpwd'] );
693
  }
694
 
695
  if ( $this->config['is_streaming'] ) {
696
- // process the body
697
  $this->response['content-length'] = 0;
698
  curl_setopt( $c, CURLOPT_TIMEOUT, 0 );
699
- curl_setopt( $c, CURLOPT_WRITEFUNCTION, array( $this, 'curlWrite' ) );
700
  }
701
 
702
  switch ( $this->method ) {
@@ -711,7 +727,7 @@ class tmhOAuth {
711
  }
712
 
713
  if ( ! empty( $this->request_params ) ) {
714
- // if not doing multipart we need to implode the parameters
715
  if ( ! $this->config['multipart'] ) {
716
  foreach ( $this->request_params as $k => $v ) {
717
  $ps[] = "{$k}={$v}";
@@ -731,8 +747,8 @@ class tmhOAuth {
731
  if ( isset( $this->config['prevent_request'] ) && ( true == $this->config['prevent_request'] ) ) {
732
  return 0;
733
  }
734
-
735
- // do it!
736
  $response = curl_exec( $c );
737
  $code = curl_getinfo( $c, CURLINFO_HTTP_CODE );
738
  $info = curl_getinfo( $c );
@@ -740,7 +756,7 @@ class tmhOAuth {
740
  $errno = curl_errno( $c );
741
  curl_close( $c );
742
 
743
- // store the response
744
  $this->response['code'] = $code;
745
  $this->response['response'] = $response;
746
  $this->response['info'] = $info;
@@ -754,4 +770,4 @@ class tmhOAuth {
754
 
755
  return $code;
756
  }
757
- }
1
  <?php
2
+ /**
3
+ * TmhOAuth
4
+ *
5
+ * @category OAuth
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
 
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
  /**
16
+ * OAuth / tmhOAuth
17
  *
18
  * An OAuth 1.0A library written in PHP.
19
  * The library supports file uploading using multipart/form as well as general
21
  *
22
  * @author themattharris
23
  * @version 0.7.5
24
+ * @link https://github.com/themattharris/tmhOAuth
25
  *
26
  * 20 February 2013
27
  */
28
+ class TmhOAuth {
29
  const VERSION = '0.7.5';
30
 
31
+ /**
32
+ * The response from Twitter.
33
+ *
34
+ * @var $response
35
+ */
36
  var $response = array();
37
 
38
  /**
39
+ * Creates a new TmhOAuth object
40
  *
41
+ * @param array $config , the configuration to use for this request.
42
  *
43
  * @return void
44
  */
48
  $this->auto_fixed_time = false;
49
  $this->buffer = null;
50
 
51
+ // default configuration options.
52
  $this->config = array_merge(
53
  array(
54
+ // leave 'user_agent' blank for default, otherwise set this to.
55
+ // something that clearly identifies your app.
56
  'user_agent' => '',
57
+ // default timezone for requests.
58
  'timezone' => 'UTC',
59
  'use_ssl' => true,
60
  'host' => 'api.twitter.com',
64
  'user_secret' => '',
65
  'force_nonce' => false,
66
  'nonce' => false,
67
+ // used for checking signatures. leave as false for auto.
68
  'force_timestamp' => false,
69
  'timestamp' => false,
70
+ // used for checking signatures. leave as false for auto.
71
+ // oauth signing variables that are not dynamic.
 
72
  'oauth_version' => '1.0',
73
  'oauth_signature_method' => 'HMAC-SHA1',
74
+ // you probably don't want to change any of these curl values.
75
  'curl_connecttimeout' => 30,
76
  'curl_timeout' => 10,
77
  // for security this should always be set to 2.
78
  'curl_ssl_verifyhost' => 2,
79
  // for security this should always be set to true.
80
  'curl_ssl_verifypeer' => true,
81
+ // you can get the latest cacert.pem from here http://curl.haxx.se/ca/cacert.pem.
82
  'curl_cainfo' => dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'cacert.pem',
83
  'curl_capath' => dirname( __FILE__ ),
84
  'curl_followlocation' => false,
85
+ // whether to follow redirects or not.
86
+ // support for proxy servers.
 
87
  'curl_proxy' => false,
88
+ // really you don't want to use this if you are using streaming.
89
  'curl_proxyuserpwd' => false,
90
+ // format username:password for proxy, if required.
91
  'curl_encoding' => '',
92
+ // leave blank for all supported formats, else use gzip, deflate, identity.
93
+ // streaming API.
 
94
  'is_streaming' => false,
95
  'streaming_eol' => "\r\n",
96
  'streaming_metrics_interval' => 60,
97
  // header or querystring. You should always use header!
98
+ // this is just to help me debug other developers implementations.
99
  'as_header' => true,
100
  'debug' => false,
101
  ),
131
  * Generates a random OAuth nonce.
132
  * If 'force_nonce' is true a nonce is not generated and the value in the configuration will be retained.
133
  *
134
+ * @param string $length how many characters the nonce should be before MD5 hashing. default 12.
135
+ * @param string $include_time whether to include time at the beginning of the nonce. default true.
136
  *
137
  * @return void value is stored to the config array class variable
138
  */
139
  private function create_nonce( $length = 12, $include_time = true ) {
140
+ if ( false == $this->config['force_nonce'] ) {
141
  $sequence = array_merge( range( 0, 9 ), range( 'A', 'Z' ), range( 'a', 'z' ) );
142
  $length = $length > count( $sequence ) ? count( $sequence ) : $length;
143
  shuffle( $sequence );
154
  * @return void value is stored to the config array class variable
155
  */
156
  private function create_timestamp() {
157
+ $this->config['timestamp'] = ( false == $this->config['force_timestamp'] ? time() : $this->config['timestamp'] );
158
  }
159
 
160
  /**
161
  * Encodes the string or array passed in a way compatible with OAuth.
162
  * If an array is passed each array value will will be encoded.
163
  *
164
+ * @param mixed $data the scalar or array to encode.
165
  *
166
  * @return $data encoded in a way compatible with OAuth
167
  */
168
  private function safe_encode( $data ) {
169
  if ( is_array( $data ) ) {
170
  return array_map( array( $this, 'safe_encode' ), $data );
171
+ } elseif ( is_scalar( $data ) ) {
172
  return str_ireplace(
173
  array( '+', '%7E' ),
174
  array( ' ', '~' ),
183
  * Decodes the string or array from it's URL encoded form
184
  * If an array is passed each array value will will be decoded.
185
  *
186
+ * @param mixed $data the scalar or array to decode.
187
  *
188
  * @return string $data decoded from the URL encoded form
189
  */
190
  private function safe_decode( $data ) {
191
  if ( is_array( $data ) ) {
192
  return array_map( array( $this, 'safe_decode' ), $data );
193
+ } elseif ( is_scalar( $data ) ) {
194
  return rawurldecode( $data );
195
  } else {
196
  return '';
211
  'oauth_signature_method' => $this->config['oauth_signature_method'],
212
  );
213
 
214
+ // include the user token if it exists.
215
  if ( $this->config['user_token'] ) {
216
  $defaults['oauth_token'] = $this->config['user_token'];
217
  }
218
 
219
+ // safely encode.
220
  foreach ( $defaults as $k => $v ) {
221
  $_defaults[ $this->safe_encode( $k ) ] = $this->safe_encode( $v );
222
  }
227
  /**
228
  * Extracts and decodes OAuth parameters from the passed string
229
  *
230
+ * @param string $body the response body from an OAuth flow method.
231
  *
232
  * @return array the response body safely decoded to an array of key => values
233
  */
248
  * Prepares the HTTP method for use in the base string by converting it to
249
  * uppercase.
250
  *
251
+ * @param string $method an HTTP method such as GET or POST.
252
  *
253
  * @return void value is stored to the class variable 'method'
254
  */
262
  *
263
  * Ref: 3.4.1.2
264
  *
265
+ * @param string $url the request URL.
266
  *
267
  * @return void value is stored to the class variable 'url'
268
  */
274
  $host = $parts['host'];
275
  $path = isset( $parts['path'] ) ? $parts['path'] : false;
276
 
277
+ if ( ! $port ) {
278
+ $port = ( 'https' == $scheme ) ? '443' : '80';
279
+ }
280
 
281
+ if ( ( 'https' == $scheme && '443' != $port ) || ( 'http' == $scheme && '80' != $port ) ) {
 
 
282
  $host = "$host:$port";
283
  }
284
 
285
+ // the scheme and host MUST be lowercase.
286
  $this->url = strtolower( "$scheme://$host" );
287
+ // but not the path.
288
  $this->url .= $path;
289
  }
290
 
293
  * Multipart parameters are ignored as they are not defined in the specification,
294
  * all other types of parameter are encoded for compatibility with OAuth.
295
  *
296
+ * @param array $params the parameters for the request.
297
  *
298
  * @return void prepared values are stored in the class variable 'signing_params'
299
  */
300
  private function prepare_params( $params ) {
301
+ // do not encode multipart parameters, leave them alone.
302
  if ( $this->config['multipart'] ) {
303
  $this->request_params = $params;
304
  $params = array();
305
  }
306
 
307
+ // signing parameters are request parameters + OAuth default parameters.
308
  $this->signing_params = array_merge( $this->get_defaults(), (array) $params );
309
 
310
+ // Remove oauth_signature if present.
311
+ // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.").
312
  if ( isset( $this->signing_params['oauth_signature'] ) ) {
313
  unset( $this->signing_params['oauth_signature'] );
314
  }
315
 
316
  // Parameters are sorted by name, using lexicographical byte value ordering.
317
+ // Ref: Spec: 9.1.1 (1).
318
  uksort( $this->signing_params, 'strcmp' );
319
 
320
+ // encode. Also sort the signed parameters from the POST parameters.
321
  foreach ( $this->signing_params as $k => $v ) {
322
  $k = $this->safe_encode( $k );
323
 
330
  $kv[] = "{$k}={$v}";
331
  }
332
 
333
+ // auth params = the default oauth params which are present in our collection of signing params.
334
  $this->auth_params = array_intersect_key( $this->get_defaults(), $_signing_params );
335
  if ( isset( $_signing_params['oauth_callback'] ) ) {
336
  $this->auth_params['oauth_callback'] = $_signing_params['oauth_callback'];
342
  unset( $_signing_params['oauth_verifier'] );
343
  }
344
 
345
+ // request_params is already set if we're doing multipart, if not we need to set them now.
346
  if ( ! $this->config['multipart'] ) {
347
  $this->request_params = array_diff_key( $_signing_params, $this->get_defaults() );
348
  }
349
 
350
+ // create the parameter part of the base string.
351
  $this->signing_params = implode( '&', $kv );
352
  }
353
 
369
  private function prepare_base_string() {
370
  $url = $this->url;
371
 
372
+ // if the host header is set we need to rewrite the basestring to use.
373
+ // that, instead of the request host. otherwise the signature won't match.
374
+ // on the server .
375
  if ( ! empty( $this->custom_headers['Host'] ) ) {
376
  $url = str_ireplace(
377
  $this->config['host'],
383
  $base = array(
384
  $this->method,
385
  $url,
386
+ $this->signing_params,
387
  );
388
  $this->base_string = implode( '&', $this->safe_encode( $base ) );
389
  }
414
  * Signs the request and adds the OAuth signature. This runs all the request
415
  * parameter preparation methods.
416
  *
417
+ * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc.
418
+ * @param string $url the request URL without query string parameters.
419
+ * @param array $params the request parameters as an array of key=value pairs.
420
  * @param string $useauth whether to use authentication when making the request.
421
  *
422
  * @return void
426
  $this->prepare_url( $url );
427
  $this->prepare_params( $params );
428
 
429
+ // we don't sign anything is we're not using auth.
430
  if ( $useauth ) {
431
  $this->prepare_base_string();
432
  $this->prepare_signing_key();
435
  base64_encode(
436
  hash_hmac(
437
  'sha1', $this->base_string, $this->signing_key, true
438
+ )
439
+ )
440
+ );
441
 
442
  $this->prepare_auth_header();
443
  }
447
  * Make an HTTP request using this library. This method doesn't return anything.
448
  * Instead the response should be inspected directly.
449
  *
450
+ * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc.
451
+ * @param string $url the request URL without query string parameters.
452
+ * @param array $params the request parameters as an array of key=value pairs. Default empty array.
453
+ * @param string $useauth whether to use authentication when making the request. Default true.
454
+ * @param string $multipart whether this request contains multipart data. Default false.
455
+ * @param array $headers any custom headers to send with the request. Default empty array.
456
  *
457
  * @return int the http response code for the request. 0 is returned if a connection could not be made
458
  */
459
  public function request( $method, $url, $params = array(), $useauth = true, $multipart = false, $headers = array() ) {
460
+ // reset the request headers (we don't want to reuse them).
461
  $this->headers = array();
462
  $this->custom_headers = $headers;
463
 
479
  * Make a long poll HTTP request using this library. This method is
480
  * different to the other request methods as it isn't supposed to disconnect
481
  *
482
+ * Using this method expects a callback which will receive the streaming responses.
 
483
  *
484
+ * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc.
485
+ * @param string $url the request URL without query string parameters.
486
+ * @param array $params the request parameters as an array of key=value pairs.
487
  * @param string $callback the callback function to stream the buffer to.
488
  *
489
+ * @return mixed false or void
490
  */
491
  public function streaming_request( $method, $url, $params = array(), $callback = '' ) {
492
  if ( ! empty( $callback ) ) {
529
  /**
530
  * Utility function to create the request URL in the requested format
531
  *
532
+ * @param string $request the API method without extension.
533
+ * @param string $format the format of the response. Default json. Set to an empty string to exclude the format.
534
  *
535
  * @return string the concatenation of the host, API version, API method and format
536
  */
538
  $format = strlen( $format ) > 0 ? ".$format" : '';
539
  $proto = $this->config['use_ssl'] ? 'https:/' : 'http:/';
540
 
541
+ // backwards compatibility with v0.1.
542
  if ( isset( $this->config['v'] ) ) {
543
  $this->config['host'] = $this->config['host'] . '/' . $this->config['v'];
544
  }
553
  return implode( '/', array(
554
  $proto,
555
  $this->config['host'],
556
+ $request . $format,
557
  ) );
558
  }
559
 
560
  /**
561
  * Public access to the private safe decode/encode methods
562
  *
563
+ * @param string $text the text to transform.
564
+ * @param string $mode the transformation mode. either encode or decode.
565
  *
566
  * @return string $text transformed by the given $mode
567
  */
568
+ public function transform_text( $text, $mode = 'encode' ) {
569
  return $this->{"safe_$mode"}( $text );
570
  }
571
 
573
  * Utility function to parse the returned curl headers and store them in the
574
  * class array variable.
575
  *
576
+ * @param object $ch curl handle.
577
+ * @param string $header the response headers.
578
  *
579
  * @return string the length of the header
580
  */
581
+ private function curl_header( $ch, $header ) {
582
  $this->response['raw'] .= $header;
583
 
584
  list( $key, $value ) = array_pad( explode( ':', $header, 2 ), 2, null );
605
  *
606
  * This function calls the previously defined streaming callback method.
607
  *
608
+ * @param object $ch curl handle.
609
+ * @param string $data the current curl buffer.
610
  *
611
  * @return int the length of the data string processed in this function
612
  */
613
+ private function curl_write( $ch, $data ) {
614
  $l = strlen( $data );
615
+ if ( false === strpos( $data, $this->config['streaming_eol'] ) ) {
616
  $this->buffer .= $data;
617
 
618
  return $l;
647
  * Makes a curl request. Takes no parameters as all should have been prepared
648
  * by the request method
649
  *
650
+ * The response data is stored in the class variable 'response'
651
  *
652
  * @return int the http response code for the request. 0 is returned if a connection could not be made
653
  */
654
  private function curlit() {
655
  $this->response['raw'] = '';
656
 
657
+ // method handling.
658
  switch ( $this->method ) {
659
  case 'POST':
660
  break;
661
  default:
662
+ // GET, DELETE request so convert the parameters to a querystring.
663
  if ( ! empty( $this->request_params ) ) {
664
  foreach ( $this->request_params as $k => $v ) {
665
  // Multipart params haven't been encoded yet.
666
+ // Not sure why you would do a multipart GET but anyway, here's the support for it.
667
  if ( $this->config['multipart'] ) {
668
  $params[] = $this->safe_encode( $k ) . '=' . $this->safe_encode( $v );
669
  } else {
677
  break;
678
  }
679
 
680
+ // configure curl.
681
  $c = curl_init();
682
  curl_setopt_array( $c, array(
683
  CURLOPT_USERAGENT => $this->config['user_agent'],
690
  CURLOPT_PROXY => $this->config['curl_proxy'],
691
  CURLOPT_ENCODING => $this->config['curl_encoding'],
692
  CURLOPT_URL => $this->url,
693
+ // process the headers.
694
+ CURLOPT_HEADERFUNCTION => array( $this, 'curl_header' ),
695
  CURLOPT_HEADER => false,
696
  CURLINFO_HEADER_OUT => true,
697
  ) );
698
 
699
+ if ( false !== $this->config['curl_cainfo'] ) {
700
  curl_setopt( $c, CURLOPT_CAINFO, $this->config['curl_cainfo'] );
701
  }
702
 
703
+ if ( false !== $this->config['curl_capath'] ) {
704
  curl_setopt( $c, CURLOPT_CAPATH, $this->config['curl_capath'] );
705
  }
706
 
707
+ if ( false !== $this->config['curl_proxyuserpwd'] ) {
708
  curl_setopt( $c, CURLOPT_PROXYUSERPWD, $this->config['curl_proxyuserpwd'] );
709
  }
710
 
711
  if ( $this->config['is_streaming'] ) {
712
+ // process the body.
713
  $this->response['content-length'] = 0;
714
  curl_setopt( $c, CURLOPT_TIMEOUT, 0 );
715
+ curl_setopt( $c, CURLOPT_WRITEFUNCTION, array( $this, 'curl_write' ) );
716
  }
717
 
718
  switch ( $this->method ) {
727
  }
728
 
729
  if ( ! empty( $this->request_params ) ) {
730
+ // if not doing multipart we need to implode the parameters.
731
  if ( ! $this->config['multipart'] ) {
732
  foreach ( $this->request_params as $k => $v ) {
733
  $ps[] = "{$k}={$v}";
747
  if ( isset( $this->config['prevent_request'] ) && ( true == $this->config['prevent_request'] ) ) {
748
  return 0;
749
  }
750
+
751
+ // Run the curl command.
752
  $response = curl_exec( $c );
753
  $code = curl_getinfo( $c, CURLINFO_HTTP_CODE );
754
  $info = curl_getinfo( $c );
756
  $errno = curl_errno( $c );
757
  curl_close( $c );
758
 
759
+ // store the response.
760
  $this->response['code'] = $code;
761
  $this->response['response'] = $response;
762
  $this->response['info'] = $info;
770
 
771
  return $code;
772
  }
773
+ }
WP_OAuth.php → classes/class-wp-oauth.php RENAMED
@@ -1,41 +1,92 @@
1
  <?php
2
- // vim: foldmethod=marker
 
 
 
 
 
 
 
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
  exit;
5
- } // Exit if accessed directly
6
 
7
  if ( ! class_exists( 'WPOAuthException' ) ) {
8
 
9
- /* Generic exception class
 
 
 
 
 
 
 
10
  */
11
-
12
  class WPOAuthException extends Exception {
13
- // pass
14
  }
15
 
 
 
 
16
  class WPOAuthConsumer {
 
 
 
 
 
17
  public $key;
 
 
 
 
 
18
  public $secret;
19
 
 
 
 
 
 
 
 
20
  function __construct( $key, $secret, $callback_url = null ) {
21
  $this->key = $key;
22
  $this->secret = $secret;
23
  $this->callback_url = $callback_url;
24
  }
25
 
 
 
 
26
  function __toString() {
27
  return "OAuthConsumer[key=$this->key,secret=$this->secret]";
28
  }
29
  }
30
 
 
 
 
31
  class WPOAuthToken {
32
- // access tokens and request tokens
 
 
 
 
33
  public $key;
 
 
 
 
 
34
  public $secret;
35
 
36
  /**
37
- * key = the token
38
- * secret = the token secret
 
 
39
  */
40
  function __construct( $key, $secret ) {
41
  $this->key = $key;
@@ -43,16 +94,18 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
43
  }
44
 
45
  /**
46
- * generates the basic string serialization of a token that a server
47
  * would respond to request_token and access_token calls with
 
 
48
  */
49
  function to_string() {
50
- return "oauth_token=" .
51
- WPOAuthUtil::urlencode_rfc3986( $this->key ) .
52
- "&oauth_token_secret=" .
53
- WPOAuthUtil::urlencode_rfc3986( $this->secret );
54
  }
55
 
 
 
 
56
  function __toString() {
57
  return $this->to_string();
58
  }
@@ -65,6 +118,7 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
65
  abstract class WPOAuthSignatureMethod {
66
  /**
67
  * Needs to return the name of the Signature Method (ie HMAC-SHA1)
 
68
  * @return string
69
  */
70
  abstract public function get_name();
@@ -75,9 +129,9 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
75
  * the encoding is handled in OAuthRequest when the final
76
  * request is serialized
77
  *
78
- * @param OAuthRequest $request
79
- * @param OAuthConsumer $consumer
80
- * @param OAuthToken $token
81
  *
82
  * @return string
83
  */
@@ -86,10 +140,10 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
86
  /**
87
  * Verifies that a given signature is correct
88
  *
89
- * @param OAuthRequest $request
90
- * @param OAuthConsumer $consumer
91
- * @param OAuthToken $token
92
- * @param string $signature
93
  *
94
  * @return bool
95
  */
@@ -105,22 +159,30 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
105
  * where the Signature Base String is the text and the key is the concatenated values (each first
106
  * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
107
  * character (ASCII code 38) even if empty.
108
- * - Chapter 9.2 ("HMAC-SHA1")
109
  */
110
  class WPOAuthSignatureMethod_HMAC_SHA1 extends WPOAuthSignatureMethod {
 
 
 
111
  function get_name() {
112
- return "HMAC-SHA1";
113
  }
114
 
 
 
 
 
 
 
 
 
 
115
  public function build_signature( $request, $consumer, $token ) {
116
  $base_string = $request->get_signature_base_string();
117
  $request->base_string = $base_string;
118
 
119
- $key_parts = array(
120
- $consumer->secret,
121
- ( $token ) ? $token->secret : ""
122
- );
123
-
124
  $key_parts = WPOAuthUtil::urlencode_rfc3986( $key_parts );
125
  $key = implode( '&', $key_parts );
126
 
@@ -134,24 +196,30 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
134
  * - Chapter 9.4 ("PLAINTEXT")
135
  */
136
  class WPOAuthSignatureMethod_PLAINTEXT extends WPOAuthSignatureMethod {
 
 
 
137
  public function get_name() {
138
- return "PLAINTEXT";
139
  }
140
 
141
  /**
142
- * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
143
  * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
144
  * empty. The result MUST be encoded again.
145
  * - Chapter 9.4.1 ("Generating Signatures")
146
  *
 
 
 
 
 
 
147
  * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
148
  * OAuthRequest handles this!
149
  */
150
  public function build_signature( $request, $consumer, $token ) {
151
- $key_parts = array(
152
- $consumer->secret,
153
- ( $token ) ? $token->secret : ""
154
- );
155
 
156
  $key_parts = WPOAuthUtil::urlencode_rfc3986( $key_parts );
157
  $key = implode( '&', $key_parts );
@@ -167,146 +235,224 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
167
  * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
168
  * verified way to the Service Provider, in a manner which is beyond the scope of this
169
  * specification.
170
- * - Chapter 9.3 ("RSA-SHA1")
171
  */
172
  abstract class WPOAuthSignatureMethod_RSA_SHA1 extends WPOAuthSignatureMethod {
 
 
 
173
  public function get_name() {
174
- return "RSA-SHA1";
175
  }
176
 
177
- // Up to the SP to implement this lookup of keys. Possible ideas are:
178
- // (1) do a lookup in a table of trusted certs keyed off of consumer
179
- // (2) fetch via http using a url provided by the requester
180
- // (3) some sort of specific discovery code based on request
181
- //
182
- // Either way should return a string representation of the certificate
 
 
 
 
183
  protected abstract function fetch_public_cert( &$request );
184
 
185
- // Up to the SP to implement this lookup of keys. Possible ideas are:
186
- // (1) do a lookup in a table of trusted certs keyed off of consumer
187
- //
188
- // Either way should return a string representation of the certificate
 
 
 
 
189
  protected abstract function fetch_private_cert( &$request );
190
 
 
 
 
 
 
 
 
 
 
191
  public function build_signature( $request, $consumer, $token ) {
192
  $base_string = $request->get_signature_base_string();
193
  $request->base_string = $base_string;
194
 
195
- // Fetch the private key cert based on the request
196
  $cert = $this->fetch_private_cert( $request );
197
 
198
- // Pull the private key ID from the certificate
199
  $privatekeyid = openssl_get_privatekey( $cert );
200
 
201
- // Sign using the key
202
  $ok = openssl_sign( $base_string, $signature, $privatekeyid );
203
 
204
- // Release the key resource
205
  openssl_free_key( $privatekeyid );
206
 
207
  return base64_encode( $signature );
208
  }
209
 
 
 
 
 
 
 
 
 
 
 
210
  public function check_signature( $request, $consumer, $token, $signature ) {
211
  $decoded_sig = base64_decode( $signature );
212
 
213
  $base_string = $request->get_signature_base_string();
214
 
215
- // Fetch the public key cert based on the request
216
  $cert = $this->fetch_public_cert( $request );
217
 
218
- // Pull the public key ID from the certificate
219
  $publickeyid = openssl_get_publickey( $cert );
220
 
221
- // Check the computed signature against the one passed in the query
222
  $ok = openssl_verify( $base_string, $decoded_sig, $publickeyid );
223
 
224
- // Release the key resource
225
  openssl_free_key( $publickeyid );
226
 
227
- return $ok == 1;
228
  }
229
  }
230
 
231
- class WPOAuthRequest {
 
 
 
 
 
 
 
 
232
  private $parameters;
 
 
 
 
 
 
233
  private $http_method;
 
 
 
 
 
 
234
  private $http_url;
235
- // for debug purposes
 
 
 
 
 
236
  public $base_string;
 
 
 
 
 
 
237
  public static $version = '1.0';
238
- public static $POST_INPUT = 'php://input';
239
 
240
- function __construct( $http_method, $http_url, $parameters = null ) {
241
- @$parameters or $parameters = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  $parameters = array_merge( WPOAuthUtil::parse_parameters( parse_url( $http_url, PHP_URL_QUERY ) ), $parameters );
243
  $this->parameters = $parameters;
244
  $this->http_method = $http_method;
245
  $this->http_url = $http_url;
246
  }
247
 
248
-
249
  /**
250
- * attempt to build up a request from what was passed to the server
 
 
 
 
 
 
251
  */
252
  public static function from_request( $http_method = null, $http_url = null, $parameters = null ) {
253
- $scheme = ( ! isset( $_SERVER['HTTPS'] ) || $_SERVER['HTTPS'] != "on" )
254
- ? 'http'
255
- : 'https';
256
- @$http_url or $http_url = $scheme .
257
- '://' . $_SERVER['HTTP_HOST'] .
258
- ':' .
259
- $_SERVER['SERVER_PORT'] .
260
- $_SERVER['REQUEST_URI'];
261
- @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
262
-
263
- // We weren't handed any parameters, so let's find the ones relevant to
264
- // this request.
265
- // If you run XML-RPC or similar you should use this to provide your own
266
- // parsed parameter-list
267
  if ( ! $parameters ) {
268
- // Find request headers
269
  $request_headers = WPOAuthUtil::get_headers();
270
 
271
- // Parse the query-string to find GET parameters
272
  $parameters = WPOAuthUtil::parse_parameters( $_SERVER['QUERY_STRING'] );
273
 
274
- // It's a POST request of the proper content-type, so parse POST
275
- // parameters and add those overriding any duplicates from GET
276
- if ( $http_method == "POST"
277
- && @strstr( $request_headers["Content-Type"],
278
- "application/x-www-form-urlencoded" )
279
- ) {
280
  $post_data = WPOAuthUtil::parse_parameters(
281
- file_get_contents( self::$POST_INPUT )
282
  );
283
  $parameters = array_merge( $parameters, $post_data );
284
  }
285
 
286
- // We have a Authorization-header with OAuth data. Parse the header
287
- // and add those overriding any duplicates from GET or POST
288
- if ( @substr( $request_headers['Authorization'], 0, 6 ) == "OAuth " ) {
 
289
  $header_parameters = WPOAuthUtil::split_header(
290
  $request_headers['Authorization']
291
  );
292
  $parameters = array_merge( $parameters, $header_parameters );
293
  }
294
-
295
  }
296
-
297
- return new WPOAuthRequest( $http_method, $http_url, $parameters );
298
  }
299
 
300
  /**
301
- * pretty much a helper function to set up the request
 
 
 
 
 
 
 
 
302
  */
303
- public static function from_consumer_and_token( $consumer, $token, $http_method, $http_url, $parameters = null ) {
304
- @$parameters or $parameters = array();
305
  $defaults = array(
306
- "oauth_version" => WPOAuthRequest::$version,
307
- "oauth_nonce" => WPOAuthRequest::generate_nonce(),
308
- "oauth_timestamp" => WPOAuthRequest::generate_timestamp(),
309
- "oauth_consumer_key" => $consumer->key
310
  );
311
  if ( $token ) {
312
  $defaults['oauth_token'] = $token->key;
@@ -314,15 +460,22 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
314
 
315
  $parameters = array_merge( $defaults, $parameters );
316
 
317
- return new WPOAuthRequest( $http_method, $http_url, $parameters );
318
  }
319
 
 
 
 
 
 
 
 
320
  public function set_parameter( $name, $value, $allow_duplicates = true ) {
321
  if ( $allow_duplicates && isset( $this->parameters[ $name ] ) ) {
322
- // We have already added parameter(s) with this name, so add to the list
323
  if ( is_scalar( $this->parameters[ $name ] ) ) {
324
- // This is the first duplicate, so transform scalar (string)
325
- // into an array so we can add the duplicates
326
  $this->parameters[ $name ] = array( $this->parameters[ $name ] );
327
  }
328
 
@@ -332,28 +485,46 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
332
  }
333
  }
334
 
 
 
 
 
 
 
 
335
  public function get_parameter( $name ) {
336
  return isset( $this->parameters[ $name ] ) ? $this->parameters[ $name ] : null;
337
  }
338
 
 
 
 
 
 
339
  public function get_parameters() {
340
  return $this->parameters;
341
  }
342
 
 
 
 
 
 
343
  public function unset_parameter( $name ) {
344
  unset( $this->parameters[ $name ] );
345
  }
346
 
347
  /**
348
  * The request parameters, sorted and concatenated into a normalized string.
 
349
  * @return string
350
  */
351
  public function get_signable_parameters() {
352
- // Grab all parameters
353
  $params = $this->parameters;
354
 
355
- // Remove oauth_signature if present
356
- // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
357
  if ( isset( $params['oauth_signature'] ) ) {
358
  unset( $params['oauth_signature'] );
359
  }
@@ -372,7 +543,7 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
372
  $parts = array(
373
  $this->get_normalized_http_method(),
374
  $this->get_normalized_http_url(),
375
- $this->get_signable_parameters()
376
  );
377
 
378
  $parts = WPOAuthUtil::urlencode_rfc3986( $parts );
@@ -381,28 +552,29 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
381
  }
382
 
383
  /**
384
- * just uppercases the http method
385
  */
386
  public function get_normalized_http_method() {
387
  return strtoupper( $this->http_method );
388
  }
389
 
390
  /**
391
- * parses the url and rebuilds it to be
392
  * scheme://host/path
393
  */
394
  public function get_normalized_http_url() {
395
  $parts = parse_url( $this->http_url );
396
 
397
  $port = isset( $parts['port'] ) ? $parts['port'] : false;
398
- $scheme = @$parts['scheme'];
399
- $host = @$parts['host'];
400
- $path = @$parts['path'];
401
 
402
- $port or $port = ( $scheme == 'https' ) ? '443' : '80';
 
 
403
 
404
- if ( ( $scheme == 'https' && $port != '443' )
405
- || ( $scheme == 'http' && $port != '80' )
406
  ) {
407
  $host = "$host:$port";
408
  }
@@ -411,7 +583,7 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
411
  }
412
 
413
  /**
414
- * builds a url usable for a GET request
415
  */
416
  public function to_url() {
417
  $post_data = $this->to_postdata();
@@ -424,14 +596,19 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
424
  }
425
 
426
  /**
427
- * builds the data one would send in a POST request
428
  */
429
  public function to_postdata() {
430
  return WPOAuthUtil::build_http_query( $this->parameters );
431
  }
432
 
433
  /**
434
- * builds the Authorization: header
 
 
 
 
 
435
  */
436
  public function to_header( $realm = null ) {
437
  $first = true;
@@ -444,38 +621,55 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
444
 
445
  $total = array();
446
  foreach ( $this->parameters as $k => $v ) {
447
- if ( substr( $k, 0, 5 ) != "oauth" ) {
448
  continue;
449
  }
450
  if ( is_array( $v ) ) {
451
  throw new WPOAuthException( 'Arrays not supported in headers' );
452
  }
453
- $out .= ( $first ) ? ' ' : ',';
454
- $out .= WPOAuthUtil::urlencode_rfc3986( $k ) .
455
- '="' .
456
- WPOAuthUtil::urlencode_rfc3986( $v ) .
457
- '"';
458
  $first = false;
459
  }
460
 
461
  return $out;
462
  }
463
 
 
 
 
 
 
464
  public function __toString() {
465
  return $this->to_url();
466
  }
467
 
468
-
 
 
 
 
 
 
469
  public function sign_request( $signature_method, $consumer, $token ) {
470
  $this->set_parameter(
471
- "oauth_signature_method",
472
  $signature_method->get_name(),
473
  false
474
  );
475
  $signature = $this->build_signature( $signature_method, $consumer, $token );
476
- $this->set_parameter( "oauth_signature", $signature, false );
477
  }
478
 
 
 
 
 
 
 
 
 
 
479
  public function build_signature( $signature_method, $consumer, $token ) {
480
  $signature = $signature_method->build_signature( $this, $consumer, $token );
481
 
@@ -483,59 +677,96 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
483
  }
484
 
485
  /**
486
- * util function: current timestamp
 
 
487
  */
488
  private static function generate_timestamp() {
489
- // make sure that timestamp is in UTC
490
  date_default_timezone_set( 'UTC' );
491
 
492
  return time();
493
  }
494
 
495
  /**
496
- * util function: current nonce
 
 
497
  */
498
  private static function generate_nonce() {
499
  $mt = microtime();
500
  $rand = mt_rand();
501
 
502
- return md5( $mt . $rand ); // md5s look nicer than numbers
503
  }
504
  }
505
 
 
 
 
506
  class WPOAuthServer {
507
- protected $timestamp_threshold = 300; // in seconds, five minutes
508
- protected $version = '1.0'; // hi blaine
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
  protected $signature_methods = array();
510
 
 
 
 
 
 
511
  protected $data_store;
512
 
 
 
 
 
 
513
  function __construct( $data_store ) {
514
  $this->data_store = $data_store;
515
  }
516
 
 
 
 
 
 
517
  public function add_signature_method( $signature_method ) {
518
- $this->signature_methods[ $signature_method->get_name() ] =
519
- $signature_method;
520
  }
521
 
522
- // high level functions
523
-
524
  /**
525
- * process a request_token request
526
- * returns the request token on success
 
 
 
527
  */
528
  public function fetch_request_token( &$request ) {
529
  $this->get_version( $request );
530
 
531
  $consumer = $this->get_consumer( $request );
532
 
533
- // no token required for the initial token request
534
  $token = null;
535
 
536
  $this->check_signature( $request, $consumer, $token );
537
 
538
- // Rev A change
539
  $callback = $request->get_parameter( 'oauth_callback' );
540
  $new_token = $this->data_store->new_request_token( $consumer, $callback );
541
 
@@ -543,20 +774,23 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
543
  }
544
 
545
  /**
546
- * process an access_token request
547
- * returns the access token on success
 
 
 
548
  */
549
  public function fetch_access_token( &$request ) {
550
  $this->get_version( $request );
551
 
552
  $consumer = $this->get_consumer( $request );
553
 
554
- // requires authorized request token
555
- $token = $this->get_token( $request, $consumer, "request" );
556
 
557
  $this->check_signature( $request, $consumer, $token );
558
 
559
- // Rev A change
560
  $verifier = $request->get_parameter( 'oauth_verifier' );
561
  $new_token = $this->data_store->new_access_token( $token, $consumer, $verifier );
562
 
@@ -564,26 +798,34 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
564
  }
565
 
566
  /**
567
- * verify an api call, checks all the parameters
 
 
 
 
568
  */
569
  public function verify_request( &$request ) {
570
  $this->get_version( $request );
571
  $consumer = $this->get_consumer( $request );
572
- $token = $this->get_token( $request, $consumer, "access" );
573
  $this->check_signature( $request, $consumer, $token );
574
 
575
  return array( $consumer, $token );
576
  }
577
 
578
- // Internals from here
579
  /**
580
- * version 1
 
 
 
 
 
581
  */
582
  private function get_version( &$request ) {
583
- $version = $request->get_parameter( "oauth_version" );
584
  if ( ! $version ) {
585
  // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
586
- // Chapter 7.0 ("Accessing Protected Ressources")
587
  $version = '1.0';
588
  }
589
  if ( $version !== $this->version ) {
@@ -594,25 +836,27 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
594
  }
595
 
596
  /**
597
- * figure out the signature with some defaults
 
 
 
 
 
598
  */
599
  private function get_signature_method( &$request ) {
600
- $signature_method =
601
- @$request->get_parameter( "oauth_signature_method" );
602
 
603
  if ( ! $signature_method ) {
604
- // According to chapter 7 ("Accessing Protected Ressources") the signature-method
605
- // parameter is required, and we can't just fallback to PLAINTEXT
606
  throw new WPOAuthException( 'No signature method parameter. This parameter is required' );
607
  }
608
 
609
- if ( ! in_array( $signature_method,
610
- array_keys( $this->signature_methods ) )
611
- ) {
612
  throw new WPOAuthException(
613
  "Signature method '$signature_method' not supported " .
614
- "try one of the following: " .
615
- implode( ", ", array_keys( $this->signature_methods ) )
616
  );
617
  }
618
 
@@ -620,30 +864,40 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
620
  }
621
 
622
  /**
623
- * try to find the consumer for the provided request's consumer key
 
 
 
 
 
624
  */
625
  private function get_consumer( &$request ) {
626
- $consumer_key = @$request->get_parameter( "oauth_consumer_key" );
627
  if ( ! $consumer_key ) {
628
- throw new WPOAuthException( "Invalid consumer key" );
629
  }
630
 
631
  $consumer = $this->data_store->lookup_consumer( $consumer_key );
632
  if ( ! $consumer ) {
633
- throw new WPOAuthException( "Invalid consumer" );
634
  }
635
 
636
  return $consumer;
637
  }
638
 
639
  /**
640
- * try to find the token for the provided request's token key
 
 
 
 
 
 
 
641
  */
642
- private function get_token( &$request, $consumer, $token_type = "access" ) {
643
- $token_field = @$request->get_parameter( 'oauth_token' );
644
- $token = $this->data_store->lookup_token(
645
- $consumer, $token_type, $token_field
646
- );
647
  if ( ! $token ) {
648
  throw new WPOAuthException( "Invalid $token_type token: $token_field" );
649
  }
@@ -652,13 +906,18 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
652
  }
653
 
654
  /**
655
- * all-in-one function to check the signature on a request
656
  * should guess the signature method appropriately
 
 
 
 
 
657
  */
658
  private function check_signature( &$request, $consumer, $token ) {
659
- // this should probably be in a different method
660
- $timestamp = @$request->get_parameter( 'oauth_timestamp' );
661
- $nonce = @$request->get_parameter( 'oauth_nonce' );
662
 
663
  $this->check_timestamp( $timestamp );
664
  $this->check_nonce( $consumer, $token, $nonce, $timestamp );
@@ -674,12 +933,15 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
674
  );
675
 
676
  if ( ! $valid_sig ) {
677
- throw new WPOAuthException( "Invalid signature" );
678
  }
679
  }
680
 
681
  /**
682
- * check that the timestamp is new enough
 
 
 
683
  */
684
  private function check_timestamp( $timestamp ) {
685
  if ( ! $timestamp ) {
@@ -688,7 +950,7 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
688
  );
689
  }
690
 
691
- // verify that timestamp is recentish
692
  $now = time();
693
  if ( abs( $now - $timestamp ) > $this->timestamp_threshold ) {
694
  throw new WPOAuthException(
@@ -698,16 +960,20 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
698
  }
699
 
700
  /**
701
- * check that the nonce is not repeated
 
 
 
 
 
 
702
  */
703
  private function check_nonce( $consumer, $token, $nonce, $timestamp ) {
704
  if ( ! $nonce ) {
705
- throw new WPOAuthException(
706
- 'Missing nonce parameter. The parameter is required'
707
- );
708
  }
709
 
710
- // verify that the nonce is uniqueish
711
  $found = $this->data_store->lookup_nonce(
712
  $consumer,
713
  $token,
@@ -721,37 +987,79 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
721
 
722
  }
723
 
 
 
 
724
  class WPOAuthDataStore {
 
 
 
 
 
725
  function lookup_consumer( $consumer_key ) {
726
- // implement me
727
  }
728
-
 
 
 
 
 
 
729
  function lookup_token( $consumer, $token_type, $token ) {
730
- // implement me
731
  }
732
-
 
 
 
 
 
 
 
733
  function lookup_nonce( $consumer, $token, $nonce, $timestamp ) {
734
- // implement me
735
  }
736
-
 
 
 
 
 
737
  function new_request_token( $consumer, $callback = null ) {
738
- // return a new token attached to this consumer
739
  }
740
-
 
 
 
 
 
 
741
  function new_access_token( $token, $consumer, $verifier = null ) {
742
- // return a new access token attached to this consumer
743
- // for the user associated with this token if the request token
744
- // is authorized
745
- // should also invalidate the request token
746
  }
747
 
748
  }
749
 
 
 
 
750
  class WPOAuthUtil {
 
 
 
 
 
 
 
751
  public static function urlencode_rfc3986( $input ) {
752
  if ( is_array( $input ) ) {
753
  return array_map( array( 'WPOAuthUtil', 'urlencode_rfc3986' ), $input );
754
- } else if ( is_scalar( $input ) ) {
755
  return str_replace(
756
  '+',
757
  ' ',
@@ -763,16 +1071,29 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
763
  }
764
 
765
 
766
- // This decode function isn't taking into consideration the above
767
- // modifications to the encoding process. However, this method doesn't
768
- // seem to be used anywhere so leaving it as is.
 
 
 
 
 
 
769
  public static function urldecode_rfc3986( $string ) {
770
  return urldecode( $string );
771
  }
772
 
773
- // Utility function for turning the Authorization: header into
774
- // parameters, has to do some unescaping
775
- // Can filter out any non-oauth parameters if needed (default behaviour)
 
 
 
 
 
 
 
776
  public static function split_header( $header, $only_allow_oauth_parameters = true ) {
777
  $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
778
  $offset = 0;
@@ -794,29 +1115,32 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
794
  return $params;
795
  }
796
 
797
- // helper to try to sort out headers for people who aren't running apache
 
 
 
 
798
  public static function get_headers() {
799
  if ( function_exists( 'apache_request_headers' ) ) {
800
- // we need this to get the actual Authorization: header
801
- // because apache tends to tell us it doesn't exist
802
  $headers = apache_request_headers();
803
 
804
- // sanitize the output of apache_request_headers because
805
- // we always want the keys to be Cased-Like-This and arh()
806
- // returns the headers in the same case as they are in the
807
- // request
808
  $out = array();
809
- foreach ( $headers AS $key => $value ) {
810
  $key = str_replace(
811
- " ",
812
- "-",
813
- ucwords( strtolower( str_replace( "-", " ", $key ) ) )
814
  );
815
  $out[ $key ] = $value;
816
  }
817
  } else {
818
- // otherwise we don't have apache and are just going to have to hope
819
- // that $_SERVER actually contains what we need
820
  $out = array();
821
  if ( isset( $_SERVER['CONTENT_TYPE'] ) ) {
822
  $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
@@ -826,14 +1150,14 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
826
  }
827
 
828
  foreach ( $_SERVER as $key => $value ) {
829
- if ( substr( $key, 0, 5 ) == "HTTP_" ) {
830
- // this is chaos, basically it is just there to capitalize the first
831
- // letter of every word that is not an initial HTTP and strip HTTP
832
- // code from przemek
833
  $key = str_replace(
834
- " ",
835
- "-",
836
- ucwords( strtolower( str_replace( "_", " ", substr( $key, 5 ) ) ) )
837
  );
838
  $out[ $key ] = $value;
839
  }
@@ -843,9 +1167,15 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
843
  return $out;
844
  }
845
 
846
- // This function takes a input like a=b&a=c&d=e and returns the parsed
847
- // parameters like this
848
- // array('a' => array('b','c'), 'd' => 'e')
 
 
 
 
 
 
849
  public static function parse_parameters( $input ) {
850
  if ( ! isset( $input ) || ! $input ) {
851
  return array();
@@ -860,12 +1190,11 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
860
  $value = isset( $split[1] ) ? WPOAuthUtil::urldecode_rfc3986( $split[1] ) : '';
861
 
862
  if ( isset( $parsed_parameters[ $parameter ] ) ) {
863
- // We have already recieved parameter(s) with this name, so add to the list
864
- // of parameters with this name
865
-
866
  if ( is_scalar( $parsed_parameters[ $parameter ] ) ) {
867
- // This is the first duplicate, so transform scalar (string) into an array
868
- // so we can add the duplicates
869
  $parsed_parameters[ $parameter ] = array( $parsed_parameters[ $parameter ] );
870
  }
871
 
@@ -878,25 +1207,32 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
878
  return $parsed_parameters;
879
  }
880
 
 
 
 
 
 
 
 
881
  public static function build_http_query( $params ) {
882
  if ( ! $params ) {
883
  return '';
884
  }
885
 
886
- // Urlencode both keys and values
887
  $keys = WPOAuthUtil::urlencode_rfc3986( array_keys( $params ) );
888
  $values = WPOAuthUtil::urlencode_rfc3986( array_values( $params ) );
889
  $params = array_combine( $keys, $values );
890
 
891
  // Parameters are sorted by name, using lexicographical byte value ordering.
892
- // Ref: Spec: 9.1.1 (1)
893
  uksort( $params, 'strcmp' );
894
 
895
  $pairs = array();
896
  foreach ( $params as $parameter => $value ) {
897
  if ( is_array( $value ) ) {
898
- // If two or more parameters share the same name, they are sorted by their value
899
- // Ref: Spec: 9.1.1 (1)
900
  natsort( $value );
901
  foreach ( $value as $duplicate_value ) {
902
  $pairs[] = $parameter . '=' . $duplicate_value;
@@ -905,10 +1241,9 @@ if ( ! class_exists( 'WPOAuthException' ) ) {
905
  $pairs[] = $parameter . '=' . $value;
906
  }
907
  }
908
- // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
909
- // Each name-value pair is separated by an '&' character (ASCII code 38)
910
  return implode( '&', $pairs );
911
  }
912
  }
913
-
914
- } // class_exists check
1
  <?php
2
+ /**
3
+ * WP OAuth class adapted from Abraham.
4
+ *
5
+ * @package WP to Twitter
6
+ * @author Joe Dolson
7
+ * @copyright 2012-2018 Joe Dolson
8
+ * @license GPL-2.0+
9
+ */
10
+
11
  if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
13
+ }
14
 
15
  if ( ! class_exists( 'WPOAuthException' ) ) {
16
 
17
+ /**
18
+ * Generic OAuth class
19
+ */
20
+ class WP_OAuth {
21
+ // Honestly, this is only here so I don't have to rename the file.
22
+ }
23
+ /**
24
+ * Generic exception class
25
  */
 
26
  class WPOAuthException extends Exception {
27
+ // pass.
28
  }
29
 
30
+ /**
31
+ * Create Consumer key
32
+ */
33
  class WPOAuthConsumer {
34
+ /**
35
+ * Contains the user's Consumer key.
36
+ *
37
+ * @var consumer key
38
+ */
39
  public $key;
40
+ /**
41
+ * Contains the user's consumer secret.
42
+ *
43
+ * @var secret
44
+ */
45
  public $secret;
46
 
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @param string $key Key.
51
+ * @param string $secret Secret.
52
+ * @param string $callback_url Response sent to.
53
+ */
54
  function __construct( $key, $secret, $callback_url = null ) {
55
  $this->key = $key;
56
  $this->secret = $secret;
57
  $this->callback_url = $callback_url;
58
  }
59
 
60
+ /**
61
+ * Generate consumer string.
62
+ */
63
  function __toString() {
64
  return "OAuthConsumer[key=$this->key,secret=$this->secret]";
65
  }
66
  }
67
 
68
+ /**
69
+ * Create consumer token.
70
+ */
71
  class WPOAuthToken {
72
+ /**
73
+ * Access token
74
+ *
75
+ * @var token
76
+ */
77
  public $key;
78
+ /**
79
+ * Access secret.
80
+ *
81
+ * @var secret
82
+ */
83
  public $secret;
84
 
85
  /**
86
+ * Construct token.
87
+ *
88
+ * @param string $key = the token.
89
+ * @param string $secret = the token secret.
90
  */
91
  function __construct( $key, $secret ) {
92
  $this->key = $key;
94
  }
95
 
96
  /**
97
+ * Generates the basic string serialization of a token that a server
98
  * would respond to request_token and access_token calls with
99
+ *
100
+ * @return string Oauth serialization.
101
  */
102
  function to_string() {
103
+ return 'oauth_token=' . WPOAuthUtil::urlencode_rfc3986( $this->key ) . '&oauth_token_secret=' . WPOAuthUtil::urlencode_rfc3986( $this->secret );
 
 
 
104
  }
105
 
106
+ /**
107
+ * Return string.
108
+ */
109
  function __toString() {
110
  return $this->to_string();
111
  }
118
  abstract class WPOAuthSignatureMethod {
119
  /**
120
  * Needs to return the name of the Signature Method (ie HMAC-SHA1)
121
+ *
122
  * @return string
123
  */
124
  abstract public function get_name();
129
  * the encoding is handled in OAuthRequest when the final
130
  * request is serialized
131
  *
132
+ * @param OAuthRequest $request OAuth Request object.
133
+ * @param OAuthConsumer $consumer OAuth Consumer key.
134
+ * @param OAuthToken $token OAuth Consumer token.
135
  *
136
  * @return string
137
  */
140
  /**
141
  * Verifies that a given signature is correct
142
  *
143
+ * @param OAuthRequest $request Request.
144
+ * @param OAuthConsumer $consumer Consumer key.
145
+ * @param OAuthToken $token Auth token.
146
+ * @param string $signature Signature.
147
  *
148
  * @return bool
149
  */
159
  * where the Signature Base String is the text and the key is the concatenated values (each first
160
  * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
161
  * character (ASCII code 38) even if empty.
162
+ * - Chapter 9.2 ("HMAC-SHA1")
163
  */
164
  class WPOAuthSignatureMethod_HMAC_SHA1 extends WPOAuthSignatureMethod {
165
+ /**
166
+ * Signature method.
167
+ */
168
  function get_name() {
169
+ return 'HMAC-SHA1';
170
  }
171
 
172
+ /**
173
+ * Build a signature.
174
+ *
175
+ * @param object $request Request object.
176
+ * @param object $consumer Consumer object.
177
+ * @param string $token Token.
178
+ *
179
+ * @return base 64 signature.
180
+ */
181
  public function build_signature( $request, $consumer, $token ) {
182
  $base_string = $request->get_signature_base_string();
183
  $request->base_string = $base_string;
184
 
185
+ $key_parts = array( $consumer->secret, ( $token ) ? $token->secret : '' );
 
 
 
 
186
  $key_parts = WPOAuthUtil::urlencode_rfc3986( $key_parts );
187
  $key = implode( '&', $key_parts );
188
 
196
  * - Chapter 9.4 ("PLAINTEXT")
197
  */
198
  class WPOAuthSignatureMethod_PLAINTEXT extends WPOAuthSignatureMethod {
199
+ /**
200
+ * Plaintext method.
201
+ */
202
  public function get_name() {
203
+ return 'PLAINTEXT';
204
  }
205
 
206
  /**
207
+ * The oauth_signature is set to the concatenated encoded values of the Consumer Secret and
208
  * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
209
  * empty. The result MUST be encoded again.
210
  * - Chapter 9.4.1 ("Generating Signatures")
211
  *
212
+ * @param object $request Request object.
213
+ * @param object $consumer Consumer object.
214
+ * @param string $token Token.
215
+ *
216
+ * @return signature.
217
+ *
218
  * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
219
  * OAuthRequest handles this!
220
  */
221
  public function build_signature( $request, $consumer, $token ) {
222
+ $key_parts = array( $consumer->secret, ( $token ) ? $token->secret : '' );
 
 
 
223
 
224
  $key_parts = WPOAuthUtil::urlencode_rfc3986( $key_parts );
225
  $key = implode( '&', $key_parts );
235
  * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
236
  * verified way to the Service Provider, in a manner which is beyond the scope of this
237
  * specification.
238
+ * - Chapter 9.3 ("RSA-SHA1")
239
  */
240
  abstract class WPOAuthSignatureMethod_RSA_SHA1 extends WPOAuthSignatureMethod {
241
+ /**
242
+ * Return method.
243
+ */
244
  public function get_name() {
245
+ return 'RSA-SHA1';
246
  }
247
 
248
+ /**
249
+ * Up to the SP to implement this lookup of keys. Possible ideas are:
250
+ * ((1) do a lookup in a table of trusted certs keyed off of consumer.
251
+ * (2) fetch via http using a url provided by the requester.
252
+ * (3) some sort of specific discovery code based on request.
253
+ *
254
+ * @param Object $request Request.
255
+ *
256
+ * Either way should return a string representation of the certificate.
257
+ */
258
  protected abstract function fetch_public_cert( &$request );
259
 
260
+ /**
261
+ * Up to the SP to implement this lookup of keys. Possible ideas are:
262
+ * (1) do a lookup in a table of trusted certs keyed off of consumer.
263
+ *
264
+ * @param Object $request Request.
265
+ *
266
+ * @return Either way should return a string representation of the certificate.
267
+ */
268
  protected abstract function fetch_private_cert( &$request );
269
 
270
+ /**
271
+ * Build a signature object.
272
+ *
273
+ * @param object $request Request object.
274
+ * @param object $consumer Consumer object.
275
+ * @param string $token Token.
276
+ *
277
+ * @return Encoded signature.
278
+ */
279
  public function build_signature( $request, $consumer, $token ) {
280
  $base_string = $request->get_signature_base_string();
281
  $request->base_string = $base_string;
282
 
283
+ // Fetch the private key cert based on the request.
284
  $cert = $this->fetch_private_cert( $request );
285
 
286
+ // Pull the private key ID from the certificate.
287
  $privatekeyid = openssl_get_privatekey( $cert );
288
 
289
+ // Sign using the key.
290
  $ok = openssl_sign( $base_string, $signature, $privatekeyid );
291
 
292
+ // Release the key resource.
293
  openssl_free_key( $privatekeyid );
294
 
295
  return base64_encode( $signature );
296
  }
297
 
298
+ /**
299
+ * Verify a signature object.
300
+ *
301
+ * @param object $request Request object.
302
+ * @param object $consumer Consumer object.
303
+ * @param string $token Token.
304
+ * @param string $signature Signature.
305
+ *
306
+ * @return boolean acceptance.
307
+ */
308
  public function check_signature( $request, $consumer, $token, $signature ) {
309
  $decoded_sig = base64_decode( $signature );
310
 
311
  $base_string = $request->get_signature_base_string();
312
 
313
+ // Fetch the public key cert based on the request.
314
  $cert = $this->fetch_public_cert( $request );
315
 
316
+ // Pull the public key ID from the certificate.
317
  $publickeyid = openssl_get_publickey( $cert );
318
 
319
+ // Check the computed signature against the one passed in the query.
320
  $ok = openssl_verify( $base_string, $decoded_sig, $publickeyid );
321
 
322
+ // Release the key resource.
323
  openssl_free_key( $publickeyid );
324
 
325
+ return 1 == $ok;
326
  }
327
  }
328
 
329
+ /**
330
+ * Construct and send the OAuth Request to the target URL.
331
+ */
332
+ class WP_Oauth_Request {
333
+ /**
334
+ * Query parameters
335
+ *
336
+ * @var parameters
337
+ */
338
  private $parameters;
339
+
340
+ /**
341
+ * HTTP query method.
342
+ *
343
+ * @var http_method
344
+ */
345
  private $http_method;
346
+
347
+ /**
348
+ * Target URL
349
+ *
350
+ * @var http_url
351
+ */
352
  private $http_url;
353
+
354
+ /**
355
+ * Base string - base for signature string.
356
+ *
357
+ * @var base_string
358
+ */
359
  public $base_string;
360
+
361
+ /**
362
+ * Version.
363
+ *
364
+ * @var version
365
+ */
366
  public static $version = '1.0';
 
367
 
368
+ /**
369
+ * POST input - source of input.
370
+ *
371
+ * @var post_input
372
+ */
373
+ public static $post_input = 'php://input';
374
+
375
+ /**
376
+ * Constructor function. Build properties.
377
+ *
378
+ * @param string $http_method Method.
379
+ * @param string $http_url URL.
380
+ * @param array $parameters Query parameters; will be combined with POST data.
381
+ */
382
+ function __construct( $http_method, $http_url, $parameters = array() ) {
383
  $parameters = array_merge( WPOAuthUtil::parse_parameters( parse_url( $http_url, PHP_URL_QUERY ) ), $parameters );
384
  $this->parameters = $parameters;
385
  $this->http_method = $http_method;
386
  $this->http_url = $http_url;
387
  }
388
 
 
389
  /**
390
+ * Attempt to build up a request from what was passed to the server
391
+ *
392
+ * @param string $http_method Method.
393
+ * @param string $http_url URL.
394
+ * @param array $parameters Query parameters.
395
+ *
396
+ * @return WP_Oauth_Request object.
397
  */
398
  public static function from_request( $http_method = null, $http_url = null, $parameters = null ) {
399
+ $scheme = ( ! isset( $_SERVER['HTTPS'] ) || 'on' != $_SERVER['HTTPS'] ) ? 'http' : 'https';
400
+ if ( null === $http_url ) {
401
+ $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
402
+ }
403
+ if ( null === $http_method ) {
404
+ $http_method = $_SERVER['REQUEST_METHOD'];
405
+ }
406
+
407
+ // We weren't handed any parameters, so let's find the ones relevant to this request.
408
+ // If you run XML-RPC or similar you should use this to provide your own parsed parameter-list.
 
 
 
 
409
  if ( ! $parameters ) {
410
+ // Find request headers.
411
  $request_headers = WPOAuthUtil::get_headers();
412
 
413
+ // Parse the query-string to find GET parameters.
414
  $parameters = WPOAuthUtil::parse_parameters( $_SERVER['QUERY_STRING'] );
415
 
416
+ // It's a POST request of the proper content-type, so parse POST.
417
+ // parameters and add those overriding any duplicates from GET.
418
+ $content_type = isset( $request_headers['Content-Type'] ) ? $request_headers['Content-Type'] : '';
419
+ if ( 'POST' == $http_method && strstr( $content_type, 'application/x-www-form-urlencoded' ) ) {
 
 
420
  $post_data = WPOAuthUtil::parse_parameters(
421
+ file_get_contents( self::$post_input )
422
  );
423
  $parameters = array_merge( $parameters, $post_data );
424
  }
425
 
426
+ // We have a Authorization-header with OAuth data. Parse the header.
427
+ // and add those overriding any duplicates from GET or POST.
428
+ $authorization = isset( $request_headers['Authorization'] ) ? $request_headers['Authorization'] : '';
429
+ if ( 'OAuth ' == substr( $authorization, 0, 6 ) ) {
430
  $header_parameters = WPOAuthUtil::split_header(
431
  $request_headers['Authorization']
432
  );
433
  $parameters = array_merge( $parameters, $header_parameters );
434
  }
 
435
  }
436
+ return new WP_Oauth_Request( $http_method, $http_url, $parameters );
 
437
  }
438
 
439
  /**
440
+ * Helper function to set up the request
441
+ *
442
+ * @param object $consumer Consumer token.
443
+ * @param object $token API token.
444
+ * @param string $http_method Method.
445
+ * @param string $http_url URL.
446
+ * @param array $parameters Query parameters.
447
+ *
448
+ * @return object WP_Oauth_Request object.
449
  */
450
+ public static function from_consumer_and_token( $consumer, $token, $http_method, $http_url, $parameters = array() ) {
 
451
  $defaults = array(
452
+ 'oauth_version' => WP_Oauth_Request::$version,
453
+ 'oauth_nonce' => WP_Oauth_Request::generate_nonce(),
454
+ 'oauth_timestamp' => WP_Oauth_Request::generate_timestamp(),
455
+ 'oauth_consumer_key' => $consumer->key,
456
  );
457
  if ( $token ) {
458
  $defaults['oauth_token'] = $token->key;
460
 
461
  $parameters = array_merge( $defaults, $parameters );
462
 
463
+ return new WP_Oauth_Request( $http_method, $http_url, $parameters );
464
  }
465
 
466
+ /**
467
+ * Construct parameters for query.
468
+ *
469
+ * @param string $name Parameter name string.
470
+ * @param string $value Parameter value.
471
+ * @param boolean $allow_duplicates Should we allow duplicate parameter names.
472
+ */
473
  public function set_parameter( $name, $value, $allow_duplicates = true ) {
474
  if ( $allow_duplicates && isset( $this->parameters[ $name ] ) ) {
475
+ // We have already added parameter(s) with this name, so add to the list.
476
  if ( is_scalar( $this->parameters[ $name ] ) ) {
477
+ // This is the first duplicate, so transform scalar (string).
478
+ // into an array so we can add the duplicates.
479
  $this->parameters[ $name ] = array( $this->parameters[ $name ] );
480
  }
481
 
485
  }
486
  }
487
 
488
+ /**
489
+ * Get a parameter by name.
490
+ *
491
+ * @param string $name Parameter name.
492
+ *
493
+ * @return Parameter value.
494
+ */
495
  public function get_parameter( $name ) {
496
  return isset( $this->parameters[ $name ] ) ? $this->parameters[ $name ] : null;
497
  }
498
 
499
+ /**
500
+ * Get all current parameters.
501
+ *
502
+ * @return Parameters.
503
+ */
504
  public function get_parameters() {
505
  return $this->parameters;
506
  }
507
 
508
+ /**
509
+ * Remove a parameter.
510
+ *
511
+ * @param string $name Parameter name.
512
+ */
513
  public function unset_parameter( $name ) {
514
  unset( $this->parameters[ $name ] );
515
  }
516
 
517
  /**
518
  * The request parameters, sorted and concatenated into a normalized string.
519
+ *
520
  * @return string
521
  */
522
  public function get_signable_parameters() {
523
+ // Grab all parameters.
524
  $params = $this->parameters;
525
 
526
+ // Remove oauth_signature if present.
527
+ // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.").
528
  if ( isset( $params['oauth_signature'] ) ) {
529
  unset( $params['oauth_signature'] );
530
  }
543
  $parts = array(
544
  $this->get_normalized_http_method(),
545
  $this->get_normalized_http_url(),
546
+ $this->get_signable_parameters(),
547
  );
548
 
549
  $parts = WPOAuthUtil::urlencode_rfc3986( $parts );
552
  }
553
 
554
  /**
555
+ * Just uppercases the http method
556
  */
557
  public function get_normalized_http_method() {
558
  return strtoupper( $this->http_method );
559
  }
560
 
561
  /**
562
+ * Parses the url and rebuilds it to be
563
  * scheme://host/path
564
  */
565
  public function get_normalized_http_url() {
566
  $parts = parse_url( $this->http_url );
567
 
568
  $port = isset( $parts['port'] ) ? $parts['port'] : false;
569
+ $scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : '';
570
+ $host = isset( $parts['host'] ) ? $parts['host'] : '';
571
+ $path = isset( $parts['path'] ) ? $parts['path'] : '';
572
 
573
+ if ( ! $port ) {
574
+ $port = ( 'https' == $scheme ) ? '443' : '80';
575
+ }
576
 
577
+ if ( ( 'https' == $scheme && '443' != $port ) || ( 'http' == $scheme && '80' != $port )
 
578
  ) {
579
  $host = "$host:$port";
580
  }
583
  }
584
 
585
  /**
586
+ * Builds a url usable for a GET request
587
  */
588
  public function to_url() {
589
  $post_data = $this->to_postdata();
596
  }
597
 
598
  /**
599
+ * Builds the data one would send in a POST request
600
  */
601
  public function to_postdata() {
602
  return WPOAuthUtil::build_http_query( $this->parameters );
603
  }
604
 
605
  /**
606
+ * Builds the Authorization: header
607
+ *
608
+ * @param string $realm If realm not null.
609
+ * @throws WPOAuthException Exception message.
610
+ *
611
+ * @return Header string.
612
  */
613
  public function to_header( $realm = null ) {
614
  $first = true;
621
 
622
  $total = array();
623
  foreach ( $this->parameters as $k => $v ) {
624
+ if ( 'oauth' != substr( $k, 0, 5 ) ) {
625
  continue;
626
  }
627
  if ( is_array( $v ) ) {
628
  throw new WPOAuthException( 'Arrays not supported in headers' );
629
  }
630
+ $out .= ( $first ) ? ' ' : ',';
631
+ $out .= WPOAuthUtil::urlencode_rfc3986( $k ) . '="' . WPOAuthUtil::urlencode_rfc3986( $v ) . '"';
 
 
 
632
  $first = false;
633
  }
634
 
635
  return $out;
636
  }
637
 
638
+ /**
639
+ * Convert object to URL string.
640
+ *
641
+ * @return string URL.
642
+ */
643
  public function __toString() {
644
  return $this->to_url();
645
  }
646
 
647
+ /**
648
+ * Sign the OAuth request.
649
+ *
650
+ * @param string $signature_method Method to use to sign.
651
+ * @param object $consumer Consumer object.
652
+ * @param object $token Token object.
653
+ */
654
  public function sign_request( $signature_method, $consumer, $token ) {
655
  $this->set_parameter(
656
+ 'oauth_signature_method',
657
  $signature_method->get_name(),
658
  false
659
  );
660
  $signature = $this->build_signature( $signature_method, $consumer, $token );
661
+ $this->set_parameter( 'oauth_signature', $signature, false );
662
  }
663
 
664
+ /**
665
+ * Create the OAuth signature.
666
+ *
667
+ * @param string $signature_method Method to use to sign.
668
+ * @param object $consumer Consumer object.
669
+ * @param object $token Token object.
670
+ *
671
+ * @return signature.
672
+ */
673
  public function build_signature( $signature_method, $consumer, $token ) {
674
  $signature = $signature_method->build_signature( $this, $consumer, $token );
675
 
677
  }
678
 
679
  /**
680
+ * Util function: current timestamp
681
+ *
682
+ * @return current time.
683
  */
684
  private static function generate_timestamp() {
685
+ // make sure that timestamp is in UTC.
686
  date_default_timezone_set( 'UTC' );
687
 
688
  return time();
689
  }
690
 
691
  /**
692
+ * Util function: current nonce
693
+ *
694
+ * @return md5 string.
695
  */
696
  private static function generate_nonce() {
697
  $mt = microtime();
698
  $rand = mt_rand();
699
 
700
+ return md5( $mt . $rand ); // md5s look nicer than numbers.
701
  }
702
  }
703
 
704
+ /**
705
+ * Query to OAuth server.
706
+ */
707
  class WPOAuthServer {
708
+ /**
709
+ * Limit on timestamp inconsistencies.
710
+ *
711
+ * @var $timestamp_threshold
712
+ */
713
+ protected $timestamp_threshold = 300; // in seconds, five minutes.
714
+ /**
715
+ * Version
716
+ *
717
+ * @var $version
718
+ */
719
+ protected $version = '1.0'; // hi blaine.
720
+ /**
721
+ * Array of methods usable.
722
+ *
723
+ * @var $signature_methods
724
+ */
725
  protected $signature_methods = array();
726
 
727
+ /**
728
+ * Storage variable.
729
+ *
730
+ * @var $data_store
731
+ */
732
  protected $data_store;
733
 
734
+ /**
735
+ * Build data store.
736
+ *
737
+ * @param object $data_store Data store.
738
+ */
739
  function __construct( $data_store ) {
740
  $this->data_store = $data_store;
741
  }
742
 
743
+ /**
744
+ * Add a signature method.
745
+ *
746
+ * @param object $signature_method Signature method.
747
+ */
748
  public function add_signature_method( $signature_method ) {
749
+ $this->signature_methods[ $signature_method->get_name() ] = $signature_method;
 
750
  }
751
 
 
 
752
  /**
753
+ * Process a request_token request
754
+ *
755
+ * @param object $request Request object.
756
+ *
757
+ * @return new token.
758
  */
759
  public function fetch_request_token( &$request ) {
760
  $this->get_version( $request );
761
 
762
  $consumer = $this->get_consumer( $request );
763
 
764
+ // no token required for the initial token request.
765
  $token = null;
766
 
767
  $this->check_signature( $request, $consumer, $token );
768
 
769
+ // Rev A change.
770
  $callback = $request->get_parameter( 'oauth_callback' );
771
  $new_token = $this->data_store->new_request_token( $consumer, $callback );
772
 
774
  }
775
 
776
  /**
777
+ * Process an access_token request
778
+ *
779
+ * @param object $request Request object.
780
+ *
781
+ * @return new token.
782
  */
783
  public function fetch_access_token( &$request ) {
784
  $this->get_version( $request );
785
 
786
  $consumer = $this->get_consumer( $request );
787
 
788
+ // requires authorized request token.
789
+ $token = $this->get_token( $request, $consumer, 'request' );
790
 
791
  $this->check_signature( $request, $consumer, $token );
792
 
793
+ // Rev A change.
794
  $verifier = $request->get_parameter( 'oauth_verifier' );
795
  $new_token = $this->data_store->new_access_token( $token, $consumer, $verifier );
796
 
798
  }
799
 
800
  /**
801
+ * Verify an api call, checks all the parameters
802
+ *
803
+ * @param object $request Request object.
804
+ *
805
+ * @return consumer & token.
806
  */
807
  public function verify_request( &$request ) {
808
  $this->get_version( $request );
809
  $consumer = $this->get_consumer( $request );
810
+ $token = $this->get_token( $request, $consumer, 'access' );
811
  $this->check_signature( $request, $consumer, $token );
812
 
813
  return array( $consumer, $token );
814
  }
815
 
 
816
  /**
817
+ * Version 1
818
+ *
819
+ * @param object $request Request.
820
+ * @throws WPOAuthException Exception message.
821
+ *
822
+ * @return Oauth version.
823
  */
824
  private function get_version( &$request ) {
825
+ $version = $request->get_parameter( 'oauth_version' );
826
  if ( ! $version ) {
827
  // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
828
+ // Chapter 7.0 ("Accessing Protected Resources").
829
  $version = '1.0';
830
  }
831
  if ( $version !== $this->version ) {
836
  }
837
 
838
  /**
839
+ * Figure out the signature with some defaults
840
+ *
841
+ * @param object $request Request.
842
+ * @throws WPOAuthException Exception message.
843
+ *
844
+ * @return signature methods.
845
  */
846
  private function get_signature_method( &$request ) {
847
+ $signature_method = $request->get_parameter( 'oauth_signature_method' );
 
848
 
849
  if ( ! $signature_method ) {
850
+ // According to chapter 7 ("Accessing Protected Resources") the signature-method.
851
+ // parameter is required, and we can't just fallback to PLAINTEXT.
852
  throw new WPOAuthException( 'No signature method parameter. This parameter is required' );
853
  }
854
 
855
+ if ( ! in_array( $signature_method, array_keys( $this->signature_methods ) ) ) {
 
 
856
  throw new WPOAuthException(
857
  "Signature method '$signature_method' not supported " .
858
+ 'try one of the following: ' .
859
+ implode( ', ', array_keys( $this->signature_methods ) )
860
  );
861
  }
862
 
864
  }
865
 
866
  /**
867
+ * Try to find the consumer for the provided request's consumer key
868
+ *
869
+ * @param object $request Request.
870
+ * @throws WPOAuthException Exception message.
871
+ *
872
+ * @return consumer.
873
  */
874
  private function get_consumer( &$request ) {
875
+ $consumer_key = $request->get_parameter( 'oauth_consumer_key' );
876
  if ( ! $consumer_key ) {
877
+ throw new WPOAuthException( 'Invalid consumer key' );
878
  }
879
 
880
  $consumer = $this->data_store->lookup_consumer( $consumer_key );
881
  if ( ! $consumer ) {
882
+ throw new WPOAuthException( 'Invalid consumer' );
883
  }
884
 
885
  return $consumer;
886
  }
887
 
888
  /**
889
+ * Try to find the token for the provided request's token key
890
+ *
891
+ * @param object $request Request.
892
+ * @param object $consumer Consumer.
893
+ * @param string $token_type Type of token being handled.
894
+ * @throws WPOAuthException Exception message.
895
+ *
896
+ * @return Oauth version.
897
  */
898
+ private function get_token( &$request, $consumer, $token_type = 'access' ) {
899
+ $token_field = $request->get_parameter( 'oauth_token' );
900
+ $token = $this->data_store->lookup_token( $consumer, $token_type, $token_field );
 
 
901
  if ( ! $token ) {
902
  throw new WPOAuthException( "Invalid $token_type token: $token_field" );
903
  }
906
  }
907
 
908
  /**
909
+ * All-in-one function to check the signature on a request
910
  * should guess the signature method appropriately
911
+ *
912
+ * @param object $request Request.
913
+ * @param object $consumer Consumer.
914
+ * @param object $token Token.
915
+ * @throws WPOAuthException Exception message.
916
  */
917
  private function check_signature( &$request, $consumer, $token ) {
918
+ // this should probably be in a different method.
919
+ $timestamp = $request->get_parameter( 'oauth_timestamp' );
920
+ $nonce = $request->get_parameter( 'oauth_nonce' );
921
 
922
  $this->check_timestamp( $timestamp );
923
  $this->check_nonce( $consumer, $token, $nonce, $timestamp );
933
  );
934
 
935
  if ( ! $valid_sig ) {
936
+ throw new WPOAuthException( 'Invalid signature' );
937
  }
938
  }
939
 
940
  /**
941
+ * Check that the timestamp is new enough
942
+ *
943
+ * @param string $timestamp Time stamp.
944
+ * @throws WPOAuthException Exception message.
945
  */
946
  private function check_timestamp( $timestamp ) {
947
  if ( ! $timestamp ) {
950
  );
951
  }
952
 
953
+ // verify that timestamp is recentish.
954
  $now = time();
955
  if ( abs( $now - $timestamp ) > $this->timestamp_threshold ) {
956
  throw new WPOAuthException(
960
  }
961
 
962
  /**
963
+ * Check that the nonce is not repeated
964
+ *
965
+ * @param string $consumer Consumer.
966
+ * @param string $token Token.
967
+ * @param string $nonce Nonce.
968
+ * @param string $timestamp Timestamp.
969
+ * @throws WPOAuthException Exception message.
970
  */
971
  private function check_nonce( $consumer, $token, $nonce, $timestamp ) {
972
  if ( ! $nonce ) {
973
+ throw new WPOAuthException( 'Missing nonce parameter. The parameter is required' );
 
 
974
  }
975
 
976
+ // verify that the nonce is uniqueish.
977
  $found = $this->data_store->lookup_nonce(
978
  $consumer,
979
  $token,
987
 
988
  }
989
 
990
+ /**
991
+ * Handle data storage.
992
+ */
993
  class WPOAuthDataStore {
994
+ /**
995
+ * Look up the current consumer.
996
+ *
997
+ * @param string $consumer_key Key.
998
+ */
999
  function lookup_consumer( $consumer_key ) {
1000
+ // implement me.
1001
  }
1002
+ /**
1003
+ * Look up the current token.
1004
+ *
1005
+ * @param object $consumer Consumer object.
1006
+ * @param string $token_type Token type.
1007
+ * @param string $token Token.
1008
+ */
1009
  function lookup_token( $consumer, $token_type, $token ) {
1010
+ // implement me.
1011
  }
1012
+ /**
1013
+ * Look up the current nonce.
1014
+ *
1015
+ * @param object $consumer Consumer object.
1016
+ * @param object $token Token.
1017
+ * @param string $nonce None.
1018
+ * @param string $timestamp Timestamp.
1019
+ */
1020
  function lookup_nonce( $consumer, $token, $nonce, $timestamp ) {
1021
+ // implement me.
1022
  }
1023
+ /**
1024
+ * Get a new request token.
1025
+ *
1026
+ * @param object $consumer Consumer.
1027
+ * @param string $callback URL.
1028
+ */
1029
  function new_request_token( $consumer, $callback = null ) {
1030
+ // return a new token attached to this consumer.
1031
  }
1032
+ /**
1033
+ * Get a new access token.
1034
+ *
1035
+ * @param object $token Token.
1036
+ * @param object $consumer Consumer.
1037
+ * @param string $verifier Verifier parameter.
1038
+ */
1039
  function new_access_token( $token, $consumer, $verifier = null ) {
1040
+ // return a new access token attached to this consumer.
1041
+ // for the user associated with this token if the request token.
1042
+ // is authorized.
1043
+ // should also invalidate the request token.
1044
  }
1045
 
1046
  }
1047
 
1048
+ /**
1049
+ * Utility procedures.
1050
+ */
1051
  class WPOAuthUtil {
1052
+ /**
1053
+ * Encode as rfc3986.
1054
+ *
1055
+ * @param string $input Any string input.
1056
+ *
1057
+ * @return encoded input.
1058
+ */
1059
  public static function urlencode_rfc3986( $input ) {
1060
  if ( is_array( $input ) ) {
1061
  return array_map( array( 'WPOAuthUtil', 'urlencode_rfc3986' ), $input );
1062
+ } elseif ( is_scalar( $input ) ) {
1063
  return str_replace(
1064
  '+',
1065
  ' ',
1071
  }
1072
 
1073
 
1074
+ /**
1075
+ * This decode function isn't taking into consideration the above
1076
+ * modifications to the encoding process. However, this method doesn't
1077
+ * seem to be used anywhere so leaving it as is.
1078
+ *
1079
+ * @param string $string An encoded string.
1080
+ *
1081
+ * @return $string A decoded string.
1082
+ */
1083
  public static function urldecode_rfc3986( $string ) {
1084
  return urldecode( $string );
1085
  }
1086
 
1087
+ /**
1088
+ * Utility function for turning the Authorization: header into.
1089
+ * parameters, has to do some unescaping.
1090
+ * Can filter out any non-oauth parameters if needed (default behaviour).
1091
+ *
1092
+ * @param string $header Header string.
1093
+ * @param boolean $only_allow_oauth_parameters Strip off non-oauth params.
1094
+ *
1095
+ * @return Return parameters array.
1096
+ */
1097
  public static function split_header( $header, $only_allow_oauth_parameters = true ) {
1098
  $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
1099
  $offset = 0;
1115
  return $params;
1116
  }
1117
 
1118
+ /**
1119
+ * Helper to try to sort out headers for people who aren't running apache
1120
+ *
1121
+ * @return headers
1122
+ */
1123
  public static function get_headers() {
1124
  if ( function_exists( 'apache_request_headers' ) ) {
1125
+ // we need this to get the actual Authorization: header.
1126
+ // because apache tends to tell us it doesn't exist.
1127
  $headers = apache_request_headers();
1128
 
1129
+ // sanitize the output of apache_request_headers because.
1130
+ // we always want the keys to be Cased-Like-This and arh().
1131
+ // returns the headers in the same case as they are in the request.
 
1132
  $out = array();
1133
+ foreach ( $headers as $key => $value ) {
1134
  $key = str_replace(
1135
+ ' ',
1136
+ '-',
1137
+ ucwords( strtolower( str_replace( '-', ' ', $key ) ) )
1138
  );
1139
  $out[ $key ] = $value;
1140
  }
1141
  } else {
1142
+ // otherwise we don't have apache and are just going to have to hope.
1143
+ // that $_SERVER actually contains what we need.
1144
  $out = array();
1145
  if ( isset( $_SERVER['CONTENT_TYPE'] ) ) {
1146
  $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
1150
  }
1151
 
1152
  foreach ( $_SERVER as $key => $value ) {
1153
+ if ( substr( $key, 0, 5 ) == 'HTTP_' ) {
1154
+ // this is chaos, basically it is just there to capitalize the first.
1155
+ // letter of every word that is not an initial HTTP and strip HTTP.
1156
+ // code from przemek.
1157
  $key = str_replace(
1158
+ ' ',
1159
+ '-',
1160
+ ucwords( strtolower( str_replace( '_', ' ', substr( $key, 5 ) ) ) )
1161
  );
1162
  $out[ $key ] = $value;
1163
  }
1167
  return $out;
1168
  }
1169
 
1170
+ /**
1171
+ * This function takes a input like a=b&a=c&d=e and returns the parsed
1172
+ * parameters like this
1173
+ * array('a' => array('b','c'), 'd' => 'e')
1174
+ *
1175
+ * @param string $input URL query string.
1176
+ *
1177
+ * @return array of parameters.
1178
+ */
1179
  public static function parse_parameters( $input ) {
1180
  if ( ! isset( $input ) || ! $input ) {
1181
  return array();
1190
  $value = isset( $split[1] ) ? WPOAuthUtil::urldecode_rfc3986( $split[1] ) : '';
1191
 
1192
  if ( isset( $parsed_parameters[ $parameter ] ) ) {
1193
+ // We have already recieved parameter(s) with this name, so add to the list.
1194
+ // of parameters with this name.
 
1195
  if ( is_scalar( $parsed_parameters[ $parameter ] ) ) {
1196
+ // This is the first duplicate, so transform scalar (string) into an array.
1197
+ // so we can add the duplicates.
1198
  $parsed_parameters[ $parameter ] = array( $parsed_parameters[ $parameter ] );
1199
  }
1200
 
1207
  return $parsed_parameters;
1208
  }
1209
 
1210
+ /**
1211
+ * Built an HTTP query string from parameters.
1212
+ *
1213
+ * @param array $params Query parameters.
1214
+ *
1215
+ * @return string query string.
1216
+ */
1217
  public static function build_http_query( $params ) {
1218
  if ( ! $params ) {
1219
  return '';
1220
  }
1221
 
1222
+ // Urlencode both keys and values.
1223
  $keys = WPOAuthUtil::urlencode_rfc3986( array_keys( $params ) );
1224
  $values = WPOAuthUtil::urlencode_rfc3986( array_values( $params ) );
1225
  $params = array_combine( $keys, $values );
1226
 
1227
  // Parameters are sorted by name, using lexicographical byte value ordering.
1228
+ // Ref: Spec: 9.1.1 (1).
1229
  uksort( $params, 'strcmp' );
1230
 
1231
  $pairs = array();
1232
  foreach ( $params as $parameter => $value ) {
1233
  if ( is_array( $value ) ) {
1234
+ // If two or more parameters share the same name, they are sorted by their value.
1235
+ // Ref: Spec: 9.1.1 (1).
1236
  natsort( $value );
1237
  foreach ( $value as $duplicate_value ) {
1238
  $pairs[] = $parameter . '=' . $duplicate_value;
1241
  $pairs[] = $parameter . '=' . $value;
1242
  }
1243
  }
1244
+ // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61).
1245
+ // Each name-value pair is separated by an '&' character (ASCII code 38).
1246
  return implode( '&', $pairs );
1247
  }
1248
  }
1249
+ } // class_exists check.
 
classes/class-wpt-latest-tweets-widget.php ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget to show latest Tweets.
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ /**
17
+ * WP to Twitter Latest Tweets widget class.
18
+ */
19
+ class WPT_Latest_Tweets_Widget extends WP_Widget {
20
+
21
+ /**
22
+ * Holds widget settings defaults, populated in constructor.
23
+ *
24
+ * @var array
25
+ */
26
+ protected $defaults;
27
+
28
+ /**
29
+ * Constructor. Set the default widget options and create widget.
30
+ *
31
+ * @since 0.1.8
32
+ */
33
+ function __construct() {
34
+
35
+ $this->defaults = array(
36
+ 'title' => '',
37
+ 'twitter_id' => '',
38
+ 'twitter_num' => '',
39
+ 'twitter_duration' => '',
40
+ 'twitter_hide_replies' => 0,
41
+ 'twitter_include_rts' => 0,
42
+ 'link_links' => '',
43
+ 'link_mentions' => '',
44
+ 'link_hashtags' => '',
45
+ 'intents' => '',
46
+ 'source' => '',
47
+ 'show_images' => '',
48
+ 'hide_header' => 0,
49
+ );
50
+
51
+ $widget_ops = array(
52
+ 'classname' => 'wpt-latest-tweets',
53
+ 'description' => __( 'Display a list of your latest tweets.', 'wp-to-twitter' ),
54
+ 'customize_selective_refresh' => true,
55
+ );
56
+
57
+ $control_ops = array(
58
+ 'id_base' => 'wpt-latest-tweets',
59
+ 'width' => 200,
60
+ 'height' => 250,
61
+ );
62
+ parent::__construct( 'wpt-latest-tweets', __( 'WP to Twitter - Latest Tweets', 'wp-to-twitter' ), $widget_ops, $control_ops );
63
+ }
64
+
65
+ /**
66
+ * Echo the widget content.
67
+ *
68
+ * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
69
+ * @param array $instance The settings for the particular instance of the widget.
70
+ */
71
+ function widget( $args, $instance ) {
72
+ $before_widget = $args['before_widget'];
73
+ $after_widget = $args['after_widget'];
74
+ $before_title = $args['before_title'];
75
+ $after_title = $args['after_title'];
76
+
77
+ wp_enqueue_script( 'twitter-platform', 'https://platform.twitter.com/widgets.js' );
78
+ /** Merge with defaults */
79
+ $instance = wp_parse_args( (array) $instance, $this->defaults );
80
+
81
+ echo $before_widget;
82
+ if ( $instance['title'] ) {
83
+ echo $before_title . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $after_title;
84
+ }
85
+ echo wpt_twitter_feed( $instance );
86
+ echo $after_widget;
87
+ }
88
+
89
+ /**
90
+ * Update a particular instance.
91
+ *
92
+ * This function should check that $new_instance is set correctly.
93
+ * The newly calculated value of $instance should be returned.
94
+ * If "false" is returned, the instance won't be saved/updated.
95
+ *
96
+ * @since 0.1
97
+ *
98
+ * @param array $new_instance New settings for this instance as input by the user via form().
99
+ * @param array $old_instance Old settings for this instance.
100
+ *
101
+ * @return array Settings to save or bool false to cancel saving
102
+ */
103
+ function update( $new_instance, $old_instance ) {
104
+ // Force the cache to refresh.
105
+ update_option( 'wpt_delete_cache', 'true' );
106
+ $new_instance['title'] = strip_tags( $new_instance['title'] );
107
+
108
+ return $new_instance;
109
+ }
110
+
111
+ /**
112
+ * Echo the settings update form.
113
+ *
114
+ * @param array $instance Current settings.
115
+ */
116
+ function form( $instance ) {
117
+
118
+ // Merge with defaults.
119
+ $instance = wp_parse_args( (array) $instance, $this->defaults );
120
+ ?>
121
+ <p>
122
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'wp-to-twitter' ); ?>:</label>
123
+ <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>" class="widefat"/>
124
+ </p>
125
+
126
+ <p>
127
+ <label for="<?php echo $this->get_field_id( 'twitter_id' ); ?>"><?php _e( 'Twitter Username', 'wp-to-twitter' ); ?> :</label>
128
+ <input type="text" id="<?php echo $this->get_field_id( 'twitter_id' ); ?>" name="<?php echo $this->get_field_name( 'twitter_id' ); ?>" value="<?php echo esc_attr( $instance['twitter_id'] ); ?>" class="widefat"/>
129
+ </p>
130
+
131
+ <p>
132
+ <input id="<?php echo $this->get_field_id( 'hide_header' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'hide_header' ); ?>" value="1" <?php checked( $instance['hide_header'], 1 ); ?>/>
133
+ <label for="<?php echo $this->get_field_id( 'hide_header' ); ?>"><?php _e( 'Hide Widget Header', 'wp-to-twitter' ); ?></label>
134
+ </p>
135
+
136
+ <p>
137
+ <label for="<?php echo $this->get_field_id( 'twitter_num' ); ?>"><?php _e( 'Number of Tweets to Show', 'wp-to-twitter' ); ?> :</label>
138
+ <input type="text" id="<?php echo $this->get_field_id( 'twitter_num' ); ?>" name="<?php echo $this->get_field_name( 'twitter_num' ); ?>" value="<?php echo esc_attr( $instance['twitter_num'] ); ?>" size="3"/>
139
+ </p>
140
+
141
+ <p>
142
+ <input id="<?php echo $this->get_field_id( 'twitter_hide_replies' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'twitter_hide_replies' ); ?>" value="1" <?php checked( $instance['twitter_hide_replies'], 1 ); ?>/>
143
+ <label for="<?php echo $this->get_field_id( 'twitter_hide_replies' ); ?>"><?php _e( 'Hide @ Replies', 'wp-to-twitter' ); ?></label>
144
+ </p>
145
+
146
+ <p>
147
+ <input id="<?php echo $this->get_field_id( 'twitter_include_rts' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'twitter_include_rts' ); ?>" value="1" <?php checked( $instance['twitter_include_rts'], 1 ); ?>/>
148
+ <label for="<?php echo $this->get_field_id( 'twitter_include_rts' ); ?>"><?php _e( 'Include Retweets', 'wp-to-twitter' ); ?></label>
149
+ </p>
150
+
151
+ <p>
152
+ <input id="<?php echo $this->get_field_id( 'link_links' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_links' ); ?>" value="1" <?php checked( $instance['link_links'], 1 ); ?>/>
153
+ <label for="<?php echo $this->get_field_id( 'link_links' ); ?>"><?php _e( 'Parse links', 'wp-to-twitter' ); ?></label>
154
+ </p>
155
+
156
+ <p>
157
+ <input id="<?php echo $this->get_field_id( 'link_mentions' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_mentions' ); ?>" value="1" <?php checked( $instance['link_mentions'], 1 ); ?>/>
158
+ <label for="<?php echo $this->get_field_id( 'link_mentions' ); ?>"><?php _e( 'Parse @mentions', 'wp-to-twitter' ); ?></label>
159
+ </p>
160
+
161
+ <p>
162
+ <input id="<?php echo $this->get_field_id( 'show_images' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'show_images' ); ?>" value="1" <?php checked( $instance['show_images'], 1 ); ?>/>
163
+ <label for="<?php echo $this->get_field_id( 'show_images' ); ?>"><?php _e( 'Show Images', 'wp-to-twitter' ); ?></label>
164
+ </p>
165
+
166
+ <p>
167
+ <input id="<?php echo $this->get_field_id( 'link_hashtags' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_hashtags' ); ?>" value="1" <?php checked( $instance['link_hashtags'], 1 ); ?>/>
168
+ <label for="<?php echo $this->get_field_id( 'link_hashtags' ); ?>"><?php _e( 'Parse #hashtags', 'wp-to-twitter' ); ?></label>
169
+ </p>
170
+
171
+ <p>
172
+ <input id="<?php echo $this->get_field_id( 'intents' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'intents' ); ?>" value="1" <?php checked( $instance['intents'], 1 ); ?>/>
173
+ <label for="<?php echo $this->get_field_id( 'intents' ); ?>"><?php _e( 'Include Reply/Retweet/Favorite Links', 'wp-to-twitter' ); ?></label>
174
+ </p>
175
+
176
+ <p>
177
+ <input id="<?php echo $this->get_field_id( 'source' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'source' ); ?>" value="1" <?php checked( $instance['source'], 1 ); ?>/>
178
+ <label for="<?php echo $this->get_field_id( 'source' ); ?>"><?php _e( 'Include Tweet source', 'wp-to-twitter' ); ?></label>
179
+ </p>
180
+ <p>
181
+ <input id="<?php echo $this->get_field_id( 'cache' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'cache' ); ?>" value="1" />
182
+ <label for="<?php echo $this->get_field_id( 'cache' ); ?>"><?php _e( 'Clear cache', 'wp-to-twitter' ); ?></label>
183
+ </p>
184
+ <?php
185
+ }
186
+ }
classes/class-wpt-normalizer.php ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP to Twitter Normalizer fallback class
4
+ *
5
+ * @category Fallbacks
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ /**
17
+ * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.
18
+ *
19
+ * It has been validated with Unicode 6.1 Normalization Conformance Test.
20
+ * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.
21
+ */
22
+ class WPT_Normalizer {
23
+ const
24
+
25
+ NONE = 1,
26
+ FORM_D = 2, NFD = 2,
27
+ FORM_KD = 3, NFKD = 3,
28
+ FORM_C = 4, NFC = 4,
29
+ FORM_KC = 5, NFKC = 5;
30
+
31
+ protected static
32
+
33
+ /**
34
+ * Character containers.
35
+ *
36
+ * @var $c
37
+ */
38
+ $c,
39
+ /**
40
+ * Character containers.
41
+ *
42
+ * @var $d
43
+ */
44
+ $d,
45
+ /**
46
+ * Character containers.
47
+ *
48
+ * @var $kd
49
+ */
50
+ $kd,
51
+ /**
52
+ * Character containers.
53
+ *
54
+ * @var $cc
55
+ */
56
+ $cc,
57
+ /**
58
+ * U length mask.
59
+ *
60
+ * @var $ulen_mask
61
+ */
62
+ $ulen_mask = array(
63
+ "\xC0" => 2,
64
+ "\xD0" => 2,
65
+ "\xE0" => 3,
66
+ "\xF0" => 4,
67
+ ),
68
+
69
+ /**
70
+ * Index of ASCII characters.
71
+ *
72
+ * @var $ascii
73
+ */
74
+ $ascii = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
75
+
76
+ /**
77
+ * Check whether is already normalized.
78
+ *
79
+ * @param string $s String to check.
80
+ * @param object $form Self.
81
+ *
82
+ * @return boolean
83
+ */
84
+ static function is_normalized( $s, $form = self::NFC ) {
85
+ if ( strspn( $s, self::$ascii ) === strlen( $s ) ) {
86
+ return true;
87
+ }
88
+ if ( self::NFC === $form && preg_match( '//u', $s ) && ! preg_match( '/[^\x00-\x{2FF}]/u', $s ) ) {
89
+ return true;
90
+ }
91
+ return false; // Pretend false as quick checks implementented in PHP won't be so quick.
92
+ }
93
+
94
+ /**
95
+ * Normalize a string.
96
+ *
97
+ * @param string $s String to normalize.
98
+ * @param object $form Self.
99
+ *
100
+ * @return boolean or normalized string.
101
+ */
102
+ static function normalize( $s, $form = self::NFC ) {
103
+ if ( ! preg_match( '//u', $s ) ) {
104
+ return false;
105
+ }
106
+
107
+ switch ( $form ) {
108
+ case self::NONE:
109
+ return $s;
110
+ case self::NFC:
111
+ $c = true;
112
+ $k = false;
113
+ break;
114
+ case self::NFD:
115
+ $c = false;
116
+ $k = false;
117
+ break;
118
+ case self::NFKC:
119
+ $c = true;
120
+ $k = true;
121
+ break;
122
+ case self::NFKD:
123
+ $c = false;
124
+ $k = true;
125
+ break;
126
+ default:
127
+ return false;
128
+ }
129
+
130
+ if ( ! strlen( $s ) ) {
131
+ return '';
132
+ }
133
+
134
+ if ( $k && empty( self::$kd ) ) {
135
+ self::$kd = self::get_data( 'compatibilityDecomposition' );
136
+ }
137
+
138
+ if ( empty( self::$d ) ) {
139
+ self::$d = self::get_data( 'canonicalDecomposition' );
140
+ self::$cc = self::get_data( 'combiningClass' );
141
+ }
142
+
143
+ if ( $c ) {
144
+ if ( empty( self::$c ) ) {
145
+ self::$c = self::get_data( 'canonicalComposition' );
146
+ }
147
+ return self::recompose( self::decompose( $s, $k ) );
148
+ } else {
149
+ return self::decompose( $s, $k );
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Recompose a string.
155
+ *
156
+ * @param string $s String to check.
157
+ *
158
+ * @return string
159
+ */
160
+ protected static function recompose( $s ) {
161
+ $ascii = self::$ascii;
162
+ $comp_map = self::$c;
163
+ $comb_class = self::$cc;
164
+ $ulen_mask = self::$ulen_mask;
165
+
166
+ $result = '';
167
+ $tail = '';
168
+
169
+ $i = $s[0] < "\x80" ? 1 : $ulen_mask[ $s[0] & "\xF0" ];
170
+ $len = strlen( $s );
171
+
172
+ $last_uchr = substr( $s, 0, $i );
173
+ $last_ucls = isset( $comb_class[ $last_uchr ] ) ? 256 : 0;
174
+
175
+ while ( $i < $len ) {
176
+ if ( $s[ $i ] < "\x80" ) {
177
+ // ascii chars.
178
+ if ( $tail ) {
179
+ $last_uchr .= $tail;
180
+ $tail = '';
181
+ }
182
+ $j = strspn( $s, $ascii, $i + 1 );
183
+ if ( $j ) {
184
+ $last_uchr .= substr( $s, $i, $j );
185
+ $i += $j;
186
+ }
187
+
188
+ $result .= $last_uchr;
189
+ $last_uchr = $s[ $i ];
190
+ ++$i;
191
+ } else {
192
+ $ulen = $ulen_mask[ $s[ $i ] & "\xF0" ];
193
+ $uchr = substr( $s, $i, $ulen );
194
+
195
+ if ( $last_uchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $last_uchr
196
+ || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
197
+ || $last_ucls ) {
198
+ // Table lookup and combining chars composition.
199
+ $ucls = isset( $comb_class[ $uchr ] ) ? $comb_class[ $uchr ] : 0;
200
+
201
+ if ( isset( $comp_map[ $last_uchr . $uchr ] ) && ( ! $last_ucls || $last_ucls < $ucls ) ) {
202
+ $last_uchr = $comp_map[ $last_uchr . $uchr ];
203
+ } elseif ( $last_ucls == $ucls ) {
204
+ $tail .= $uchr;
205
+ } else {
206
+ if ( $tail ) {
207
+ $last_uchr .= $tail;
208
+ $tail = '';
209
+ }
210
+
211
+ $result .= $last_uchr;
212
+ $last_uchr = $uchr;
213
+ }
214
+ } else {
215
+ // Hangul chars.
216
+ $l = ord( $last_uchr[2] ) - 0x80;
217
+ $v = ord( $uchr[2] ) - 0xA1;
218
+ $t = 0;
219
+
220
+ $uchr = substr( $s, $i + $ulen, 3 );
221
+
222
+ if ( "\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82" ) {
223
+ $t = ord( $uchr[2] ) - 0xA7;
224
+ 0 > $t && $t += 0x40;
225
+ $ulen += 3;
226
+ }
227
+
228
+ $l = 0xAC00 + ( $l * 21 + $v ) * 28 + $t;
229
+ $last_uchr = chr( 0xE0 | $l >> 12 ) . chr( 0x80 | $l >> 6 & 0x3F ) . chr( 0x80 | $l & 0x3F );
230
+ }
231
+
232
+ $i += $ulen;
233
+ }
234
+ }
235
+
236
+ return $result . $last_uchr . $tail;
237
+ }
238
+
239
+ /**
240
+ * Decompose a string.
241
+ *
242
+ * @param string $s String to check.
243
+ * @param boolean $c use compat map.
244
+ *
245
+ * @return string
246
+ */
247
+ protected static function decompose( $s, $c ) {
248
+ $result = '';
249
+
250
+ $ascii = self::$ascii;
251
+ $decomp_map = self::$d;
252
+ $comb_class = self::$cc;
253
+ $ulen_mask = self::$ulen_mask;
254
+ if ( $c ) {
255
+ $compat_map = self::$kd;
256
+ }
257
+
258
+ $c = array();
259
+ $i = 0;
260
+ $len = strlen( $s );
261
+
262
+ while ( $i < $len ) {
263
+ if ( $s[ $i ] < "\x80" ) {
264
+ // ascii chars.
265
+ if ( $c ) {
266
+ ksort( $c );
267
+ $result .= implode( '', $c );
268
+ $c = array();
269
+ }
270
+
271
+ $j = 1 + strspn( $s, $ascii, $i + 1 );
272
+ $result .= substr( $s, $i, $j );
273
+ $i += $j;
274
+ } else {
275
+ $ulen = $ulen_mask[ $s[ $i ] & "\xF0" ];
276
+ $uchr = substr( $s, $i, $ulen );
277
+ $i += $ulen;
278
+
279
+ if ( isset( $comb_class[ $uchr ] ) ) {
280
+ // Combining chars, for sorting.
281
+ if ( ! isset( $c[ $comb_class[ $uchr ] ] ) ) {
282
+ $c[ $comb_class[ $uchr ] ] = '';
283
+ }
284
+ $c[ $comb_class[ $uchr ] ] .= isset( $compat_map[ $uchr ] ) ? $compat_map[ $uchr ] : ( isset( $decomp_map[ $uchr ] ) ? $decomp_map[ $uchr ] : $uchr );
285
+ } else {
286
+ if ( $c ) {
287
+ ksort( $c );
288
+ $result .= implode( '', $c );
289
+ $c = array();
290
+ }
291
+
292
+ if ( $uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr ) {
293
+ // Table lookup.
294
+ $j = isset( $compat_map[ $uchr ] ) ? $compat_map[ $uchr ] : ( isset( $decomp_map[ $uchr ] ) ? $decomp_map[ $uchr ] : $uchr );
295
+
296
+ if ( $uchr != $j ) {
297
+ $uchr = $j;
298
+
299
+ $j = strlen( $uchr );
300
+ $ulen = $uchr[0] < "\x80" ? 1 : $ulen_mask[ $uchr[0] & "\xF0" ];
301
+
302
+ if ( $ulen != $j ) {
303
+ // Put trailing chars in $s.
304
+ $j -= $ulen;
305
+ $i -= $j;
306
+
307
+ if ( 0 > $i ) {
308
+ $s = str_repeat( ' ', -$i ) . $s;
309
+ $len -= $i;
310
+ $i = 0;
311
+ }
312
+
313
+ while ( $j-- ) {
314
+ $s[ $i + $j ] = $uchr[ $ulen + $j ];
315
+ }
316
+
317
+ $uchr = substr( $uchr, 0, $ulen );
318
+ }
319
+ }
320
+ } else {
321
+ // Hangul chars.
322
+ $uchr = unpack( 'C*', $uchr );
323
+ $j = ( ( $uchr[1] - 224 ) << 12 ) + ( ( $uchr[2] - 128 ) << 6 ) + $uchr[3] - 0xAC80;
324
+
325
+ $uchr = "\xE1\x84" . chr( 0x80 + (int) ( $j / 588 ) ) . "\xE1\x85" . chr( 0xA1 + (int) ( ( $j % 588 ) / 28 ) );
326
+
327
+ if ( $j %= 28 ) {
328
+ $uchr .= $j < 25 ? ( "\xE1\x86" . chr( 0xA7 + $j ) ) : ( "\xE1\x87" . chr( 0x67 + $j ) );
329
+ }
330
+ }
331
+
332
+ $result .= $uchr;
333
+ }
334
+ }
335
+ }
336
+
337
+ if ( $c ) {
338
+ ksort( $c );
339
+ $result .= implode( '', $c );
340
+ }
341
+
342
+ return $result;
343
+ }
344
+
345
+ /**
346
+ * Data fetcher.
347
+ *
348
+ * @param string $file Get data file.
349
+ *
350
+ * @return file contents or false.
351
+ */
352
+ protected static function get_data( $file ) {
353
+ $file = __DIR__ . '/unidata/' . $file . '.ser';
354
+ if ( file_exists( $file ) ) {
355
+ return unserialize( file_get_contents( $file ) );
356
+ } else {
357
+ return false;
358
+ }
359
+ }
360
+ }
classes/class-wpt-search-tweets-widget.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget to show searched Tweets.
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ /**
17
+ * WP to Twitter Latest Tweets widget class.
18
+ */
19
+ class WPT_Search_Tweets_Widget extends WP_Widget {
20
+
21
+ /**
22
+ * Holds widget settings defaults, populated in constructor.
23
+ *
24
+ * @var array
25
+ */
26
+ protected $defaults;
27
+
28
+ /**
29
+ * Constructor. Set the default widget options and create widget.
30
+ *
31
+ * @since 0.1.8
32
+ */
33
+ function __construct() {
34
+
35
+ $this->defaults = array(
36
+ 'title' => '',
37
+ 'twitter_num' => '',
38
+ 'search' => '',
39
+ 'result_type' => 'recent', // mixed, recent, popular.
40
+ 'geocode' => '', // 37.777,-127.98,2km.
41
+ 'link_links' => '',
42
+ 'link_mentions' => '',
43
+ 'show_images' => '',
44
+ 'link_hashtags' => '',
45
+ 'intents' => '',
46
+ 'source' => '',
47
+ );
48
+
49
+ $widget_ops = array(
50
+ 'classname' => 'wpt-search-tweets',
51
+ 'description' => __( 'Display a list of tweets returned by a search.', 'wp-to-twitter' ),
52
+ 'customize_selective_refresh' => true,
53
+ );
54
+
55
+ $control_ops = array(
56
+ 'id_base' => 'wpt-search-tweets',
57
+ 'width' => 200,
58
+ 'height' => 250,
59
+ );
60
+ parent::__construct( 'wpt-search-tweets', __( 'WP to Twitter - Searched Tweets', 'wp-to-twitter' ), $widget_ops, $control_ops );
61
+ }
62
+
63
+ /**
64
+ * Echo the widget content.
65
+ *
66
+ * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
67
+ * @param array $instance The settings for the particular instance of the widget.
68
+ */
69
+ function widget( $args, $instance ) {
70
+ $before_widget = $args['before_widget'];
71
+ $after_widget = $args['after_widget'];
72
+ $before_title = $args['before_title'];
73
+ $after_title = $args['after_title'];
74
+
75
+ wp_enqueue_script( 'twitter-platform', 'https://platform.twitter.com/widgets.js' );
76
+ // Merge with defaults.
77
+ $instance = wp_parse_args( (array) $instance, $this->defaults );
78
+ echo $before_widget;
79
+ if ( $instance['title'] ) {
80
+ echo $before_title . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $after_title;
81
+ }
82
+ echo wpt_twitter_feed( $instance );
83
+ echo $after_widget;
84
+ }
85
+
86
+ /**
87
+ * Update a particular instance.
88
+ *
89
+ * This function should check that $new_instance is set correctly.
90
+ * The newly calculated value of $instance should be returned.
91
+ * If "false" is returned, the instance won't be saved/updated.
92
+ *
93
+ * @since 0.1
94
+ *
95
+ * @param array $new_instance New settings for this instance as input by the user via form().
96
+ * @param array $old_instance Old settings for this instance.
97
+ *
98
+ * @return array Settings to save or bool false to cancel saving
99
+ */
100
+ function update( $new_instance, $old_instance ) {
101
+ // Force the cache to refresh.
102
+ update_option( 'wpt_delete_cache', 'true' );
103
+ $new_instance['title'] = strip_tags( $new_instance['title'] );
104
+
105
+ return $new_instance;
106
+ }
107
+
108
+ /**
109
+ * Echo the settings update form.
110
+ *
111
+ * @param array $instance Current settings.
112
+ */
113
+ function form( $instance ) {
114
+ // Merge with defaults.
115
+ $instance = wp_parse_args( (array) $instance, $this->defaults );
116
+ ?>
117
+ <p>
118
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'wp-to-twitter' ); ?>:</label>
119
+ <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>" class="widefat"/>
120
+ </p>
121
+
122
+ <p>
123
+ <label for="<?php echo $this->get_field_id( 'search' ); ?>"><?php _e( 'Search String', 'wp-to-twitter' ); ?> :</label>
124
+ <input type="text" id="<?php echo $this->get_field_id( 'search' ); ?>" name="<?php echo $this->get_field_name( 'search' ); ?>" value="<?php echo esc_attr( $instance['search'] ); ?>" class="widefat"/>
125
+ </p>
126
+
127
+ <p>
128
+ <label for="<?php echo $this->get_field_id( 'twitter_num' ); ?>"><?php _e( 'Number of Tweets to Show', 'wp-to-twitter' ); ?> :</label>
129
+ <input type="text" id="<?php echo $this->get_field_id( 'twitter_num' ); ?>" name="<?php echo $this->get_field_name( 'twitter_num' ); ?>" value="<?php echo esc_attr( $instance['twitter_num'] ); ?>" size="3"/>
130
+ </p>
131
+
132
+ <p>
133
+ <label for="<?php echo $this->get_field_id( 'result_type' ); ?>"><?php _e( 'Type of Results', 'wp-to-twitter' ); ?></label>
134
+ <select name="<?php echo $this->get_field_name( 'result_type' ); ?>" id="<?php echo $this->get_field_id( 'result_type' ); ?>"> <option value='recent'<?php echo ( 'recent' == $instance['result_type'] ) ? ' selected="selected"' : ''; ?>><?php _e( 'Recent Tweets', 'wp-to-twitter' ); ?></option> <option value='popular'<?php echo ( 'popular' == $instance['result_type'] ) ? ' selected="selected"' : ''; ?>><?php _e( 'Popular Tweets', 'wp-to-twitter' ); ?></option> <option value='mixed'<?php echo ( 'mixed' == $instance['result_type'] ) ? ' selected="selected"' : ''; ?>><?php _e( 'Mixed', 'wp-to-twitter' ); ?></option>
135
+ </select>
136
+ </p>
137
+
138
+ <p>
139
+ <label for="<?php echo $this->get_field_id( 'geocode' ); ?>"><?php _e( 'Geocode (Latitude,Longitude,Radius)', 'wp-to-twitter' ); ?> :</label>
140
+ <input type="text" id="<?php echo $this->get_field_id( 'geocode' ); ?>" class="widefat" name="<?php echo $this->get_field_name( 'geocode' ); ?>" value="<?php echo esc_attr( $instance['geocode'] ); ?>" size="32" placeholder="37.781157,-122.398720,2km"/>
141
+ </p>
142
+
143
+ <p>
144
+ <input id="<?php echo $this->get_field_id( 'link_links' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_links' ); ?>" value="1" <?php checked( $instance['link_links'] ); ?>/>
145
+ <label for="<?php echo $this->get_field_id( 'link_links' ); ?>"><?php _e( 'Parse links', 'wp-to-twitter' ); ?></label>
146
+ </p>
147
+
148
+ <p>
149
+ <input id="<?php echo $this->get_field_id( 'link_mentions' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_mentions' ); ?>" value="1" <?php checked( $instance['link_mentions'] ); ?>/>
150
+ <label for="<?php echo $this->get_field_id( 'link_mentions' ); ?>"><?php _e( 'Parse @mentions', 'wp-to-twitter' ); ?></label>
151
+ </p>
152
+
153
+ <p>
154
+ <input id="<?php echo $this->get_field_id( 'show_images' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'show_images' ); ?>" value="1" <?php checked( $instance['show_images'], 1 ); ?>/>
155
+ <label for="<?php echo $this->get_field_id( 'show_images' ); ?>"><?php _e( 'Show Images', 'wp-to-twitter' ); ?></label>
156
+ </p>
157
+
158
+ <p>
159
+ <input id="<?php echo $this->get_field_id( 'link_hashtags' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'link_hashtags' ); ?>" value="1" <?php checked( $instance['link_hashtags'] ); ?>/>
160
+ <label for="<?php echo $this->get_field_id( 'link_hashtags' ); ?>"><?php _e( 'Parse #hashtags', 'wp-to-twitter' ); ?></label>
161
+ </p>
162
+
163
+ <p>
164
+ <input id="<?php echo $this->get_field_id( 'intents' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'intents' ); ?>" value="1" <?php checked( $instance['intents'] ); ?>/>
165
+ <label for="<?php echo $this->get_field_id( 'intents' ); ?>"><?php _e( 'Include Reply/Retweet/Favorite Links', 'wp-to-twitter' ); ?></label>
166
+ </p>
167
+
168
+ <p>
169
+ <input id="<?php echo $this->get_field_id( 'source' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'source' ); ?>" value="1" <?php checked( $instance['source'] ); ?>/>
170
+ <label for="<?php echo $this->get_field_id( 'source' ); ?>"><?php _e( 'Include Tweet source', 'wp-to-twitter' ); ?></label>
171
+ </p>
172
+ <?php
173
+ }
174
+ }
wpt-feed.php → classes/class-wpt-twitterfeed.php RENAMED
@@ -1,18 +1,31 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
5
- /*
6
- * Version 2.0.3, Twitter Feed for Developers by Storm Consultancy (Liam Gladdy)
7
- * The base class for the storm twitter feed for developers.
8
- */
9
-
10
- // based on StormTwitter; significantly modified
11
 
12
- require_once( 'wpt_twitter_oauth.php' );
13
 
 
 
 
 
14
  class WPT_TwitterFeed {
15
 
 
 
 
 
 
16
  private $defaults = array(
17
  'directory' => '',
18
  'key' => '',
@@ -20,21 +33,44 @@ class WPT_TwitterFeed {
20
  'token' => '',
21
  'token_secret' => '',
22
  'screenname' => false,
23
- 'cache_expire' => 1800
24
  );
25
 
 
 
 
 
 
26
  public $st_last_error = false;
27
 
 
 
 
 
 
28
  function __construct( $args = array() ) {
29
  $this->defaults = array_merge( $this->defaults, $args );
30
  }
31
 
 
 
 
 
 
32
  function __toString() {
33
  return print_r( $this->defaults, true );
34
  }
35
 
36
- //I'd prefer to put username before count, but for backwards compatibility it's not really viable. :(
37
- function getTweets( $count = 20, $screenname = false, $options = false ) {
 
 
 
 
 
 
 
 
38
  if ( $count > 20 ) {
39
  /**
40
  * Filters the max feed count. Default is 20, but you can change it.
@@ -49,37 +85,49 @@ class WPT_TwitterFeed {
49
  $count = 1;
50
  }
51
 
52
- $default_options = array( 'trim_user' => true, 'exclude_replies' => true, 'include_rts' => false );
 
 
 
 
53
 
54
- if ( $options === false || ! is_array( $options ) ) {
55
  $options = $default_options;
56
  } else {
57
  $options = array_merge( $default_options, $options );
58
  }
59
 
60
- if ( $screenname == false ) {
61
  $screenname = get_option( 'wtt_twitter_username' );
62
  }
63
 
64
- $result = $this->checkValidCache( $screenname, $options );
65
- if ( $result !== false ) {
66
- return $this->cropTweets( $result, $count );
67
  }
68
 
69
- //If we're here, we need to load.
70
- $result = $this->oauthGetTweets( $screenname, $options );
71
 
72
  if ( is_object( $result ) && isset( $result->error ) ) {
73
  $last_error = $result->error;
74
 
75
  return array( 'error' => 'Twitter said: ' . $last_error );
76
  } else {
77
- return $this->cropTweets( $result, $count );
78
  }
79
 
80
  }
81
 
82
- private function cropTweets( $result, $count ) {
 
 
 
 
 
 
 
 
83
  if ( is_array( $result ) ) {
84
  return array_slice( $result, 0, $count );
85
  } else {
@@ -87,16 +135,32 @@ class WPT_TwitterFeed {
87
  }
88
  }
89
 
90
- private function getCacheLocation() {
 
 
 
91
  return $this->defaults['directory'] . '.tweetcache';
92
  }
93
 
94
- private function getOptionsHash( $options ) {
 
 
 
 
 
 
 
95
  $hash = md5( serialize( $options ) );
96
 
97
  return $hash;
98
  }
99
 
 
 
 
 
 
 
100
  private function save_cache( $file, $cache ) {
101
  $is_writable = wpt_is_writable( $file );
102
  if ( $is_writable ) {
@@ -106,6 +170,11 @@ class WPT_TwitterFeed {
106
  }
107
  }
108
 
 
 
 
 
 
109
  private function delete_cache( $file ) {
110
  $is_writable = wpt_is_writable( $file );
111
  if ( $is_writable ) {
@@ -113,20 +182,28 @@ class WPT_TwitterFeed {
113
  } else {
114
  delete_transient( 'wpt_cache' );
115
  }
116
- }
117
-
118
- private function checkValidCache( $screenname, $options ) {
 
 
 
 
 
 
 
 
119
  $delete_cache = get_option( 'wpt_delete_cache' );
120
- $file = $this->getCacheLocation();
121
-
122
- if ( $delete_cache == 'true' ) {
123
  update_option( 'wpt_delete_cache', 'false' );
124
  $this->delete_cache( $file );
125
  }
126
-
127
  if ( is_file( $file ) ) {
128
  $cache = file_get_contents( $file );
129
- $cache = @json_decode( $cache, true );
130
  if ( ! isset( $cache ) ) {
131
  unlink( $file );
132
 
@@ -134,14 +211,14 @@ class WPT_TwitterFeed {
134
  }
135
  } else {
136
  $cache = get_transient( 'wpt_cache' );
137
- $cache = @json_decode( $cache, true );
138
  if ( ! isset( $cache ) ) {
139
  return false;
140
  }
141
  }
142
- $cachename = $screenname . "-" . $this->getOptionsHash( $options );
143
 
144
- //Check if we have a cache for the user.
145
  if ( ! isset( $cache[ $cachename ] ) ) {
146
  return false;
147
  }
@@ -154,7 +231,7 @@ class WPT_TwitterFeed {
154
  }
155
 
156
  if ( $cache[ $cachename ]['time'] < ( time() - $this->defaults['cache_expire'] ) ) {
157
- $result = $this->oauthGetTweets( $screenname, $options );
158
  if ( ! isset( $result->error ) ) {
159
  return $result;
160
  }
@@ -163,13 +240,25 @@ class WPT_TwitterFeed {
163
  return $cache[ $cachename ]['tweets'];
164
  }
165
 
166
- private function oauthGetTweets( $screenname, $options ) {
 
 
 
 
 
 
 
 
167
  $key = $this->defaults['key'];
168
  $secret = $this->defaults['secret'];
169
  $token = $this->defaults['token'];
170
  $token_secret = $this->defaults['token_secret'];
171
- $cachename = $screenname . "-" . $this->getOptionsHash( $options );
172
- $options = array_merge( $options, array( 'screen_name' => $screenname, 'count' => 20, 'include_ext_alt_text' => 'true' ) );
 
 
 
 
173
 
174
  if ( empty( $key ) ) {
175
  return array( 'error' => __( 'Missing Consumer Key - Check settings', 'wp-to-twitter' ) );
@@ -190,10 +279,11 @@ class WPT_TwitterFeed {
190
  $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
191
 
192
  if ( isset( $options['search'] ) ) {
193
- $args = array( 'q' => urlencode( $options['search'] ),
194
- 'result_type' => urlencode( $options['result_type'] )
 
195
  );
196
- if ( $options['geocode'] != '' ) {
197
  $args['geocode'] = urlencode( $options['geocode'] );
198
  }
199
  $url = add_query_arg( $args, 'https://api.twitter.com/1.1/search/tweets.json' );
@@ -203,28 +293,30 @@ class WPT_TwitterFeed {
203
  }
204
  $result = json_decode( $result );
205
  if ( isset( $options['search'] ) ) {
206
- if ( !method_exists( $result, 'errors' ) ) {
207
- $result = $result->statuses;
208
  } else {
209
  $errors = $result->errors;
210
  $return = '';
211
  foreach ( $errors as $error ) {
212
  $return .= "<li>$error->message</li>";
213
  }
214
- echo "<ul>" . $return . "</ul>"; return;
 
215
  }
216
  }
217
- if ( is_file( $this->getCacheLocation() ) ) {
218
- $cache = json_decode( file_get_contents( $this->getCacheLocation() ), true );
219
  }
220
 
221
  if ( ! isset( $result->error ) ) {
222
  $cache[ $cachename ]['time'] = time();
223
  $cache[ $cachename ]['tweets'] = $result;
224
- $file = $this->getCacheLocation();
225
  $this->save_cache( $file, json_encode( $cache ) );
226
  } else {
227
  if ( is_array( $result ) && isset( $result['errors'][0] ) && isset( $result['errors'][0]['message'] ) ) {
 
228
  $last_error = '[' . date( 'r' ) . '] ' . sprintf( __( 'Twitter error: %s', 'wp-to-twitter' ), $result['errors'][0]['message'] );
229
  $this->st_last_error = $last_error;
230
  } else {
@@ -232,9 +324,9 @@ class WPT_TwitterFeed {
232
  $this->st_last_error = $last_error;
233
  }
234
  }
235
- // Run an action on the results output from the Twitter widget query
236
  do_action( 'wpt_process_tweets', $result, $screenname, $options );
237
 
238
  return $result;
239
  }
240
- }
1
  <?php
2
+ /**
3
+ * WP to Twitter Twitter Feed Class
4
+ *
5
+ * @category Widgets
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
 
 
 
 
 
 
15
 
16
+ require_once( 'class-wpt-twitteroauth.php' );
17
 
18
+ /**
19
+ * Based on Version 2.0.3, Twitter Feed for Developers by Storm Consultancy (Liam Gladdy)
20
+ * The base class for the storm twitter feed for developers.
21
+ */
22
  class WPT_TwitterFeed {
23
 
24
+ /**
25
+ * Default feed settings.
26
+ *
27
+ * @var $defaults.
28
+ */
29
  private $defaults = array(
30
  'directory' => '',
31
  'key' => '',
33
  'token' => '',
34
  'token_secret' => '',
35
  'screenname' => false,
36
+ 'cache_expire' => 1800,
37
  );
38
 
39
+ /**
40
+ * Last error, if any.
41
+ *
42
+ * @var $st_last_error
43
+ */
44
  public $st_last_error = false;
45
 
46
+ /**
47
+ * Constructor.
48
+ *
49
+ * @param array $args Arguments; merged with defaults.
50
+ */
51
  function __construct( $args = array() ) {
52
  $this->defaults = array_merge( $this->defaults, $args );
53
  }
54
 
55
+ /**
56
+ * Convert arguments into a string.
57
+ *
58
+ * @return print_r of arguments.
59
+ */
60
  function __toString() {
61
  return print_r( $this->defaults, true );
62
  }
63
 
64
+ /**
65
+ * Get Tweets for a given screen name.
66
+ *
67
+ * @param int $count Number of Tweets to fetch.
68
+ * @param string $screenname Twitter account feed to fetch.
69
+ * @param array $options Options to apply for display of feed.
70
+ *
71
+ * @return Tweets or error message.
72
+ */
73
+ function get_tweets( $count = 20, $screenname = false, $options = false ) {
74
  if ( $count > 20 ) {
75
  /**
76
  * Filters the max feed count. Default is 20, but you can change it.
85
  $count = 1;
86
  }
87
 
88
+ $default_options = array(
89
+ 'trim_user' => true,
90
+ 'exclude_replies' => true,
91
+ 'include_rts' => false,
92
+ );
93
 
94
+ if ( false === $options || ! is_array( $options ) ) {
95
  $options = $default_options;
96
  } else {
97
  $options = array_merge( $default_options, $options );
98
  }
99
 
100
+ if ( false === $screenname ) {
101
  $screenname = get_option( 'wtt_twitter_username' );
102
  }
103
 
104
+ $result = $this->check_valid_cache( $screenname, $options );
105
+ if ( false !== $result ) {
106
+ return $this->crop_tweets( $result, $count );
107
  }
108
 
109
+ // If we're here, we need to load.
110
+ $result = $this->oauth_get_tweets( $screenname, $options );
111
 
112
  if ( is_object( $result ) && isset( $result->error ) ) {
113
  $last_error = $result->error;
114
 
115
  return array( 'error' => 'Twitter said: ' . $last_error );
116
  } else {
117
+ return $this->crop_tweets( $result, $count );
118
  }
119
 
120
  }
121
 
122
+ /**
123
+ * Crop list of Tweets to display correct number of items.
124
+ *
125
+ * @param array $result Full query result.
126
+ * @param int $count Tweets to show.
127
+ *
128
+ * @return array
129
+ */
130
+ private function crop_tweets( $result, $count ) {
131
  if ( is_array( $result ) ) {
132
  return array_slice( $result, 0, $count );
133
  } else {
135
  }
136
  }
137
 
138
+ /**
139
+ * Locate cache.
140
+ */
141
+ private function get_cache_location() {
142
  return $this->defaults['directory'] . '.tweetcache';
143
  }
144
 
145
+ /**
146
+ * Hash options so cache is unique.
147
+ *
148
+ * @param array $options Display options.
149
+ *
150
+ * @return md5 hash.
151
+ */
152
+ private function get_options_hash( $options ) {
153
  $hash = md5( serialize( $options ) );
154
 
155
  return $hash;
156
  }
157
 
158
+ /**
159
+ * Save cache to file.
160
+ *
161
+ * @param string $file Cache file location.
162
+ * @param string $cache Data to save.
163
+ */
164
  private function save_cache( $file, $cache ) {
165
  $is_writable = wpt_is_writable( $file );
166
  if ( $is_writable ) {
170
  }
171
  }
172
 
173
+ /**
174
+ * Delete cache.
175
+ *
176
+ * @param string $file File name.
177
+ */
178
  private function delete_cache( $file ) {
179
  $is_writable = wpt_is_writable( $file );
180
  if ( $is_writable ) {
182
  } else {
183
  delete_transient( 'wpt_cache' );
184
  }
185
+ }
186
+
187
+ /**
188
+ * Fetch and verify cache.
189
+ *
190
+ * @param string $screenname Name to get cache for.
191
+ * @param array $options Options for cache being fetched.
192
+ *
193
+ * @return boolean or cache contents.
194
+ */
195
+ private function check_valid_cache( $screenname, $options ) {
196
  $delete_cache = get_option( 'wpt_delete_cache' );
197
+ $file = $this->get_cache_location();
198
+
199
+ if ( 'true' == $delete_cache ) {
200
  update_option( 'wpt_delete_cache', 'false' );
201
  $this->delete_cache( $file );
202
  }
203
+
204
  if ( is_file( $file ) ) {
205
  $cache = file_get_contents( $file );
206
+ $cache = json_decode( $cache, true );
207
  if ( ! isset( $cache ) ) {
208
  unlink( $file );
209
 
211
  }
212
  } else {
213
  $cache = get_transient( 'wpt_cache' );
214
+ $cache = json_decode( $cache, true );
215
  if ( ! isset( $cache ) ) {
216
  return false;
217
  }
218
  }
219
+ $cachename = $screenname . '-' . $this->get_options_hash( $options );
220
 
221
+ // Check if we have a cache for the user.
222
  if ( ! isset( $cache[ $cachename ] ) ) {
223
  return false;
224
  }
231
  }
232
 
233
  if ( $cache[ $cachename ]['time'] < ( time() - $this->defaults['cache_expire'] ) ) {
234
+ $result = $this->oauth_get_tweets( $screenname, $options );
235
  if ( ! isset( $result->error ) ) {
236
  return $result;
237
  }
240
  return $cache[ $cachename ]['tweets'];
241
  }
242
 
243
+ /**
244
+ * Fetch Tweets from Twitter.
245
+ *
246
+ * @param string $screenname Username.
247
+ * @param array $options Array of display options.
248
+ *
249
+ * @return Tweets.
250
+ */
251
+ private function oauth_get_tweets( $screenname, $options ) {
252
  $key = $this->defaults['key'];
253
  $secret = $this->defaults['secret'];
254
  $token = $this->defaults['token'];
255
  $token_secret = $this->defaults['token_secret'];
256
+ $cachename = $screenname . '-' . $this->get_options_hash( $options );
257
+ $options = array_merge( $options, array(
258
+ 'screen_name' => $screenname,
259
+ 'count' => 20,
260
+ 'include_ext_alt_text' => 'true',
261
+ ) );
262
 
263
  if ( empty( $key ) ) {
264
  return array( 'error' => __( 'Missing Consumer Key - Check settings', 'wp-to-twitter' ) );
279
  $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
280
 
281
  if ( isset( $options['search'] ) ) {
282
+ $args = array(
283
+ 'q' => urlencode( $options['search'] ),
284
+ 'result_type' => urlencode( $options['result_type'] ),
285
  );
286
+ if ( '' != $options['geocode'] ) {
287
  $args['geocode'] = urlencode( $options['geocode'] );
288
  }
289
  $url = add_query_arg( $args, 'https://api.twitter.com/1.1/search/tweets.json' );
293
  }
294
  $result = json_decode( $result );
295
  if ( isset( $options['search'] ) ) {
296
+ if ( ! method_exists( $result, 'errors' ) ) {
297
+ $result = ( is_object( $result ) ) ? $result->statuses : '';
298
  } else {
299
  $errors = $result->errors;
300
  $return = '';
301
  foreach ( $errors as $error ) {
302
  $return .= "<li>$error->message</li>";
303
  }
304
+ echo '<ul>' . $return . '</ul>';
305
+ return;
306
  }
307
  }
308
+ if ( is_file( $this->get_cache_location() ) ) {
309
+ $cache = json_decode( file_get_contents( $this->get_cache_location() ), true );
310
  }
311
 
312
  if ( ! isset( $result->error ) ) {
313
  $cache[ $cachename ]['time'] = time();
314
  $cache[ $cachename ]['tweets'] = $result;
315
+ $file = $this->get_cache_location();
316
  $this->save_cache( $file, json_encode( $cache ) );
317
  } else {
318
  if ( is_array( $result ) && isset( $result['errors'][0] ) && isset( $result['errors'][0]['message'] ) ) {
319
+ // Translators: Error message.
320
  $last_error = '[' . date( 'r' ) . '] ' . sprintf( __( 'Twitter error: %s', 'wp-to-twitter' ), $result['errors'][0]['message'] );
321
  $this->st_last_error = $last_error;
322
  } else {
324
  $this->st_last_error = $last_error;
325
  }
326
  }
327
+ // Run an action on the results output from the Twitter widget query.
328
  do_action( 'wpt_process_tweets', $result, $screenname, $options );
329
 
330
  return $result;
331
  }
332
+ }
classes/class-wpt-twitteroauth.php ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abraham Williams (abraham@abrah.am) http://abrah.am
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ *
11
+ * The first PHP Library to support WPOAuth for Twitter's REST API.
12
+ */
13
+
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ exit;
16
+ }
17
+
18
+ require_once( 'class-wp-oauth.php' );
19
+
20
+ if ( ! class_exists( 'Wpt_TwitterOAuth' ) ) {
21
+
22
+ /**
23
+ * Twitter WPOAuth class
24
+ */
25
+ class Wpt_TwitterOAuth {
26
+ /**
27
+ * Contains the last HTTP status code returned
28
+ *
29
+ * @var status code
30
+ */
31
+ public $http_code;
32
+ /**
33
+ * Contains the last API call.
34
+ *
35
+ * @var $url
36
+ */
37
+ public $url;
38
+ /**
39
+ * Set up the API root URL.
40
+ *
41
+ * @var $host
42
+ */
43
+ public $host = 'https://api.twitter.com/1.1/';
44
+ /**
45
+ * Set timeout default.
46
+ *
47
+ * @var $format
48
+ */
49
+ public $format = 'json';
50
+ /**
51
+ * Decode returned json data.
52
+ *
53
+ * @var $decode_json
54
+ */
55
+ public $decode_json = false;
56
+ /**
57
+ * Contains the last API call
58
+ *
59
+ * @var $last_api_call
60
+ */
61
+ private $last_api_call;
62
+ /**
63
+ * Contains the header
64
+ *
65
+ * @var $http_header
66
+ */
67
+ public $http_header;
68
+ /**
69
+ * Contains the body
70
+ *
71
+ * @var $body
72
+ */
73
+ public $body;
74
+
75
+ /**
76
+ * Set API URLS
77
+ *
78
+ * @return access token endpoint.
79
+ */
80
+ function access_token_url() {
81
+ return 'https://api.twitter.com/oauth/access_token';
82
+ }
83
+
84
+ /**
85
+ * Set authentication URL.
86
+ *
87
+ * @return authentication endpoint.
88
+ */
89
+ function authenticate_url() {
90
+ return 'https://api.twitter.com/oauth/authenticate';
91
+ }
92
+
93
+ /**
94
+ * Set authorization URL.
95
+ *
96
+ * @return authorization endpoint.
97
+ */
98
+ function authorize_url() {
99
+ return 'https://api.twitter.com/oauth/authorize';
100
+ }
101
+
102
+ /**
103
+ * Set request Token URL.
104
+ *
105
+ * @return request token ednpoint.
106
+ */
107
+ function request_token_url() {
108
+ return 'https://api.twitter.com/oauth/request_token';
109
+ }
110
+
111
+ /**
112
+ * Debug helpers
113
+ *
114
+ * @return last query's http code response.
115
+ */
116
+ function last_status_code() {
117
+ return $this->http_code;
118
+ }
119
+
120
+ /**
121
+ * Return last API call.
122
+ *
123
+ * @return last query API call.
124
+ */
125
+ function last_api_call() {
126
+ return $this->last_api_call;
127
+ }
128
+
129
+ /**
130
+ * Construct TwitterWPOAuth object
131
+ *
132
+ * @param string $consumer_key Consumer key.
133
+ * @param string $consumer_secret Consumer secret.
134
+ * @param string $wp_oauth_token Token.
135
+ * @param string $wp_oauth_token_secret Token secret.
136
+ */
137
+ function __construct( $consumer_key, $consumer_secret, $wp_oauth_token = null, $wp_oauth_token_secret = null ) {
138
+ $this->sha1_method = new WPOAuthSignatureMethod_HMAC_SHA1();
139
+ $this->consumer = new WPOAuthConsumer( $consumer_key, $consumer_secret );
140
+ if ( ! empty( $wp_oauth_token ) && ! empty( $wp_oauth_token_secret ) ) {
141
+ $this->token = new WPOAuthConsumer( $wp_oauth_token, $wp_oauth_token_secret );
142
+ } else {
143
+ $this->token = null;
144
+ }
145
+ }
146
+
147
+
148
+ /**
149
+ * Get a request_token from Twitter
150
+ *
151
+ * @returns a key/value array containing WPOAuth_token and WPOAuth_token_secret
152
+ */
153
+ function get_request_token() {
154
+ $r = $this->wp_oauth_request( $this->request_token_url() );
155
+ $token = $this->wp_oauth_parse_response( $r );
156
+ $this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
157
+
158
+ return $token;
159
+ }
160
+
161
+ /**
162
+ * Parse a URL-encoded WPOAuth response
163
+ *
164
+ * @param string $response_string String from response.
165
+ *
166
+ * @return a key/value array
167
+ */
168
+ function wp_oauth_parse_response( $response_string ) {
169
+ $r = array();
170
+ foreach ( explode( '&', $response_string ) as $param ) {
171
+ $pair = explode( '=', $param, 2 );
172
+ if ( count( $pair ) != 2 ) {
173
+ continue;
174
+ }
175
+ $r[ urldecode( $pair[0] ) ] = urldecode( $pair[1] );
176
+ }
177
+
178
+ return $r;
179
+ }
180
+
181
+ /**
182
+ * Get the authorize URL
183
+ *
184
+ * @param array $token Token array.
185
+ *
186
+ * @returns a string
187
+ */
188
+ function getauthorize_url( $token ) {
189
+ if ( is_array( $token ) ) {
190
+ $token = $token['WPOAuth_token'];
191
+ }
192
+
193
+ return $this->authorize_url() . '?WPOAuth_token=' . $token;
194
+ }
195
+
196
+
197
+ /**
198
+ * Get the authenticate URL
199
+ *
200
+ * @param array $token Token array.
201
+ *
202
+ * @returns a string
203
+ */
204
+ function getauthenticate_url( $token ) {
205
+ if ( is_array( $token ) ) {
206
+ $token = $token['WPOAuth_token'];
207
+ }
208
+
209
+ return $this->authenticate_url() . '?WPOAuth_token=' . $token;
210
+ }
211
+
212
+ /**
213
+ * Exchange the request token and secret for an access token and secret, to sign API calls.
214
+ *
215
+ * @param array $token Token array.
216
+ *
217
+ * @returns array("WPOAuth_token" => the access token, "WPOAuth_token_secret" => the access secret)
218
+ */
219
+ function get_access_token( $token = null ) {
220
+ $r = $this->wp_oauth_request( $this->access_token_url() );
221
+ $token = $this->wp_oauth_parse_response( $r );
222
+ $this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
223
+
224
+ return $token;
225
+ }
226
+
227
+ /**
228
+ * Wrapper for POST requests
229
+ *
230
+ * @param string $url URL.
231
+ * @param array $parameters Request params.
232
+ *
233
+ * @return decoded response.
234
+ */
235
+ function post( $url, $parameters = array() ) {
236
+ $response = $this->wp_oauth_request( $url, $parameters, 'POST' );
237
+ if ( 'json' === $this->format && $this->decode_json ) {
238
+ return json_decode( $response );
239
+ }
240
+
241
+ return $response;
242
+ }
243
+
244
+ /**
245
+ * Wrapper for MEDIA requests
246
+ *
247
+ * @param string $url URL.
248
+ * @param array $parameters Request params.
249
+ *
250
+ * @return decoded response.
251
+ */
252
+ function media( $url, $parameters = array() ) {
253
+ $response = $this->wp_oauth_request( $url, $parameters, 'MEDIA' );
254
+ if ( 'json' === $this->format && $this->decode_json ) {
255
+ return json_decode( $response );
256
+ }
257
+
258
+ return $response;
259
+ }
260
+
261
+ /**
262
+ * Wrapper for GET requests
263
+ *
264
+ * @param string $url URL.
265
+ * @param array $parameters Request params.
266
+ *
267
+ * @return decoded response.
268
+ */
269
+ function get( $url, $parameters = array() ) {
270
+ $response = $this->wp_oauth_request( $url, $parameters, 'GET' );
271
+ if ( 'json' === $this->format && $this->decode_json ) {
272
+ return json_decode( $response );
273
+ }
274
+
275
+ return $response;
276
+ }
277
+
278
+ /**
279
+ * Handles a status update that includes an image.
280
+ *
281
+ * @param string $url Target URL.
282
+ * @param array $args Array of arguments to send.
283
+ *
284
+ * @return boolean
285
+ */
286
+ function handle_media_request( $url, $args = array() ) {
287
+ // Load tmhOAuth for Media uploads only when needed: https://github.com/themattharris/tmhOAuth.
288
+ // It's not possible to upload media using WP_HTTP, so this needs to use cURL.
289
+ if ( ! class_exists( 'tmhOAuth' ) ) {
290
+ require_once( plugin_dir_path( __FILE__ ) . 'class-tmhoauth.php' );
291
+ }
292
+ $auth = $args['auth'];
293
+ if ( ! $auth ) {
294
+ $ack = get_option( 'app_consumer_key' );
295
+ $acs = get_option( 'app_consumer_secret' );
296
+ $ot = get_option( 'oauth_token' );
297
+ $ots = get_option( 'oauth_token_secret' );
298
+ } else {
299
+ $ack = get_user_meta( $auth, 'app_consumer_key', true );
300
+ $acs = get_user_meta( $auth, 'app_consumer_secret', true );
301
+ $ot = get_user_meta( $auth, 'oauth_token', true );
302
+ $ots = get_user_meta( $auth, 'oauth_token_secret', true );
303
+ }
304
+ // when performing as a scheduled action, need to include file.php.
305
+ if ( ! function_exists( 'get_home_path' ) ) {
306
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
307
+ }
308
+ $connect = array(
309
+ 'consumer_key' => $ack,
310
+ 'consumer_secret' => $acs,
311
+ 'user_token' => $ot,
312
+ 'user_secret' => $ots,
313
+ );
314
+ $tmh_oauth = new TmhOAuth( $connect );
315
+ $attachment = $args['media'];
316
+
317
+ $image_sizes = get_intermediate_image_sizes();
318
+ if ( in_array( 'large', $image_sizes ) ) {
319
+ $size = 'large';
320
+ } else {
321
+ $size = array_pop( $image_sizes );
322
+ }
323
+ $upload = wp_get_attachment_image_src( $attachment, apply_filters( 'wpt_upload_image_size', $size ) );
324
+ $image_url = $upload[0];
325
+ $remote = wp_remote_get( $image_url );
326
+ if ( is_wp_error( $remote ) ) {
327
+ $transport = 'curl';
328
+ $binary = wp_get_curl( $image_url );
329
+ } else {
330
+ $transport = 'wp_http';
331
+ $binary = wp_remote_retrieve_body( $remote );
332
+ }
333
+ wpt_mail( 'Media fetched binary', print_r( $remote, 1 ) . "\n\n" . print_r( $binary, 1 ) );
334
+ if ( ! $binary ) {
335
+ return;
336
+ }
337
+
338
+ $mime_type = get_post_mime_type( $attachment );
339
+ if ( ! $mime_type ) {
340
+ $mime_type = 'image/jpeg';
341
+ }
342
+
343
+ $code = $tmh_oauth->request( 'POST', $url, array( 'media' => "$binary" ), true, true );
344
+ $response = $tmh_oauth->response['response'];
345
+ $full = $tmh_oauth->response;
346
+ wpt_mail( 'Media Posted', "
347
+ Media ID #$args[media] ($transport)" . "\n\n" .
348
+ 'Twitter Response' . "\n" . print_r( $full, 1 ) . "\n\n" .
349
+ 'Attachment Details' . "\n" . print_r( $upload, 1 ) . "\n\n" .
350
+ 'Img Request Response' . "\n" . print_r( $remote, 1 )
351
+ );
352
+
353
+ if ( is_wp_error( $response ) ) {
354
+ return '';
355
+ }
356
+
357
+ $this->http_code = $code;
358
+ $this->last_api_call = $url;
359
+ $this->format = 'json';
360
+ $this->http_header = $response;
361
+ $response = json_decode( $response );
362
+ $media_id = $response->media_id_string;
363
+
364
+ return $media_id;
365
+ }
366
+
367
+ /**
368
+ * Format and sign an WPOAuth / API request
369
+ *
370
+ * @param string $url Target URL.
371
+ * @param array $args Arguments for signing.
372
+ * @param string $method Method type.
373
+ *
374
+ * @return Request.
375
+ */
376
+ function wp_oauth_request( $url, $args = array(), $method = null ) {
377
+ // Handle media requests using tmhOAuth library.
378
+ if ( 'MEDIA' == $method ) {
379
+ return $this->handle_media_request( $url, $args );
380
+ }
381
+
382
+ if ( empty( $method ) ) {
383
+ $method = empty( $args ) ? 'GET' : 'POST';
384
+ }
385
+ $req = WP_Oauth_Request::from_consumer_and_token( $this->consumer, $this->token, $method, $url, $args );
386
+ $req->sign_request( $this->sha1_method, $this->consumer, $this->token );
387
+
388
+ $response = false;
389
+ $url = null;
390
+
391
+ switch ( $method ) {
392
+ case 'GET':
393
+ $url = $req->to_url();
394
+ $response = wp_remote_get( $url );
395
+ break;
396
+ case 'POST':
397
+ // TODO: if JSON, need to authenticate, pass bearer authentication as header in query.
398
+ // TODO: add content-type when JSON.
399
+ $url = $req->get_normalized_http_url();
400
+ $args = wp_parse_args( $req->to_postdata() );
401
+ $response = wp_remote_post( $url, array(
402
+ 'body' => $args,
403
+ 'timeout' => 30,
404
+ ) );
405
+ break;
406
+ }
407
+
408
+ if ( is_wp_error( $response ) ) {
409
+ return false;
410
+ }
411
+ $this->http_code = $response['response']['code'];
412
+ $this->body = json_decode( $response['body'] );
413
+ $this->last_api_call = $url;
414
+ $this->format = 'json';
415
+ $this->http_header = $response['headers'];
416
+
417
+ return $response['body'];
418
+ }
419
+ }
420
+ }
css/styles.css CHANGED
@@ -209,12 +209,12 @@ label[for="wpt_license_key"] {
209
  }
210
 
211
  .tweet {
212
- background: #070 url(../images/Ok.png) right 50% no-repeat;
213
  color: #fff;
214
  }
215
 
216
  .notweet {
217
- background: #9d1309 url(../images/Error.png) right 50% no-repeat;
218
  color: #fff;
219
  }
220
 
209
  }
210
 
211
  .tweet {
212
+ background: #070 url(../images/Ok.png) 99% 50% no-repeat;
213
  color: #fff;
214
  }
215
 
216
  .notweet {
217
+ background: #9d1309 url(../images/Error.png) 99% 50% no-repeat;
218
  color: #fff;
219
  }
220
 
readme.txt CHANGED
@@ -4,9 +4,10 @@ Donate link: http://www.joedolson.com/donate/
4
  Tags: twitter, microblogging, su.pr, bitly, yourls, redirect, shortener, post, links, social, sharing, media, tweet
5
  Requires at least: 4.4
6
  Tested up to: 4.9
 
7
  License: GPLv2 or later
8
  Text Domain: wp-to-twitter
9
- Stable tag: 3.3.2
10
 
11
  Posts a Twitter update when you update your WordPress blog or add a link, with your chosen URL shortening service.
12
 
@@ -64,6 +65,21 @@ Check out my <a href="https://github.com/joedolson/plugin-extensions/tree/master
64
 
65
  == Changelog ==
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  = 3.3.2 =
68
 
69
  * If short URL already stored, do not execute shortening routine
4
  Tags: twitter, microblogging, su.pr, bitly, yourls, redirect, shortener, post, links, social, sharing, media, tweet
5
  Requires at least: 4.4
6
  Tested up to: 4.9
7
+ Requires PHP: 5.3
8
  License: GPLv2 or later
9
  Text Domain: wp-to-twitter
10
+ Stable tag: 3.3.3
11
 
12
  Posts a Twitter update when you update your WordPress blog or add a link, with your chosen URL shortening service.
13
 
65
 
66
  == Changelog ==
67
 
68
+ = 3.3.3 =
69
+
70
+ * Removed: upgrade paths from version 2.4.x
71
+ * Removed: support for YOURLS version 1.3
72
+ * Removed: support for Twitter Friendly Links (plug-in not updated in 8 years)
73
+ * Removed: Ability to enable the Goo.gl URL shortener (see: https://developers.google.com/url-shortener/)
74
+ * Removed: fallback functions required for PHP 4 support.
75
+ * Add 'show images' as option in feeds.
76
+ * Support for alt attributes displayed in Feeds
77
+ * Improved URL generation to link to searched Tweets.
78
+ * Improve parsing of URLs in Tweets.
79
+ * Don't save URLs if no shortener used or shortener returns no value.
80
+ * Option to ignore stored URLs when sending Tweets.
81
+ * Code now conforms with WordPress PHP standards with the exception of four deprecated functions.
82
+
83
  = 3.3.2 =
84
 
85
  * If short URL already stored, do not execute shortening routine
tmhOAuth/LICENSE DELETED
@@ -1,202 +0,0 @@
1
-
2
- Apache License
3
- Version 2.0, January 2004
4
- http://www.apache.org/licenses/
5
-
6
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
-
8
- 1. Definitions.
9
-
10
- "License" shall mean the terms and conditions for use, reproduction,
11
- and distribution as defined by Sections 1 through 9 of this document.
12
-
13
- "Licensor" shall mean the copyright owner or entity authorized by
14
- the copyright owner that is granting the License.
15
-
16
- "Legal Entity" shall mean the union of the acting entity and all
17
- other entities that control, are controlled by, or are under common
18
- control with that entity. For the purposes of this definition,
19
- "control" means (i) the power, direct or indirect, to cause the
20
- direction or management of such entity, whether by contract or
21
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
- outstanding shares, or (iii) beneficial ownership of such entity.
23
-
24
- "You" (or "Your") shall mean an individual or Legal Entity
25
- exercising permissions granted by this License.
26
-
27
- "Source" form shall mean the preferred form for making modifications,
28
- including but not limited to software source code, documentation
29
- source, and configuration files.
30
-
31
- "Object" form shall mean any form resulting from mechanical
32
- transformation or translation of a Source form, including but
33
- not limited to compiled object code, generated documentation,
34
- and conversions to other media types.
35
-
36
- "Work" shall mean the work of authorship, whether in Source or
37
- Object form, made available under the License, as indicated by a
38
- copyright notice that is included in or attached to the work
39
- (an example is provided in the Appendix below).
40
-
41
- "Derivative Works" shall mean any work, whether in Source or Object
42
- form, that is based on (or derived from) the Work and for which the
43
- editorial revisions, annotations, elaborations, or other modifications
44
- represent, as a whole, an original work of authorship. For the purposes
45
- of this License, Derivative Works shall not include works that remain
46
- separable from, or merely link (or bind by name) to the interfaces of,
47
- the Work and Derivative Works thereof.
48
-
49
- "Contribution" shall mean any work of authorship, including
50
- the original version of the Work and any modifications or additions
51
- to that Work or Derivative Works thereof, that is intentionally
52
- submitted to Licensor for inclusion in the Work by the copyright owner
53
- or by an individual or Legal Entity authorized to submit on behalf of
54
- the copyright owner. For the purposes of this definition, "submitted"
55
- means any form of electronic, verbal, or written communication sent
56
- to the Licensor or its representatives, including but not limited to
57
- communication on electronic mailing lists, source code control systems,
58
- and issue tracking systems that are managed by, or on behalf of, the
59
- Licensor for the purpose of discussing and improving the Work, but
60
- excluding communication that is conspicuously marked or otherwise
61
- designated in writing by the copyright owner as "Not a Contribution."
62
-
63
- "Contributor" shall mean Licensor and any individual or Legal Entity
64
- on behalf of whom a Contribution has been received by Licensor and
65
- subsequently incorporated within the Work.
66
-
67
- 2. Grant of Copyright License. Subject to the terms and conditions of
68
- this License, each Contributor hereby grants to You a perpetual,
69
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
- copyright license to reproduce, prepare Derivative Works of,
71
- publicly display, publicly perform, sublicense, and distribute the
72
- Work and such Derivative Works in Source or Object form.
73
-
74
- 3. Grant of Patent License. Subject to the terms and conditions of
75
- this License, each Contributor hereby grants to You a perpetual,
76
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
- (except as stated in this section) patent license to make, have made,
78
- use, offer to sell, sell, import, and otherwise transfer the Work,
79
- where such license applies only to those patent claims licensable
80
- by such Contributor that are necessarily infringed by their
81
- Contribution(s) alone or by combination of their Contribution(s)
82
- with the Work to which such Contribution(s) was submitted. If You
83
- institute patent litigation against any entity (including a
84
- cross-claim or counterclaim in a lawsuit) alleging that the Work
85
- or a Contribution incorporated within the Work constitutes direct
86
- or contributory patent infringement, then any patent licenses
87
- granted to You under this License for that Work shall terminate
88
- as of the date such litigation is filed.
89
-
90
- 4. Redistribution. You may reproduce and distribute copies of the
91
- Work or Derivative Works thereof in any medium, with or without
92
- modifications, and in Source or Object form, provided that You
93
- meet the following conditions:
94
-
95
- (a) You must give any other recipients of the Work or
96
- Derivative Works a copy of this License; and
97
-
98
- (b) You must cause any modified files to carry prominent notices
99
- stating that You changed the files; and
100
-
101
- (c) You must retain, in the Source form of any Derivative Works
102
- that You distribute, all copyright, patent, trademark, and
103
- attribution notices from the Source form of the Work,
104
- excluding those notices that do not pertain to any part of
105
- the Derivative Works; and
106
-
107
- (d) If the Work includes a "NOTICE" text file as part of its
108
- distribution, then any Derivative Works that You distribute must
109
- include a readable copy of the attribution notices contained
110
- within such NOTICE file, excluding those notices that do not
111
- pertain to any part of the Derivative Works, in at least one
112
- of the following places: within a NOTICE text file distributed
113
- as part of the Derivative Works; within the Source form or
114
- documentation, if provided along with the Derivative Works; or,
115
- within a display generated by the Derivative Works, if and
116
- wherever such third-party notices normally appear. The contents
117
- of the NOTICE file are for informational purposes only and
118
- do not modify the License. You may add Your own attribution
119
- notices within Derivative Works that You distribute, alongside
120
- or as an addendum to the NOTICE text from the Work, provided
121
- that such additional attribution notices cannot be construed
122
- as modifying the License.
123
-
124
- You may add Your own copyright statement to Your modifications and
125
- may provide additional or different license terms and conditions
126
- for use, reproduction, or distribution of Your modifications, or
127
- for any such Derivative Works as a whole, provided Your use,
128
- reproduction, and distribution of the Work otherwise complies with
129
- the conditions stated in this License.
130
-
131
- 5. Submission of Contributions. Unless You explicitly state otherwise,
132
- any Contribution intentionally submitted for inclusion in the Work
133
- by You to the Licensor shall be under the terms and conditions of
134
- this License, without any additional terms or conditions.
135
- Notwithstanding the above, nothing herein shall supersede or modify
136
- the terms of any separate license agreement you may have executed
137
- with Licensor regarding such Contributions.
138
-
139
- 6. Trademarks. This License does not grant permission to use the trade
140
- names, trademarks, service marks, or product names of the Licensor,
141
- except as required for reasonable and customary use in describing the
142
- origin of the Work and reproducing the content of the NOTICE file.
143
-
144
- 7. Disclaimer of Warranty. Unless required by applicable law or
145
- agreed to in writing, Licensor provides the Work (and each
146
- Contributor provides its Contributions) on an "AS IS" BASIS,
147
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
- implied, including, without limitation, any warranties or conditions
149
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
- PARTICULAR PURPOSE. You are solely responsible for determining the
151
- appropriateness of using or redistributing the Work and assume any
152
- risks associated with Your exercise of permissions under this License.
153
-
154
- 8. Limitation of Liability. In no event and under no legal theory,
155
- whether in tort (including negligence), contract, or otherwise,
156
- unless required by applicable law (such as deliberate and grossly
157
- negligent acts) or agreed to in writing, shall any Contributor be
158
- liable to You for damages, including any direct, indirect, special,
159
- incidental, or consequential damages of any character arising as a
160
- result of this License or out of the use or inability to use the
161
- Work (including but not limited to damages for loss of goodwill,
162
- work stoppage, computer failure or malfunction, or any and all
163
- other commercial damages or losses), even if such Contributor
164
- has been advised of the possibility of such damages.
165
-
166
- 9. Accepting Warranty or Additional Liability. While redistributing
167
- the Work or Derivative Works thereof, You may choose to offer,
168
- and charge a fee for, acceptance of support, warranty, indemnity,
169
- or other liability obligations and/or rights consistent with this
170
- License. However, in accepting such obligations, You may act only
171
- on Your own behalf and on Your sole responsibility, not on behalf
172
- of any other Contributor, and only if You agree to indemnify,
173
- defend, and hold each Contributor harmless for any liability
174
- incurred by, or claims asserted against, such Contributor by reason
175
- of your accepting any such warranty or additional liability.
176
-
177
- END OF TERMS AND CONDITIONS
178
-
179
- APPENDIX: How to apply the Apache License to your work.
180
-
181
- To apply the Apache License to your work, attach the following
182
- boilerplate notice, with the fields enclosed by brackets "[]"
183
- replaced with your own identifying information. (Don't include
184
- the brackets!) The text should be enclosed in the appropriate
185
- comment syntax for the file format. We also recommend that a
186
- file or class name and description of purpose be included on the
187
- same "printed page" as the copyright notice for easier
188
- identification within third-party archives.
189
-
190
- Copyright [yyyy] [name of copyright owner]
191
-
192
- Licensed under the Apache License, Version 2.0 (the "License");
193
- you may not use this file except in compliance with the License.
194
- You may obtain a copy of the License at
195
-
196
- http://www.apache.org/licenses/LICENSE-2.0
197
-
198
- Unless required by applicable law or agreed to in writing, software
199
- distributed under the License is distributed on an "AS IS" BASIS,
200
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
- See the License for the specific language governing permissions and
202
- limitations under the License.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tmhOAuth/README.md DELETED
@@ -1,211 +0,0 @@
1
- # tmhOAuth
2
-
3
- An OAuth 1.0A library written in PHP by @themattharris, specifically for use
4
- with the Twitter API.
5
-
6
- **Disclaimer**: This project is a work in progress. Please use the issue tracker
7
- to report any enhancements or issues you encounter.
8
-
9
- ## Goals
10
-
11
- - Support OAuth 1.0A
12
- - Use Authorisation headers instead of query string or POST parameters
13
- - Allow uploading of images
14
- - Provide enough information to assist with debugging
15
-
16
- ## Dependencies
17
-
18
- The library has been tested with PHP 5.3+ and relies on CURL and hash_hmac. The
19
- vast majority of hosting providers include these libraries and run with PHP 5.1+.
20
-
21
- The code makes use of hash_hmac, which was introduced in PHP 5.1.2. If your version
22
- of PHP is lower than this you should ask your hosting provider for an update.
23
-
24
- ## A note about security and SSL
25
-
26
- Version 0.60 hardened the security of the library and defaulted `curl_ssl_verifypeer` to `true`.
27
- As some hosting providers do not provide the most current certificate root file
28
- it is now included in this repository. If the version is out of date OR you prefer
29
- to download the certificate roots yourself, you can get them
30
- from: http://curl.haxx.se/ca/cacert.pem
31
-
32
- Before upgrading the version of tmhOAuth that you use, be sure to verify the SSL
33
- handling works on your server by running the `examples/verify_ssl.php` script.
34
-
35
- ## Usage
36
-
37
- This will be built out later but for the moment review the examples repository
38
- <https://github.com/themattharris/tmhOAuth-examples> for ways the library can be
39
- used. Each example contains instructions on how to use it.
40
-
41
- ## Notes for users of previous versions
42
-
43
- If you previously used version 0.4 be aware the utility functions
44
- have now been broken into their own file. Before you use version 0.5+ in your app
45
- test locally to ensure your code doesn't need tmhUtilities included.
46
-
47
- If you used custom HTTP request headers when they were defined as `'key: value'` strings
48
- you should now define them as `'key' => 'value'` pairs.
49
-
50
- Versions prior to 0.7.3 collapsed headers with the same value into one
51
- $tmhOAuth->response['headers'] key. Since 0.7.3 headers with the same key will use an array
52
- to store their values.
53
-
54
- ## Change History
55
- ### 0.7.5 - 20 Februrary 2013
56
- - tidying up of composer.json. (Issue #112) Props: ceeram
57
-
58
- ### 0.7.4 - 19 Februrary 2013
59
- - corrections to composer.json to support packagists requirements. (Issue #110)
60
-
61
- ### 0.7.3 - 18 Februrary 2013
62
- - add support for making requests with the host header being different to the request host.
63
- - ensure headers with the same key do not overwrite each other in $tmhOAuth->response['headers'].
64
- - removed examples submodule in favor of examples including tmhOAuth, rather than tmhOAuth including examples
65
- - made it so that if param values are sent to $tmhOAuth->request as an array (key -> array()) then $tmhOAuth->prepare_params will now implode them using ','
66
- - fixed composer. (Issue #99). Props: rasa
67
- - fixed PHPDoc. (Issue #47). Props: trante
68
- - instead of void, $tmhOAuth->curlit now returns 0 if 'prevent_request' is set
69
-
70
- ### 0.7.2 - 01 November 2012
71
- - use DIRECTORY_SEPARATOR for multi-environment support. (Issue #80) Props: whallz
72
- - tidied up the curlHeader function to use explode instead of substr and store the keys in the format they are returned from the API
73
- - removed content-length hack as it isn't needed if CURLOPT_POSTFIELDS is initialized on all POSTs
74
- - removed the expects header hack as Twitter no longer requires it to be there
75
- - introduce composer.json. (Issues #39, #77, #85) Props: akandels, conradkleinespel, dguyon, kud, philsturgeon, willdurand
76
- - added support for specifying custom headers when using $tmhOAuth->request. (Issue #98)
77
-
78
- ### 0.7.1 - 27 October 2012
79
- - set content-length to 0 explictly to avoid a bug between libcurl and Twitter. (Issue #94)
80
- - allow initialization without a configuration array (default config to array())
81
- - prevent ->url allowing double slashes in paths
82
-
83
- ### 0.7.0 - 04 September 2012
84
- - changed version numbers to x.y.z format
85
- - stronger method scoping (public and private)
86
- - Typo fix in depenencies. (Issue #42) Props: tantek
87
- - Only lowercase the host and scheme, and not path, in prepare_url. (Issue #56) Props: uzyn
88
- - Fixed a number of PHP warnings by changing some tmhUtilty methods to static. (Issue #52) Props: DrayChou
89
- - Raw headers and response body are now available as `$tmhOAuth->response['raw']`
90
- - Moved the examples to their own repository <https://github.com/themattharris/tmhOAuth-examples>
91
- - Removed the `noexamples` branch as master does not contain examples anymore
92
- - Introduced `$tmhOAuth->config['timezone']` and set `date_default_timezone_set`. (Issue #70) Props: iamctodd
93
-
94
- ### 0.621 - 12 March 2012
95
- - Ensure `$_SERVER['HTTPS']` isset before checking it's value. Props: kud
96
-
97
- ### 0.62 - 01 March 2012
98
- - Fix array merging bug. Props: julien-c
99
- - use is_callable instead of function_exists: Props: samwierema
100
- - Allow options to be specified for the entify function. Props: davidcroda
101
- - protocol was not inferred correctly for https when ['HTTPS'] == 'on'. Props: ospector
102
- - Switched to https for twitter.com display URLs
103
- - Improved the search results example
104
-
105
- ### 0.61 - 16 January 2012
106
- - Removed trailing ?> from tmhOAuth.php and tmhUtilities.php to meet the Zend Framework's coding practices. Props: reedy
107
- - Fixed bug where CURLOPT_SSL_VERIFYHOST was defaulted to true when it should have been defaulted to 2. Props: kevinsmcarthur
108
-
109
- ### 0.60 - 29 December 2011
110
- - Changed any use of implode to the preferred format of implode($glue, $pieces). Props: reedy
111
- - Moved oauth_verifier to the authorization header as shown in example of RFC 5849. Props: spacenick
112
- - added curl error and error number values to the $tmhOAuth->response object
113
- - added an example script for testing the SSL connection to twitter.com with the new SSL configuration of tmhOAuth
114
- - added a function to generate the useragent depending on whether SSL is on or not
115
- - defaulted CURLOPT_SSL_VERIFYPEER to true
116
- - added CURLOPT_SSL_VERIFYHOST and defaulted it to true
117
- - added the most current cacert.pem file from http://curl.haxx.se/ca/cacert.pem and configured curl to use it
118
-
119
- ### 0.58 - 29 December 2011
120
- - Rearranged some configuration variables around to make commenting easier
121
- - Standarised on lowercase booleans
122
-
123
- ### 0.57 - 11 December 2011
124
- - Fixed prevent_request so OAuth Echo requests work again.
125
- - Added a TwitPic OAuth Echo example
126
-
127
- ### 0.56 - 29 September 2011
128
- - Fixed version reference in the UserAgent
129
- - Updated tmhUtilities::entify with support for media
130
- - Updated tmhUtilities::entify with support for multibyte characters. Props: andersonshatch
131
-
132
- ### 0.55 - 29 September 2011
133
- - Added support for content encoding. Defaults to whatever localhost supports. Props: yusuke
134
-
135
- ### 0.54 - 29 September 2011
136
- - User-Agent is now configurable and includes the current version number of the script
137
- - Updated the Streaming examples to use SSL
138
-
139
- ### 0.53 - 15 July 2011
140
- - Fixed issue where headers were being duplicated if the library was called more than once.
141
- - Updated examples to fit the new location of access tokens and secrets on dev.twitter.com
142
- - Added Photo Tweet example
143
-
144
- ### 0.52 - 06 July 2011
145
- - Fixed issue where the preference for include_time in create_nonce was being ignored
146
-
147
- ### 0.51 - 06 July 2011
148
- - Use isset instead of suppress errors. Props: funkatron
149
- - Added example of using the Search API
150
- - Added example of using friends/ids and users/lookup to get details of a users friends
151
- - Added example of the authorize OAuth webflow
152
-
153
- ### 0.5 - 29 March 2011
154
- - Moved utility functions out of the main class and into the tmhUtilities class.
155
- - Added the ability to send OAuth parameters as part of the querystring or POST body.
156
- - Section 3.4.1.2 says the url must be lowercase so prepare URL now does this.
157
- - Added a convenience method for accessing the safe_encode/decode transforms.
158
- - Updated the examples to use the new utilities library.
159
- - Added examples for sitestreams and userstreams.
160
- - Added a more advanced streaming API example.
161
-
162
- ### 0.4 - 03 March 2011
163
- - Fixed handling of parameters when using DELETE. Thanks to yusuke for reporting
164
- - Fixed php_self to handle port numbers other than 80/443. Props: yusuke
165
- - Updated function pr to use pre only when not running in CLI mode
166
- - Add support for proxy servers. Props juanchorossi
167
- - Function request now returns the HTTP status code. Props: kronenthaler
168
- - Documentation fixes for xAuth. Props: 140dev
169
- - Some minor code formatting changes
170
-
171
- ### 0.3 - 28 September 2010
172
- - Moved entities rendering into the library
173
-
174
- ### 0.2 - 17 September 2010
175
- - Added support for the Streaming API
176
-
177
- ### 0.14 - 17 September 2010
178
- - Fixed authorisation header for use with OAuth Echo
179
-
180
- ### 0.13 - 17 September 2010
181
- - Added use_ssl configuration parameter
182
- - Fixed config array typo
183
- - Removed v from the config
184
- - Remove protocol from the host (configured by use_ssl)
185
- - Added include for easier debugging
186
-
187
- ### 0.12 - 17 September 2010
188
-
189
- - Moved curl options to config
190
- - Added the ability for curl to follow redirects, default false
191
-
192
- ### 0.11 - 17 September 2010
193
-
194
- - Fixed a bug in the GET requests
195
-
196
- ### 0.1 - 26 August 2010
197
-
198
- - Initial beta version
199
-
200
- ## Community
201
-
202
- License: Apache 2 (see [included LICENSE file](https://github.com/themattharris/tmhOAuth/blob/master/LICENSE))
203
-
204
- Follow [@tmhOAuth](https://twitter.com/intent/follow?screen_name=tmhOAuth) to receive updates on releases, or ask for support
205
- Follow me on Twitter: [@themattharris](https://twitter.com/intent/follow?screen_name=themattharris)
206
- Check out the Twitter Developer Resources: <https://dev.twitter.com>
207
-
208
- ## To Do
209
-
210
- - Add good behavior logic to the Streaming API handler - i.e. on disconnect back off
211
- - Async Curl support
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tmhOAuth/composer.json DELETED
@@ -1,26 +0,0 @@
1
- {
2
- "name": "themattharris/tmhoauth",
3
- "description": "An OAuth 1.0A library written in PHP by @themattharris, specifically for use with the Twitter API",
4
- "license": "Apache-2.0",
5
- "authors": [
6
- {
7
- "name": "themattharris",
8
- "email": "matt@themattharris.com",
9
- "role": "Developer"
10
- }
11
- ],
12
- "keywords": [
13
- "twitter",
14
- "oauth"
15
- ],
16
- "support": {
17
- "issues": "https://github.com/themattharris/tmhOAuth/issues"
18
- },
19
- "require": {
20
- "php": ">=5.3.0",
21
- "ext-curl": "*"
22
- },
23
- "autoload": {
24
- "psr-0": {"tmhOAuth": ""}
25
- }
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tmhOAuth/tmhUtilities.php DELETED
@@ -1,301 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * tmhUtilities
5
- *
6
- * Helpful utility and Twitter formatting functions
7
- *
8
- * @author themattharris
9
- * @version 0.5.0
10
- *
11
- * 04 September 2012
12
- */
13
- class tmhUtilities {
14
- const VERSION = '0.5.0';
15
-
16
- /**
17
- * Entifies the tweet using the given entities element.
18
- * Deprecated.
19
- * You should instead use entify_with_options.
20
- *
21
- * @param array $tweet the json converted to normalised array
22
- * @param array $replacements if specified, the entities and their replacements will be stored to this variable
23
- *
24
- * @return the tweet text with entities replaced with hyperlinks
25
- */
26
- public static function entify( $tweet, &$replacements = array() ) {
27
- return tmhUtilities::entify_with_options( $tweet, array(), $replacements );
28
- }
29
-
30
- /**
31
- * Entifies the tweet using the given entities element, using the provided
32
- * options.
33
- *
34
- * @param array $tweet the json converted to normalised array
35
- * @param array $options settings to be used when rendering the entities
36
- * @param array $replacements if specified, the entities and their replacements will be stored to this variable
37
- *
38
- * @return the tweet text with entities replaced with hyperlinks
39
- */
40
- public static function entify_with_options( $tweet, $options = array(), &$replacements = array() ) {
41
- $default_opts = array(
42
- 'encoding' => 'UTF-8',
43
- 'target' => '',
44
- );
45
-
46
- $opts = array_merge( $default_opts, $options );
47
-
48
- $encoding = mb_internal_encoding();
49
- mb_internal_encoding( $opts['encoding'] );
50
-
51
- $keys = array();
52
- $is_retweet = false;
53
-
54
- if ( isset( $tweet['retweeted_status'] ) ) {
55
- $tweet = $tweet['retweeted_status'];
56
- $is_retweet = true;
57
- }
58
-
59
- if ( ! isset( $tweet['entities'] ) ) {
60
- return $tweet['text'];
61
- }
62
-
63
- $target = ( ! empty( $opts['target'] ) ) ? ' target="' . $opts['target'] . '"' : '';
64
-
65
- // prepare the entities
66
- foreach ( $tweet['entities'] as $type => $things ) {
67
- foreach ( $things as $entity => $value ) {
68
- $tweet_link = "<a href=\"https://twitter.com/{$tweet['user']['screen_name']}/statuses/{$tweet['id']}\"{$target}>{$tweet['created_at']}</a>";
69
-
70
- switch ( $type ) {
71
- case 'hashtags':
72
- $href = "<a href=\"https://twitter.com/search?q=%23{$value['text']}\"{$target}>#{$value['text']}</a>";
73
- break;
74
- case 'user_mentions':
75
- $href = "@<a href=\"https://twitter.com/{$value['screen_name']}\" title=\"{$value['name']}\"{$target}>{$value['screen_name']}</a>";
76
- break;
77
- case 'urls':
78
- case 'media':
79
- $url = empty( $value['expanded_url'] ) ? $value['url'] : $value['expanded_url'];
80
- $display = isset( $value['display_url'] ) ? $value['display_url'] : str_replace( 'http://', '', $url );
81
- // Not all pages are served in UTF-8 so you may need to do this ...
82
- $display = urldecode( str_replace( '%E2%80%A6', '&hellip;', urlencode( $display ) ) );
83
- $href = "<a href=\"{$value['url']}\"{$target}>{$display}</a>";
84
- break;
85
- }
86
- $keys[ $value['indices']['0'] ] = mb_substr(
87
- $tweet['text'],
88
- $value['indices']['0'],
89
- $value['indices']['1'] - $value['indices']['0']
90
- );
91
- $replacements[ $value['indices']['0'] ] = $href;
92
- }
93
- }
94
-
95
- ksort( $replacements );
96
- $replacements = array_reverse( $replacements, true );
97
- $entified_tweet = $tweet['text'];
98
- foreach ( $replacements as $k => $v ) {
99
- $entified_tweet = mb_substr( $entified_tweet, 0, $k ) . $v . mb_substr( $entified_tweet, $k + strlen( $keys[ $k ] ) );
100
- }
101
- $replacements = array(
102
- 'replacements' => $replacements,
103
- 'keys' => $keys
104
- );
105
-
106
- mb_internal_encoding( $encoding );
107
-
108
- return $entified_tweet;
109
- }
110
-
111
- /**
112
- * Returns the current URL. This is instead of PHP_SELF which is unsafe
113
- *
114
- * @param bool $dropqs whether to drop the querystring or not. Default true
115
- *
116
- * @return string the current URL
117
- */
118
- public static function php_self( $dropqs = true ) {
119
- $protocol = 'http';
120
- if ( isset( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) == 'on' ) {
121
- $protocol = 'https';
122
- } elseif ( isset( $_SERVER['SERVER_PORT'] ) && ( $_SERVER['SERVER_PORT'] == '443' ) ) {
123
- $protocol = 'https';
124
- }
125
-
126
- $url = sprintf( '%s://%s%s',
127
- $protocol,
128
- $_SERVER['SERVER_NAME'],
129
- $_SERVER['REQUEST_URI']
130
- );
131
-
132
- $parts = parse_url( $url );
133
-
134
- $port = $_SERVER['SERVER_PORT'];
135
- $scheme = $parts['scheme'];
136
- $host = $parts['host'];
137
- $path = @$parts['path'];
138
- $qs = @$parts['query'];
139
-
140
- $port or $port = ( $scheme == 'https' ) ? '443' : '80';
141
-
142
- if ( ( $scheme == 'https' && $port != '443' )
143
- || ( $scheme == 'http' && $port != '80' )
144
- ) {
145
- $host = "$host:$port";
146
- }
147
- $url = "$scheme://$host$path";
148
- if ( ! $dropqs ) {
149
- return "{$url}?{$qs}";
150
- } else {
151
- return $url;
152
- }
153
- }
154
-
155
- public static function is_cli() {
156
- return ( PHP_SAPI == 'cli' && empty( $_SERVER['REMOTE_ADDR'] ) );
157
- }
158
-
159
- /**
160
- * Debug function for printing the content of an object
161
- *
162
- * @param mixes $obj
163
- */
164
- public static function pr( $obj ) {
165
-
166
- if ( ! self::is_cli() ) {
167
- echo '<pre style="word-wrap: break-word">';
168
- }
169
- if ( is_object( $obj ) ) {
170
- print_r( $obj );
171
- } elseif ( is_array( $obj ) ) {
172
- print_r( $obj );
173
- } else {
174
- echo $obj;
175
- }
176
- if ( ! self::is_cli() ) {
177
- echo '</pre>';
178
- }
179
- }
180
-
181
- /**
182
- * Make an HTTP request using this library. This method is different to 'request'
183
- * because on a 401 error it will retry the request.
184
- *
185
- * When a 401 error is returned it is possible the timestamp of the client is
186
- * too different to that of the API server. In this situation it is recommended
187
- * the request is retried with the OAuth timestamp set to the same as the API
188
- * server. This method will automatically try that technique.
189
- *
190
- * This method doesn't return anything. Instead the response should be
191
- * inspected directly.
192
- *
193
- * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
194
- * @param string $url the request URL without query string parameters
195
- * @param array $params the request parameters as an array of key=value pairs
196
- * @param string $useauth whether to use authentication when making the request. Default true.
197
- * @param string $multipart whether this request contains multipart data. Default false
198
- */
199
- public static function auto_fix_time_request( $tmhOAuth, $method, $url, $params = array(), $useauth = true, $multipart = false ) {
200
- $tmhOAuth->request( $method, $url, $params, $useauth, $multipart );
201
-
202
- // if we're not doing auth the timestamp isn't important
203
- if ( ! $useauth ) {
204
- return;
205
- }
206
-
207
- // some error that isn't a 401
208
- if ( $tmhOAuth->response['code'] != 401 ) {
209
- return;
210
- }
211
-
212
- // some error that is a 401 but isn't because the OAuth token and signature are incorrect
213
- // TODO: this check is horrid but helps avoid requesting twice when the username and password are wrong
214
- if ( stripos( $tmhOAuth->response['response'], 'password' ) !== false ) {
215
- return;
216
- }
217
-
218
- // force the timestamp to be the same as the Twitter servers, and re-request
219
- $tmhOAuth->auto_fixed_time = true;
220
- $tmhOAuth->config['force_timestamp'] = true;
221
- $tmhOAuth->config['timestamp'] = strtotime( $tmhOAuth->response['headers']['date'] );
222
-
223
- return $tmhOAuth->request( $method, $url, $params, $useauth, $multipart );
224
- }
225
-
226
- /**
227
- * Asks the user for input and returns the line they enter
228
- *
229
- * @param string $prompt the text to display to the user
230
- *
231
- * @return the text entered by the user
232
- */
233
- public static function read_input( $prompt ) {
234
- echo $prompt;
235
- $handle = fopen( "php://stdin", "r" );
236
- $data = fgets( $handle );
237
-
238
- return trim( $data );
239
- }
240
-
241
- /**
242
- * Get a password from the shell.
243
- *
244
- * This function works on *nix systems only and requires shell_exec and stty.
245
- *
246
- * @param boolean $stars Wether or not to output stars for given characters
247
- *
248
- * @return string
249
- * @url http://www.dasprids.de/blog/2008/08/22/getting-a-password-hidden-from-stdin-with-php-cli
250
- */
251
- public static function read_password( $prompt, $stars = false ) {
252
- echo $prompt;
253
- $style = shell_exec( 'stty -g' );
254
-
255
- if ( $stars === false ) {
256
- shell_exec( 'stty -echo' );
257
- $password = rtrim( fgets( STDIN ), "\n" );
258
- } else {
259
- shell_exec( 'stty -icanon -echo min 1 time 0' );
260
- $password = '';
261
- while ( true ) :
262
- $char = fgetc( STDIN );
263
- if ( $char === "\n" ) :
264
- break;
265
- elseif ( ord( $char ) === 127 ) :
266
- if ( strlen( $password ) > 0 ) {
267
- fwrite( STDOUT, "\x08 \x08" );
268
- $password = substr( $password, 0, - 1 );
269
- } else {
270
- fwrite( STDOUT, "*" );
271
- }
272
- $password .= $char;
273
- endif;
274
- endwhile;
275
- }
276
-
277
- // Reset
278
- shell_exec( 'stty ' . $style );
279
- echo PHP_EOL;
280
-
281
- return $password;
282
- }
283
-
284
- /**
285
- * Check if one string ends with another
286
- *
287
- * @param string $haystack the string to check inside of
288
- * @param string $needle the string to check $haystack ends with
289
- *
290
- * @return true if $haystack ends with $needle, false otherwise
291
- */
292
- public static function endswith( $haystack, $needle ) {
293
- $haylen = strlen( $haystack );
294
- $needlelen = strlen( $needle );
295
- if ( $needlelen > $haylen ) {
296
- return false;
297
- }
298
-
299
- return substr_compare( $haystack, $needle, - $needlelen ) === 0;
300
- }
301
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
uninstall.php CHANGED
@@ -1,5 +1,15 @@
1
  <?php
2
- if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
 
 
 
 
 
 
 
 
 
 
3
  exit();
4
  } else {
5
  delete_option( 'wpt_post_types' );
@@ -10,10 +20,10 @@ if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
  delete_option( 'comment-published-text' );
11
  delete_option( 'wpt_status_message_last' );
12
  delete_option( 'wtt_twitter_username' );
13
- // Su.pr API
14
  delete_option( 'suprapi' );
15
 
16
- // Error checking
17
  delete_option( 'jd-functions-checked' );
18
  delete_option( 'wp_twitter_failure' );
19
  delete_option( 'wp_supr_failure' );
@@ -21,24 +31,24 @@ if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
21
  delete_option( 'wp_bitly_failure' );
22
  delete_option( 'wpt_curl_error' );
23
 
24
- // Rate Limiting
25
  delete_option( 'wpt_rate_limits' );
26
  delete_option( 'wpt_default_rate_limit' );
27
  delete_option( 'wpt_rate_limit' );
28
  delete_option( 'wpt_rate_limiting' );
29
-
30
- // Blogroll options
31
  delete_option( 'jd-use-link-title' );
32
  delete_option( 'jd-use-link-description' );
33
  delete_option( 'newlink-published-text' );
34
  delete_option( 'jd_twit_blogroll' );
35
 
36
- // Default publishing options.
37
  delete_option( 'jd_tweet_default' );
38
  delete_option( 'jd_tweet_default_edit' );
39
  delete_option( 'wpt_inline_edits' );
40
 
41
- // Note that default options are set.
42
  delete_option( 'twitterInitialised' );
43
  delete_option( 'wpt_twitter_setup' );
44
  delete_option( 'wp_twitter_failure' );
@@ -51,7 +61,7 @@ if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
51
  delete_option( 'jd-use-none' );
52
  delete_option( 'jd-use-wp' );
53
 
54
- // Special Options
55
  delete_option( 'jd_twit_prepend' );
56
  delete_option( 'jd_twit_append' );
57
  delete_option( 'jd_twit_remote' );
@@ -65,25 +75,25 @@ if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
65
  delete_option( 'use_tags_as_hashtags' );
66
  delete_option( 'jd_max_tags' );
67
  delete_option( 'jd_max_characters' );
68
- // Bitly Settings
69
  delete_option( 'bitlylogin' );
70
  delete_option( 'jd-use-bitly' );
71
  delete_option( 'bitlyapi' );
72
 
73
- // twitter compatible api
74
  delete_option( 'jd_api_post_status' );
75
  delete_option( 'app_consumer_key' );
76
  delete_option( 'app_consumer_secret' );
77
  delete_option( 'oauth_token' );
78
  delete_option( 'oauth_token_secret' );
79
 
80
- //dymamic analytics
81
  delete_option( 'jd_dynamic_analytics' );
82
  delete_option( 'use_dynamic_analytics' );
83
- //category limits
84
  delete_option( 'limit_categories' );
85
  delete_option( 'tweet_categories' );
86
- //yourls installation
87
  delete_option( 'yourlsapi' );
88
  delete_option( 'yourlspath' );
89
  delete_option( 'yourlsurl' );
@@ -91,8 +101,8 @@ if ( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
91
  delete_option( 'jd_replace_character' );
92
  delete_option( 'jd_date_format' );
93
  delete_option( 'jd_keyword_format' );
94
- //Version
95
  delete_option( 'wp_to_twitter_version' );
96
  delete_option( 'wpt_authentication_missing' );
97
  delete_option( 'wpt_http' );
98
- }
1
  <?php
2
+ /**
3
+ * Uninstall WP to Twitter
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
+ if ( ! defined( 'ABSPATH' ) && ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
13
  exit();
14
  } else {
15
  delete_option( 'wpt_post_types' );
20
  delete_option( 'comment-published-text' );
21
  delete_option( 'wpt_status_message_last' );
22
  delete_option( 'wtt_twitter_username' );
23
+ // Su.pr API.
24
  delete_option( 'suprapi' );
25
 
26
+ // Error checking.
27
  delete_option( 'jd-functions-checked' );
28
  delete_option( 'wp_twitter_failure' );
29
  delete_option( 'wp_supr_failure' );
31
  delete_option( 'wp_bitly_failure' );
32
  delete_option( 'wpt_curl_error' );
33
 
34
+ // Rate Limiting.
35
  delete_option( 'wpt_rate_limits' );
36
  delete_option( 'wpt_default_rate_limit' );
37
  delete_option( 'wpt_rate_limit' );
38
  delete_option( 'wpt_rate_limiting' );
39
+
40
+ // Blogroll options.
41
  delete_option( 'jd-use-link-title' );
42
  delete_option( 'jd-use-link-description' );
43
  delete_option( 'newlink-published-text' );
44
  delete_option( 'jd_twit_blogroll' );
45
 
46
+ // Default publishing options.
47
  delete_option( 'jd_tweet_default' );
48
  delete_option( 'jd_tweet_default_edit' );
49
  delete_option( 'wpt_inline_edits' );
50
 
51
+ // Note that default options are set.
52
  delete_option( 'twitterInitialised' );
53
  delete_option( 'wpt_twitter_setup' );
54
  delete_option( 'wp_twitter_failure' );
61
  delete_option( 'jd-use-none' );
62
  delete_option( 'jd-use-wp' );
63
 
64
+ // Special Options.
65
  delete_option( 'jd_twit_prepend' );
66
  delete_option( 'jd_twit_append' );
67
  delete_option( 'jd_twit_remote' );
75
  delete_option( 'use_tags_as_hashtags' );
76
  delete_option( 'jd_max_tags' );
77
  delete_option( 'jd_max_characters' );
78
+ // Bitly Settings.
79
  delete_option( 'bitlylogin' );
80
  delete_option( 'jd-use-bitly' );
81
  delete_option( 'bitlyapi' );
82
 
83
+ // twitter compatible api.
84
  delete_option( 'jd_api_post_status' );
85
  delete_option( 'app_consumer_key' );
86
  delete_option( 'app_consumer_secret' );
87
  delete_option( 'oauth_token' );
88
  delete_option( 'oauth_token_secret' );
89
 
90
+ // dymamic analytics.
91
  delete_option( 'jd_dynamic_analytics' );
92
  delete_option( 'use_dynamic_analytics' );
93
+ // category limits.
94
  delete_option( 'limit_categories' );
95
  delete_option( 'tweet_categories' );
96
+ // yourls installation.
97
  delete_option( 'yourlsapi' );
98
  delete_option( 'yourlspath' );
99
  delete_option( 'yourlsurl' );
101
  delete_option( 'jd_replace_character' );
102
  delete_option( 'jd_date_format' );
103
  delete_option( 'jd_keyword_format' );
104
+ // Version.
105
  delete_option( 'wp_to_twitter_version' );
106
  delete_option( 'wpt_authentication_missing' );
107
  delete_option( 'wpt_http' );
108
+ }
wp-to-twitter-manager.php CHANGED
@@ -1,18 +1,31 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
5
-
 
 
 
6
  function wpt_updated_settings() {
7
  wpt_check_version();
8
-
9
  if ( empty( $_POST ) ) {
10
  return;
11
  }
12
-
13
  $nonce = $_REQUEST['_wpnonce'];
14
  if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
15
- die( "Security check failed" );
16
  }
17
 
18
  if ( isset( $_POST['oauth_settings'] ) ) {
@@ -21,11 +34,11 @@ function wpt_updated_settings() {
21
  $oauth_message = '';
22
  }
23
 
24
- $message = "";
25
 
26
- // notifications from oauth connection
27
  if ( isset( $_POST['oauth_settings'] ) ) {
28
- if ( $oauth_message == "success" ) {
29
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro?tab=basic' );
30
 
31
  print( '
@@ -33,19 +46,19 @@ function wpt_updated_settings() {
33
  <p>' . __( 'WP to Twitter is now connected with Twitter.', 'wp-to-twitter' ) . " <a href='$admin_url'>" . __( 'Configure your Tweet templates', 'wp-to-twitter' ) . '</a></p>
34
  </div>
35
  ' );
36
- } else if ( $oauth_message == "failed" ) {
37
  print( '
38
  <div id="message" class="error fade">
39
  <p>' . __( 'WP to Twitter failed to connect with Twitter.', 'wp-to-twitter' ) . ' <strong>' . __( 'Error:', 'wp-to-twitter' ) . '</strong> ' . get_option( 'wpt_error' ) . '</p>
40
  </div>
41
  ' );
42
- } else if ( $oauth_message == "cleared" ) {
43
  print( '
44
  <div id="message" class="updated fade">
45
  <p>' . __( 'OAuth Authentication Data Cleared.', 'wp-to-twitter' ) . '</p>
46
  </div>
47
  ' );
48
- } else if ( $oauth_message == 'nosync' ) {
49
  print( '
50
  <div id="message" class="error fade">
51
  <p>' . __( 'OAuth Authentication Failed. Your server time is not in sync with the Twitter servers. Talk to your hosting service to see what can be done.', 'wp-to-twitter' ) . '</p>
@@ -55,23 +68,23 @@ function wpt_updated_settings() {
55
  print( '
56
  <div id="message" class="error fade">
57
  <p>' . __( 'OAuth Authentication response not understood.', 'wp-to-twitter' ) . '</p>
58
- </div>
59
  ' );
60
  }
61
  }
62
 
63
- if ( isset( $_POST['submit-type'] ) && $_POST['submit-type'] == 'advanced' ) {
64
  update_option( 'jd_tweet_default', ( isset( $_POST['jd_tweet_default'] ) ) ? $_POST['jd_tweet_default'] : 0 );
65
  update_option( 'jd_tweet_default_edit', ( isset( $_POST['jd_tweet_default_edit'] ) ) ? $_POST['jd_tweet_default_edit'] : 0 );
66
-
67
- if ( isset( $_POST['wpt_rate_limiting'] ) && get_option( 'wpt_rate_limiting' ) != 1 ) {
68
  $extend = __( 'Rate Limiting is enabled. Default rate limits are set at 10 posts per category/term per hour. <a href="#special_cases">Edit global default</a> or edit individual terms to customize limits for each category or taxonomy term.', 'wp-to-twitter' );
69
- wp_schedule_event( current_time( 'timestamp' )+3600, 'hourly', 'wptratelimits' );
70
  } else {
71
  $extend = '';
72
  wp_clear_scheduled_hook( 'wptratelimits' );
73
- }
74
-
75
  update_option( 'wpt_rate_limiting', ( isset( $_POST['wpt_rate_limiting'] ) ) ? 1 : 0 );
76
  update_option( 'wpt_inline_edits', ( isset( $_POST['wpt_inline_edits'] ) ) ? $_POST['wpt_inline_edits'] : 0 );
77
  update_option( 'jd_twit_remote', ( isset( $_POST['jd_twit_remote'] ) ) ? $_POST['jd_twit_remote'] : 0 );
@@ -82,20 +95,20 @@ function wpt_updated_settings() {
82
  update_option( 'jd_twit_append', $_POST['jd_twit_append'] );
83
  update_option( 'jd_post_excerpt', $_POST['jd_post_excerpt'] );
84
  update_option( 'jd_max_tags', $_POST['jd_max_tags'] );
85
- $use_cats = ( isset( $_POST['wpt_use_cats'] ) ) ? $_POST['wpt_use_cats'] : 0;
86
  update_option( 'wpt_use_cats', $use_cats );
87
- update_option( 'wpt_tag_source', ( ( isset( $_POST['wpt_tag_source'] ) && $_POST['wpt_tag_source'] == 'slug' ) ? 'slug' : '' ) );
88
  update_option( 'jd_max_characters', $_POST['jd_max_characters'] );
89
  update_option( 'jd_replace_character', $_POST['jd_replace_character'] );
90
  update_option( 'jd_date_format', $_POST['jd_date_format'] );
91
  update_option( 'jd_dynamic_analytics', $_POST['jd-dynamic-analytics'] );
92
 
93
  $twitter_analytics = ( isset( $_POST['twitter-analytics'] ) ) ? $_POST['twitter-analytics'] : 0;
94
- if ( $twitter_analytics == 1 ) {
95
  update_option( 'use_dynamic_analytics', 0 );
96
  update_option( 'use-twitter-analytics', 1 );
97
  update_option( 'no-analytics', 0 );
98
- } else if ( $twitter_analytics == 2 ) {
99
  update_option( 'use_dynamic_analytics', 1 );
100
  update_option( 'use-twitter-analytics', 0 );
101
  update_option( 'no-analytics', 0 );
@@ -108,16 +121,9 @@ function wpt_updated_settings() {
108
  update_option( 'twitter-analytics-campaign', $_POST['twitter-analytics-campaign'] );
109
  update_option( 'jd_individual_twitter_users', ( isset( $_POST['jd_individual_twitter_users'] ) ? $_POST['jd_individual_twitter_users'] : 0 ) );
110
 
111
-
112
  if ( isset( $_POST['wpt_caps'] ) ) {
113
  $perms = $_POST['wpt_caps'];
114
- $caps = array(
115
- 'wpt_twitter_oauth',
116
- 'wpt_twitter_custom',
117
- 'wpt_twitter_switch',
118
- 'wpt_can_tweet',
119
- 'wpt_tweet_now'
120
- );
121
  foreach ( $perms as $key => $value ) {
122
  $role = get_role( $key );
123
  if ( is_object( $role ) ) {
@@ -140,44 +146,44 @@ function wpt_updated_settings() {
140
  $message .= __( 'WP to Twitter Advanced Options Updated', 'wp-to-twitter' ) . '. ' . $extend;
141
  }
142
 
143
- if ( isset( $_POST['submit-type'] ) && $_POST['submit-type'] == 'options' ) {
144
- // UPDATE OPTIONS
145
  $wpt_settings = get_option( 'wpt_post_types' );
146
- if ( !is_array( $wpt_settings ) ) {
147
  $wpt_settings = array();
148
  }
149
 
150
  $keys = array();
151
  $values = array();
152
  foreach ( $_POST['wpt_post_types'] as $key => $value ) {
153
- // using wp_encode_emoji allows me to save emoji in templates
154
- // ...but I haven't found a way to convert the saved emoji *back* to unicode
155
  // sending the HTML entity just yields a broken character on Twitter.
156
  $array = array(
157
- 'post-published-update' => ( isset( $value["post-published-update"] ) ) ? $value["post-published-update"] : "",
158
- 'post-published-text' => $value["post-published-text"],
159
- 'post-edited-update' => ( isset( $value["post-edited-update"] ) ) ? $value["post-edited-update"] : "",
160
- 'post-edited-text' => $value["post-edited-text"]
161
  );
162
- array_push( $keys, $key );
163
  array_push( $values, $array );
164
  }
165
-
166
  $wpt_settings = array_combine( $keys, $values );
167
  update_option( 'wpt_post_types', $wpt_settings );
168
  update_option( 'newlink-published-text', $_POST['newlink-published-text'] );
169
- update_option( 'jd_twit_blogroll', ( isset( $_POST['jd_twit_blogroll'] ) ) ? $_POST['jd_twit_blogroll'] : "" );
170
  $message = wpt_select_shortener( $_POST );
171
  $message .= __( 'WP to Twitter Options Updated', 'wp-to-twitter' );
172
  $message = apply_filters( 'wpt_settings', $message, $_POST );
173
  }
174
 
175
- if ( isset( $_POST['wpt_shortener_update'] ) && $_POST['wpt_shortener_update'] == 'true' ) {
176
  $message = wpt_shortener_update( $_POST );
177
  }
178
 
179
  // Check whether the server has supported for needed functions.
180
- if ( isset( $_POST['submit-type'] ) && $_POST['submit-type'] == 'check-support' ) {
181
  $message = wpt_check_functions();
182
  }
183
 
@@ -186,44 +192,47 @@ function wpt_updated_settings() {
186
  }
187
  }
188
 
 
 
 
189
  function wpt_update_settings() {
190
  ?>
191
  <div class="wrap" id="wp-to-twitter">
192
- <?php
193
- if ( defined( 'WPT_STAGING_MODE' ) && WPT_STAGING_MODE == true ) {
194
- echo "<div class='updated notice'><p>" . __( 'WP to Twitter is in staging mode. Tweets will be reported as if successfully sent to Twitter but will not be sent.', 'wp-to-twitter' ) . "</p></div>";
195
- }
196
- wpt_updated_settings();
197
- wpt_show_last_tweet();
198
- wpt_handle_errors();
199
  ?>
200
- <?php $elem = ( version_compare( '4.3', get_option( 'version' ), '>=' ) ) ? 'h1' : 'h2'; ?>
201
- <<?php echo $elem; ?>><?php _e( "WP to Twitter Options", 'wp-to-twitter' ); ?></<?php echo $elem; ?>>
202
-
203
  <?php wpt_max_length(); ?>
204
-
205
  <div class='nav-tab-wrapper'>
206
  <?php wpt_settings_tabs(); ?>
207
  </div>
208
  <div id="wpt_settings_page" class="postbox-container jcd-wide">
209
  <div class="metabox-holder">
210
 
211
- <?php
212
- $default = ( get_option( 'wtt_twitter_username' ) == '' ) ? 'connection' : 'basic';
213
  $current = ( isset( $_GET['tab'] ) ) ? $_GET['tab'] : $default;
214
- if ( $current == 'connection' ) {
215
  if ( function_exists( 'wtt_connect_oauth' ) ) {
216
  wtt_connect_oauth();
217
  }
218
  }
219
- if ( $current == 'pro' ) {
220
  if ( function_exists( 'wpt_pro_functions' ) ) {
221
  wpt_pro_functions();
222
  if ( function_exists( 'wpt_notes' ) ) {
223
  wpt_notes();
224
  }
225
  } else {
226
- if ( ! function_exists( 'wpt_pro_exists' ) ) { ?>
 
227
  <div class="ui-sortable meta-box-sortables">
228
  <div class="postbox">
229
  <h3 class='wpt-upgrade'><span><strong><?php _e( 'Upgrade Now!', 'wp-to-twitter' ); ?></strong></span></h3>
@@ -231,41 +240,49 @@ function wpt_update_settings() {
231
  <div class="inside purchase">
232
  <h4><strong><?php _e( 'What can WP Tweets PRO do for you?', 'wp-to-twitter' ); ?></strong></h4>
233
  <p>
234
- <?php
235
- _e( 'WP Tweets PRO takes the great Tweeting abilities from WP to Twitter and puts them in high gear.', 'wp-to-twitter' );
236
- ?>
237
  </p>
238
  <ul>
239
- <li><?php _e( 'Publish to unique Twitter accounts for each site author.','wp-to-twitter' ); ?></li>
240
  <li><?php _e( 'Schedule up to 3 re-posts of Tweets at an interval of your choice.', 'wp-to-twitter' ); ?></li>
241
  <li><?php _e( 'With a delay between publishing and Tweeting, verify your tweets before you share online.', 'wp-to-twitter' ); ?></li>
242
  <li><?php _e( 'Automatically your great old posts every few hours, days, or weeks!', 'wp-to-twitter' ); ?></li>
243
  <li><?php _e( 'Upload your featured images to Twitter with each Tweet', 'wp-to-twitter' ); ?></li>
244
- <li><?php printf( __( 'Take a look at the <a href="%s">complete feature list</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' ); ?></li>
 
 
 
 
 
245
  </ul>
246
  <p>
247
- <strong><?php _e( "Use WP Tweets PRO to keep traffic coming for every post.", 'wp-to-twitter' ); ?></strong>
248
  </p>
249
  <p class='wpt-button'>
250
  <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Upgrade to <strong>WP Tweets PRO</strong>!', 'wp-to-twitter' ); ?></a></strong>
251
- </p>
252
-
253
  <h4><?php _e( 'What else does WP Tweets PRO do?', 'wp-to-twitter' ); ?></h4>
254
-
255
  <p>
256
  <?php _e( 'WP Tweets PRO is packed with features to help you increase engagement with your Twitter followers. Upload images, use Twitter Cards, and automated re-posting of your Tweets are just a few of the features available in the premium add-on to WP to Twitter.', 'wp-to-twitter' ); ?>
257
  </p>
258
  <p>
259
- <?php printf( __( 'Is there something that WP Tweets PRO <em>doesn\'t already do for you</em>? No problem! Take a look at the extensive <a href="%s">library of plug-in extensions</a> - you can try out or modify any of these code samples to extend and customize WP Tweets PRO.', 'wp-to-twitter' ), 'https://github.com/joedolson/plugin-extensions/tree/master/wp-to-twitter' ); ?>
 
 
 
260
  </p>
261
  <p>
262
- <?php printf( __( '<a href="%s">Learn more about WP Tweets PRO</a>!', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro?campaign=get-wpt' ); ?>
 
 
 
263
  </p>
264
-
265
  <p class='wpt-button'>
266
  <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Buy WP Tweets PRO today!', 'wp-to-twitter' ); ?></a></strong>
267
  </p>
268
-
269
  </div>
270
  </div>
271
  </div>
@@ -273,7 +290,7 @@ function wpt_update_settings() {
273
  }
274
  }
275
  }
276
- if ( $current == 'basic' ) {
277
  ?>
278
  <div class="ui-sortable meta-box-sortables">
279
  <div class="postbox">
@@ -281,109 +298,101 @@ function wpt_update_settings() {
281
 
282
  <div class="inside wpt-settings">
283
  <form method="post" action="">
284
- <?php $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
285
- echo "<div>$nonce</div>"; ?>
 
 
286
  <div>
287
- <?php echo apply_filters( 'wpt_tweet_length', '' ); ?>
288
- <?php echo apply_filters( 'wpt_pick_shortener', '' ); ?>
289
  <?php
 
 
290
  $post_types = get_post_types( array( 'public' => true ), 'objects' );
291
  $wpt_settings = get_option( 'wpt_post_types' );
292
  $tabs = "<ul class='tabs' role='tablist'>";
293
  foreach ( $post_types as $type ) {
294
- $name = $type->labels->name;
295
- $slug = $type->name;
296
- if ( $slug == 'attachment' || $slug == 'nav_menu_item' || $slug == 'revision' ) {
297
  } else {
298
  $tabs .= "<li><a href='#wpt_$slug' role='tab' id='tab_wpt_$slug' aria-controls='wpt_$slug'>$name</a></li>";
299
  }
300
  }
301
- $tabs .= "<li><a href='#wpt_links' id='tab_wpt_links' aria-controls='wpt_links'>" . __( 'Links', 'wp-to-twitter' ) . "</a></li>
302
- </ul>";
303
  echo $tabs;
304
  foreach ( $post_types as $type ) {
305
- $name = $type->labels->name;
306
- $singular = $type->labels->singular_name;
307
- $slug = $type->name;
308
- if ( $slug == 'attachment' || $slug == 'nav_menu_item' || $slug == 'revision' ) {
309
  continue;
310
  } else {
311
- $vowels = array( 'a', 'e', 'i', 'o', 'u' );
312
- foreach ( $vowels as $vowel ) {
313
- if ( strpos( $name, $vowel ) === 0 ) {
314
- $word = 'an';
315
- break;
316
- } else {
317
- $word = 'a';
318
- }
319
- }
320
  ?>
321
-
322
  <div class='wptab wpt_types wpt_<?php echo $slug; ?>' aria-labelledby='tab_wpt_<?php echo $slug; ?>' role="tabpanel" id='wpt_<?php echo $slug; ?>'>
323
- <?php
324
- // share information about any usage of pre 2.8 category filters
325
- if ( get_option( 'limit_categories' ) != '0' && $slug == 'post' ) {
326
- $falseness = get_option( 'jd_twit_cats' );
327
- $categories = get_option( 'tweet_categories' );
328
- if ( $falseness == 1 ) {
329
- echo "<p>" . __( 'These categories are currently <strong>excluded</strong> by the deprecated WP to Twitter category filters.', 'wp-to-twitter' ) . "</p>";
330
- } else {
331
- echo "<p>" . __( 'These categories are currently <strong>allowed</strong> by the deprecated WP to Twitter category filters.', 'wp-to-twitter' ) . "</p>";
332
- }
333
- echo "<ul>";
334
- if ( is_array( $categories ) ) {
335
- foreach ( $categories as $cat ) {
336
- $category = get_the_category_by_ID( $cat );
337
- echo "<li>$category</li>";
338
- }
339
- }
340
- echo "</ul>";
341
- if ( ! function_exists( 'wpt_pro_exists' ) ) {
342
- printf( __( '<a href="%s">Upgrade to WP Tweets PRO</a> to filter posts in all custom post types on any taxonomy.', 'wp-to-twitter' ), "http://www.wptweetspro.com/wp-tweets-pro" );
343
- } else {
344
- _e( 'Updating the WP Tweets PRO taxonomy filters will overwrite your old category filters.', 'wp-to-twitter' );
345
  }
346
  }
347
- ?>
348
- <fieldset>
349
- <legend><?php _e( 'Tweet Templates', 'wp-to-twitter' ); ?></legend>
350
- <p>
351
- <input type="checkbox"
352
- name="wpt_post_types[<?php echo $slug; ?>][post-published-update]"
353
- id="<?php echo $slug; ?>-post-published-update"
354
- value="1" <?php echo jd_checkCheckbox( 'wpt_post_types', $slug, 'post-published-update' ) ?> />
355
- <label
356
- for="<?php echo $slug; ?>-post-published-update"><strong><?php printf( __( 'Update when %1$s %2$s is published', 'wp-to-twitter' ), $word, $singular ); ?></strong></label>
357
- <label
358
- for="<?php echo $slug; ?>-post-published-text"><br/><?php printf( __( 'Template for new %1$s updates', 'wp-to-twitter' ), $name ); ?>
359
- </label><br/><textarea class="wpt-template"
360
- name="wpt_post_types[<?php echo $slug; ?>][post-published-text]"
361
- id="<?php echo $slug; ?>-post-published-text"
362
- cols="60"
363
- rows="3"><?php if ( isset( $wpt_settings[ $slug ] ) ) {
364
- echo esc_attr( stripslashes( $wpt_settings[ $slug ]['post-published-text'] ) );
365
- } ?></textarea>
366
- </p>
367
-
368
- <p>
369
- <input type="checkbox"
370
- name="wpt_post_types[<?php echo $slug; ?>][post-edited-update]"
371
- id="<?php echo $slug; ?>-post-edited-update"
372
- value="1" <?php echo jd_checkCheckbox( 'wpt_post_types', $slug, 'post-edited-update' ) ?> />
373
- <label
374
- for="<?php echo $slug; ?>-post-edited-update"><strong><?php printf( __( 'Update when %1$s %2$s is edited', 'wp-to-twitter' ), $word, $singular ); ?></strong></label><br/><label
375
- for="<?php echo $slug; ?>-post-edited-text"><?php printf( __( 'Template for %1$s editing updates', 'wp-to-twitter' ), $name ); ?></label><br/><textarea
376
- class="wpt-template"
377
- name="wpt_post_types[<?php echo $slug; ?>][post-edited-text]"
378
- id="<?php echo $slug; ?>-post-edited-text" cols="60"
379
- rows="3"><?php if ( isset( $wpt_settings[ $slug ] ) ) {
380
- echo esc_attr( stripslashes( $wpt_settings[ $slug ]['post-edited-text'] ) );
381
- } ?></textarea>
382
- </p>
383
- </fieldset>
384
- <?php if ( function_exists( 'wpt_list_terms' ) ) {
385
- wpt_list_terms( $slug, $name );
386
- } ?>
 
 
 
 
 
 
 
 
 
387
  </div>
388
  <?php
389
  }
@@ -393,281 +402,255 @@ function wpt_update_settings() {
393
  <fieldset>
394
  <legend><span><?php _e( 'Links', 'wp-to-twitter' ); ?></span></legend>
395
  <p>
396
- <input type="checkbox" name="jd_twit_blogroll" id="jd_twit_blogroll"
397
- value="1" <?php echo jd_checkCheckbox( 'jd_twit_blogroll' ) ?> />
398
- <label
399
- for="jd_twit_blogroll"><strong><?php _e( "Update Twitter when you post a Blogroll link", 'wp-to-twitter' ); ?></strong></label><br/>
400
- <label
401
- for="newlink-published-text"><?php _e( "Text for new link updates:", 'wp-to-twitter' ); ?></label>
402
- <input aria-describedby="newlink-published-text-label" type="text"
403
- class="wpt-template" name="newlink-published-text"
404
- id="newlink-published-text" size="60" maxlength="120"
405
- value="<?php esc_attr_e( stripslashes( get_option( 'newlink-published-text' ) ) ); ?>"/><br/><span
406
- id="newlink-published-text-label"><?php _e( 'Available shortcodes: <code>#url#</code>, <code>#title#</code>, and <code>#description#</code>.', 'wp-to-twitter' ); ?></span>
407
  </p>
408
  </fieldset>
409
  </div>
410
  <div>
411
  <input type="hidden" name="submit-type" value="options" />
412
  </div>
413
- <input type="submit" name="submit" value="<?php _e( "Save WP to Twitter Options", 'wp-to-twitter' ); ?>" class="button-primary"/>
414
  </div>
415
  </form>
416
  </div>
417
  </div>
418
  </div>
419
-
420
  <div class="ui-sortable meta-box-sortables">
421
  <div class="postbox">
422
  <h3><span><?php _e( 'Tweet Template Tags', 'wp-to-twitter' ); ?></span></h3>
423
-
424
  <div class="inside">
425
  <ul>
426
- <li><?php _e( "<code>#title#</code>: the title of your blog post", 'wp-to-twitter' ); ?></li>
427
- <li><?php _e( "<code>#blog#</code>: the title of your blog", 'wp-to-twitter' ); ?></li>
428
- <li><?php _e( "<code>#post#</code>: a short excerpt of the post content", 'wp-to-twitter' ); ?></li>
429
- <li><?php _e( "<code>#category#</code>: the first selected category for the post", 'wp-to-twitter' ); ?></li>
430
- <li><?php _e( "<code>#cat_desc#</code>: custom value from the category description field", 'wp-to-twitter' ); ?></li>
431
- <li><?php _e( "<code>#date#</code>: the post date", 'wp-to-twitter' ); ?></li>
432
- <li><?php _e( "<code>#modified#</code>: the post modified date", 'wp-to-twitter' ); ?></li>
433
- <li><?php _e( "<code>#url#</code>: the post URL", 'wp-to-twitter' ); ?></li>
434
- <li><?php _e( "<code>#longurl#</code>: the unshortened post URL", 'wp-to-twitter' ); ?></li>
435
- <li><?php _e( "<code>#author#</code>: the post author (@reference if available, otherwise display name)", 'wp-to-twitter' ); ?></li>
436
- <li><?php _e( "<code>#displayname#</code>: post author's display name", 'wp-to-twitter' ); ?></li>
437
- <li><?php _e( "<code>#account#</code>: the twitter @reference for the account (or the author, if author settings are enabled and set.)", 'wp-to-twitter' ); ?></li>
438
- <li><?php _e( "<code>#@#</code>: the twitter @reference for the author or blank, if not set", 'wp-to-twitter' ); ?></li>
439
- <li><?php _e( "<code>#tags#</code>: your tags modified into hashtags. See options in the Advanced Settings section, below.", 'wp-to-twitter' ); ?></li>
440
- <?php if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) { ?>
441
- <li><?php _e( "<code>#reference#</code>: Used only in co-tweeting. @reference to main account when posted to author account, @reference to author account in post to main account.", 'wp-to-twitter' ); ?></li>
442
- <?php } ?>
 
 
 
 
443
  </ul>
444
  <p>
445
- <?php
446
- _e( "Create custom shortcodes and access WordPress custom fields by using square brackets and the name of your custom field.", 'wp-to-twitter' );
447
- ?>
448
  <br />
449
- <?php
450
- _e( "<strong>Example:</strong> <code>[[custom_field]]</code>", 'wp-to-twitter' );
451
- ?>
452
  </p>
453
  <p>
454
- <?php
455
- _e( "Create custom shortcodes and access the post author's custom user meta fields by using curly brackets and the name of the custom field.", 'wp-to-twitter' );
456
- ?>
457
  <br />
458
- <?php
459
- _e( "<strong>Example:</strong> <code>{{user_meta}}</code>", 'wp-to-twitter' );
460
- ?>
461
- </p>
462
  </div>
463
  </div>
464
- </div>
465
- <?php }
466
- if ( $current == 'shortener' ) {
467
- echo apply_filters( 'wpt_shortener_controls', '' );
 
468
  }
469
-
470
- if ( $current == 'advanced' ) {
471
  ?>
 
472
  <div class="ui-sortable meta-box-sortables">
473
  <div class="postbox">
474
  <h3><span><?php _e( 'Advanced Settings', 'wp-to-twitter' ); ?></span></h3>
475
  <div class="inside">
476
- <form method="post" action="">
477
  <div>
478
- <?php
479
  $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
480
- echo "<div>$nonce</div>";
481
  ?>
482
 
483
  <fieldset>
484
- <legend><?php _e( 'Hashtags', 'wp-to-twitter' ); ?></legend>
485
  <p>
486
- <input type="checkbox" name="jd_strip_nonan" id="jd_strip_nonan"
487
- value="1" <?php echo jd_checkCheckbox( 'jd_strip_nonan' ); ?> /> <label
488
- for="jd_strip_nonan"><?php _e( "Strip nonalphanumeric characters from tags", 'wp-to-twitter' ); ?></label>
489
  </p>
490
-
491
  <p>
492
- <input type="checkbox" name="wpt_tag_source" id="wpt_tag_source"
493
- value="slug" <?php echo jd_checkSelect( 'wpt_tag_source', 'slug', 'checkbox' ); ?> />
494
- <label
495
- for="wpt_tag_source"><?php _e( "Use tag slug as hashtag value", 'wp-to-twitter' ); ?></label><br/>
496
  </p>
497
- <p>
498
  <input type="checkbox" name="wpt_use_cats" id="wpt_use_cats" value="1" <?php checked( get_option( 'wpt_use_cats' ), '1' ); ?> />
499
- <label for="wpt_use_cats"><?php _e( "Use categories instead of tags", 'wp-to-twitter' ); ?></label><br/>
500
  </p>
501
  <p>
502
- <label
503
- for="jd_replace_character"><?php _e( "Spaces in tags replaced with:", 'wp-to-twitter' ); ?></label>
504
- <input type="text" name="jd_replace_character" id="jd_replace_character"
505
- value="<?php esc_attr_e( get_option( 'jd_replace_character' ) ); ?>"
506
- size="3"/>
507
  </p>
508
 
509
  <p>
510
- <label
511
- for="jd_max_tags"><?php _e( "Maximum number of tags to include:", 'wp-to-twitter' ); ?></label>
512
- <input aria-describedby="jd_max_characters_label" type="text" name="jd_max_tags"
513
- id="jd_max_tags" value="<?php esc_attr_e( get_option( 'jd_max_tags' ) ); ?>"
514
- size="3"/>
515
  </p>
516
  <p>
517
- <label
518
- for="jd_max_characters"><?php _e( "Maximum length in characters for included tags:", 'wp-to-twitter' ); ?></label>
519
- <input type="text" name="jd_max_characters" id="jd_max_characters"
520
- value="<?php esc_attr_e( get_option( 'jd_max_characters' ) ); ?>" size="3"/>
521
  </p>
522
  </fieldset>
 
 
 
 
 
 
 
523
  <fieldset>
524
- <legend><?php _e( 'Template Settings', 'wp-to-twitter' ); ?></legend>
525
  <p>
526
- <label
527
- for="jd_post_excerpt"><?php _e( "Post excerpt (#post#) in characters:", 'wp-to-twitter' ); ?></label>
528
- <input type="text" name="jd_post_excerpt" id="jd_post_excerpt" size="3" maxlength="3" value="<?php echo( esc_attr( get_option( 'jd_post_excerpt' ) ) ) ?>"/>
529
  </p>
530
-
531
  <p>
532
- <label
533
- for="jd_date_format"><?php _e( "Date Format (#date#):", 'wp-to-twitter' ); ?></label>
534
- <input type="text" aria-describedby="date_format_label" name="jd_date_format"
535
- id="jd_date_format" size="12" maxlength="12"
536
- value="<?php if ( get_option( 'jd_date_format' ) == '' ) {
537
- echo( esc_attr( stripslashes( get_option( 'date_format' ) ) ) );
538
- } else {
539
- echo( esc_attr( get_option( 'jd_date_format' ) ) );
540
- } ?>"/> <?php if ( get_option( 'jd_date_format' ) != '' ) {
 
 
 
541
  echo date_i18n( get_option( 'jd_date_format' ) );
542
  } else {
543
- echo "<em>" . date_i18n( get_option( 'date_format' ) ) . "</em>";
544
- } ?> (<em
545
- id="date_format_label"><a href='http://codex.wordpress.org/Formatting_Date_and_Time'><?php _e( "Date Formatting", 'wp-to-twitter' ); ?></a></em>)
 
546
  </p>
547
 
548
  <p>
549
- <label for="jd_twit_prepend"><?php _e( "Custom text before Tweets:", 'wp-to-twitter' ); ?></label>
550
- <input type="text" name="jd_twit_prepend" id="jd_twit_prepend" size="20"
551
- value="<?php esc_attr_e( stripslashes( get_option( 'jd_twit_prepend' ) ) ) ?>"/>
552
  </p>
553
  <p>
554
- <label for="jd_twit_append"><?php _e( "Custom text after Tweets:", 'wp-to-twitter' ); ?></label>
555
- <input type="text" name="jd_twit_append" id="jd_twit_append" size="20"
556
- value="<?php esc_attr_e( stripslashes( get_option( 'jd_twit_append' ) ) ) ?>"/>
557
  </p>
558
  <p>
559
- <label for="jd_twit_custom_url"><?php _e( "Custom field for alternate post URL:", 'wp-to-twitter' ); ?></label>
560
- <input type="text" name="jd_twit_custom_url" id="jd_twit_custom_url" size="30" maxlength="120"
561
- value="<?php esc_attr_e( stripslashes( get_option( 'jd_twit_custom_url' ) ) ) ?>"/>
562
  </p>
563
  </fieldset>
 
 
 
 
 
 
 
564
  <fieldset>
565
- <legend id="special_cases"><?php _e( "Special Cases", 'wp-to-twitter' ); ?></legend>
566
  <p>
567
- <input type="checkbox" name="jd_tweet_default" id="jd_tweet_default"
568
- value="1" <?php echo jd_checkCheckbox( 'jd_tweet_default' ) ?> />
569
- <label
570
- for="jd_tweet_default"><?php _e( "Do not post Tweets by default", 'wp-to-twitter' ); ?></label><br/>
571
- <input type="checkbox" name="jd_tweet_default_edit" id="jd_tweet_default_edit"
572
- value="1" <?php echo jd_checkCheckbox( 'jd_tweet_default_edit' ) ?> />
573
- <label
574
- for="jd_tweet_default_edit"><?php _e( "Do not post Tweets by default (editing only)", 'wp-to-twitter' ); ?></label><br/>
575
- <input type="checkbox" name="wpt_inline_edits" id="wpt_inline_edits"
576
- value="1" <?php echo jd_checkCheckbox( 'wpt_inline_edits' ) ?> />
577
- <label
578
- for="wpt_inline_edits"><?php _e( "Allow status updates from Quick Edit", 'wp-to-twitter' ); ?></label><br/>
579
- <input type="checkbox" name="wpt_rate_limiting" id="wpt_rate_limiting"
580
- value="1" <?php echo jd_checkCheckbox( 'wpt_rate_limiting' ) ?> />
581
- <label
582
- for="wpt_rate_limiting"><?php _e( "Enable Rate Limiting", 'wp-to-twitter' ); ?></label><br/>
583
  <?php
584
  if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
585
- ?>
586
- <input type="number" name="wpt_default_rate_limit" min="1" id="wpt_default_rate_limit"
587
- value="<?php echo wpt_default_rate_limit(); ?>" />
588
- <label
589
- for="wpt_default_rate_limit"><?php _e( "Default Rate Limit per category per hour", 'wp-to-twitter' ); ?></label><br/>
590
- <?php
591
  }
592
  ?>
593
  </p>
594
  </fieldset>
 
 
 
 
 
 
 
595
  <fieldset>
596
- <legend><?php _e( "Google Analytics Settings", 'wp-to-twitter' ); ?></legend>
597
 
598
  <p>
599
- <input type="radio" name="twitter-analytics" id="use-twitter-analytics"
600
- value="1" <?php echo jd_checkCheckbox( 'use-twitter-analytics' ) ?> />
601
- <label
602
- for="use-twitter-analytics"><?php _e( "Use a Static Identifier", 'wp-to-twitter' ); ?></label><br/>
603
- <label
604
- for="twitter-analytics-campaign"><?php _e( "Static Campaign identifier", 'wp-to-twitter' ); ?></label>
605
- <input type="text" name="twitter-analytics-campaign" id="twitter-analytics-campaign"
606
- size="40" maxlength="120"
607
- value="<?php esc_attr_e( get_option( 'twitter-analytics-campaign' ) ) ?>"/><br/>
608
  </p>
609
-
610
  <p>
611
- <input type="radio" name="twitter-analytics" id="use-dynamic-analytics"
612
- value="2" <?php echo jd_checkCheckbox( 'use_dynamic_analytics' ) ?> />
613
- <label
614
- for="use-dynamic-analytics"><?php _e( "Use a dynamic identifier", 'wp-to-twitter' ); ?></label><br/>
615
- <label
616
- for="jd-dynamic-analytics"><?php _e( "What dynamic identifier would you like to use?", "wp-to-twitter" ); ?></label>
617
  <select name="jd-dynamic-analytics" id="jd-dynamic-analytics">
618
- <option
619
- value="post_category"<?php echo jd_checkSelect( 'jd_dynamic_analytics', 'post_category' ); ?>><?php _e( "Category", "wp-to-twitter" ); ?></option>
620
- <option
621
- value="post_ID"<?php echo jd_checkSelect( 'jd_dynamic_analytics', 'post_ID' ); ?>><?php _e( "Post ID", "wp-to-twitter" ); ?></option>
622
- <option
623
- value="post_title"<?php echo jd_checkSelect( 'jd_dynamic_analytics', 'post_title' ); ?>><?php _e( "Post Title", "wp-to-twitter" ); ?></option>
624
- <option
625
- value="post_author"<?php echo jd_checkSelect( 'jd_dynamic_analytics', 'post_author' ); ?>><?php _e( "Author", "wp-to-twitter" ); ?></option>
626
  </select><br/>
627
  </p>
628
  <p>
629
- <input type="radio" name="twitter-analytics" id="no-analytics"
630
- value="3" <?php echo jd_checkCheckbox( 'no-analytics' ); ?> /> <label
631
- for="no-analytics"><?php _e( "No Analytics", 'wp-to-twitter' ); ?></label>
632
  </p>
633
  </fieldset>
634
- <fieldset id="indauthors">
635
- <legend><?php _e( 'Author Settings', 'wp-to-twitter' ); ?></legend>
636
- <p>
637
- <input type="checkbox" name="jd_individual_twitter_users" id="jd_individual_twitter_users"
638
- value="1" <?php echo jd_checkCheckbox( 'jd_individual_twitter_users' ) ?> />
639
- <label
640
- for="jd_individual_twitter_users"><?php _e( "Authors have individual Twitter accounts", 'wp-to-twitter' ); ?></label>
641
- </p>
 
 
 
 
642
 
643
- </fieldset>
644
  <div class='wpt-permissions'>
645
  <fieldset>
646
  <legend><?php _e( 'Permissions', 'wp-to-twitter' ); ?></legend>
647
  <?php
648
  global $wp_roles;
649
- $roles = $wp_roles->get_names();
650
- $caps = array(
651
  'wpt_can_tweet' => __( 'Can send Tweets', 'wp-to-twitter' ),
652
  'wpt_twitter_custom' => __( 'See Custom Tweet Field when creating a Post', 'wp-to-twitter' ),
653
  'wpt_twitter_switch' => __( 'Toggle the Tweet/Don\'t Tweet option', 'wp-to-twitter' ),
654
  'wpt_tweet_now' => __( 'Can see Tweet Now button', 'wp-to-twitter' ),
655
- 'wpt_twitter_oauth' => __( 'Allow user to authenticate with Twitter', 'wp-to-twitter' )
656
  );
657
- $role_tabs = $role_container = '';
 
658
  foreach ( $roles as $role => $rolename ) {
659
- if ( $role == 'administrator' ) {
660
  continue;
661
  }
662
- $role_tabs .= "<li><a href='#wpt_" . sanitize_title( $role ) . "'>$rolename</a></li>\n";
663
  $role_container .= "<div class='wptab wpt_$role' id='wpt_" . sanitize_title( $role ) . "' aria-live='assertive'><fieldset id='wpt_$role' class='roles'><legend>$rolename</legend>";
664
  $role_container .= "<input type='hidden' value='none' name='wpt_caps[" . $role . "][none]' />
665
- <ul class='wpt-settings checkboxes'>";
666
  foreach ( $caps as $cap => $name ) {
667
  $role_container .= wpt_cap_checkbox( $role, $cap, $name );
668
  }
669
- $role_container .= "
670
- </ul></fieldset></div>\n";
671
  }
672
  echo "
673
  <ul class='tabs'>
@@ -677,7 +660,14 @@ function wpt_update_settings() {
677
  ?>
678
  </fieldset>
679
  </div>
680
- <?php
 
 
 
 
 
 
 
681
  $inputs = '';
682
  $default_order = array(
683
  'excerpt' => 0,
@@ -690,7 +680,7 @@ function wpt_update_settings() {
690
  'tags' => 7,
691
  'modified' => 8,
692
  '@' => 9,
693
- 'cat_desc' => 10
694
  );
695
  $preferred_order = get_option( 'wpt_truncation_order' );
696
  if ( ! $preferred_order ) {
@@ -702,9 +692,9 @@ function wpt_update_settings() {
702
  }
703
  asort( $default_order );
704
  foreach ( $default_order as $k => $v ) {
705
- if ( $k == 'blogname' ) {
706
- $label = '<code>#blog#</code>';
707
- } else if ( $k == 'excerpt' ) {
708
  $label = '<code>#post#</code>';
709
  } else {
710
  $label = '<code>#' . $k . '#</code>';
@@ -713,58 +703,76 @@ function wpt_update_settings() {
713
  }
714
  ?>
715
  <fieldset>
716
- <legend><?php _e( 'Template tag priority order', 'wp-to-twitter' ); ?></legend>
717
- <p><?php _e( 'The order in which items will be abbreviated or removed from your Tweet if the Tweet is too long to send to Twitter.', 'wp-to-twitter' ); ?> <?php _e( 'Tags with lower values will be modified first.', 'wp-to-twitter' ); ?></p>
718
  <p>
719
- <?php echo $inputs; ?>
 
 
 
720
  </p>
721
- </fieldset>
 
 
 
 
 
 
 
 
 
 
722
  <fieldset>
723
- <legend><?php _e( 'Miscellaneous Settings', 'wp-to-twitter' ); ?></legend>
724
  <ul>
725
  <li>
726
- <input type="checkbox" name="wpt_permit_feed_styles" id="wpt_permit_feed_styles" value="1" <?php echo jd_checkCheckbox( 'wpt_permit_feed_styles' ) ?> />
727
- <label for="wpt_permit_feed_styles"><?php _e( "Disable Twitter Feed Stylesheet", 'wp-to-twitter' ); ?></label>
728
  </li>
729
  <li>
730
- <input type="checkbox" name="wp_debug_oauth" id="wp_debug_oauth" value="1" <?php echo jd_checkCheckbox( 'wp_debug_oauth' ) ?> /> <label for="wp_debug_oauth"><?php _e( "Get Debugging Data for OAuth Connection", 'wp-to-twitter' ); ?></label>
731
  </li>
732
- <li><input type="checkbox" name="jd_donations" id="jd_donations"
733
- value="1" <?php echo jd_checkCheckbox( 'jd_donations' ) ?> /> <label
734
- for="jd_donations"><strong><?php _e( "I made a donation, so stop whinging at me, please.", 'wp-to-twitter' ); ?></strong></label>
735
  </li>
736
  </ul>
737
  </fieldset>
738
  <div>
739
  <input type="hidden" name="submit-type" value="advanced"/>
740
  </div>
741
- <input type="submit" name="submit"
742
- value="<?php _e( "Save Advanced WP to Twitter Options", 'wp-to-twitter' ); ?>"
743
- class="button-primary"/>
744
  </div>
745
  </form>
746
  </div>
747
  </div>
748
  </div>
749
- <?php }
750
- if ( $current == 'support' ) {
 
751
  ?>
752
  <div class="postbox" id="get-support">
753
  <h3><span><?php _e( 'Get Plug-in Support', 'wp-to-twitter' ); ?></span></h3>
754
 
755
  <div class="inside">
756
- <?php if ( ! function_exists( 'wpt_pro_exists' ) ) { ?>
757
- <div class='wpt-support-me'>
758
- <p>
759
- <?php printf(
760
- __( 'Please, consider a <a href="%s">purchase</a> to support WP to Twitter!', 'wp-to-twitter' ), "http://www.wptweetspro.com/wp-tweets-pro" ); ?>
761
- </p>
762
- </div>
763
- <?php } ?>
764
- <?php wpt_get_support_form(); ?>
 
 
 
 
 
 
765
  </div>
766
  </div>
767
- <?php } ?>
 
 
768
  </div>
769
  </div>
770
  <?php wpt_sidebar(); ?>
@@ -773,6 +781,9 @@ function wpt_update_settings() {
773
  <?php
774
  }
775
 
 
 
 
776
  function wpt_sidebar() {
777
  $context = ( ! function_exists( 'wpt_pro_exists' ) ) ? 'free' : 'premium';
778
  ?>
@@ -780,20 +791,27 @@ function wpt_sidebar() {
780
  <div class="metabox-holder">
781
  <div class="ui-sortable meta-box-sortables<?php echo ' ' . $context; ?>">
782
  <div class="postbox">
783
- <?php if ( $context == 'free' ) { ?>
784
- <h3>
785
- <span><strong><?php _e( 'Support WP to Twitter', 'wp-to-twitter' ); ?></strong></span></h3>
786
- <?php } else { ?>
787
- <h3>
788
- <span><strong><?php _e( 'WP to Twitter Support', 'wp-to-twitter' ); ?></strong></span></h3>
789
- <?php } ?>
 
 
 
 
790
  <div class="inside resources">
791
- <?php if ( get_option( 'jd_donations' ) != 1 && ! function_exists( 'wpt_pro_exists' ) ) { ?>
792
- <p class='cta'><?php _e( '<a href="http://www.wptweetspro.com/wp-tweets-pro">Get WP Tweets Pro</a>', 'wp-to-twitter' ); ?></p>
793
- <?php } ?>
 
 
 
 
794
  <p>
795
- <a href="https://twitter.com/intent/follow?screen_name=joedolson" class="twitter-follow-button"
796
- data-size="small" data-related="joedolson">Follow @joedolson</a>
797
  <script>!function (d, s, id) {
798
  var js, fjs = d.getElementsByTagName(s)[0];
799
  if (!d.getElementById(id)) {
@@ -805,84 +823,102 @@ function wpt_sidebar() {
805
  }(document, "script", "twitter-wjs");</script>
806
  </p>
807
  <?php
808
- if ( $context == 'premium' ) {
809
  $support_url = admin_url( 'admin.php?page=wp-tweets-pro' );
810
- $support = '<a href="' . esc_url( add_query_arg( 'tab', 'support', $support_url ) ) . '#get-support">' . __( "Get Support", 'wp-to-twitter' ) . '</a> &bull;';
811
  } else {
812
  $support_url = false;
813
- $support = '';
814
- }
815
  echo $support;
816
  ?>
817
  <a href="https://www.joedolson.com/wp-content/uploads/wp-tweets-pro-users-guide-current.pdf"><?php _e( 'Read the Manual', 'wp-to-twitter' ); ?></a>
818
  </div>
819
  </div>
820
  </div>
821
-
822
  <div class="ui-sortable meta-box-sortables">
823
  <div class="postbox">
824
- <h3><?php _e( 'Twitter Time Check', 'wp-to-twitter' ); ?></h3>
 
 
 
 
825
 
826
  <div class="inside server">
827
- <?php wpt_do_server_check(); ?>
828
  </div>
829
  </div>
830
  </div>
831
-
832
  <div class="ui-sortable meta-box-sortables">
833
  <div class="postbox">
834
  <h3><?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?></h3>
835
-
836
  <div class="inside test">
837
  <p>
838
- <?php _e( 'Check whether WP to Twitter is setup correctly for Twitter and your URL Shortener. The test sends a status update to Twitter and shortens a URL using your chosen shortener.', 'wp-to-twitter' ); ?>
839
  </p>
840
  <form method="post" action="">
841
  <input type="hidden" name="submit-type" value="check-support"/>
842
- <?php $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
843
- echo "<div>$nonce</div>"; ?>
 
 
844
  <p>
845
- <input type="submit" name="submit" value="<?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?>" class="button-primary" />
846
  </p>
847
- </form>
848
  </div>
849
  </div>
850
  </div>
851
 
852
- <?php if ( get_option( 'wpt_rate_limiting' ) == 1 ) { ?>
 
 
853
  <div class="ui-sortable meta-box-sortables">
854
  <div class="postbox">
855
  <h3><?php _e( 'Monitor Rate Limiting', 'wp-to-twitter' ); ?></h3>
856
 
857
- <div class="inside server">
858
  <?php echo wpt_view_rate_limits(); ?>
859
  </div>
860
  </div>
861
- </div>
862
- <?php } ?>
 
 
863
  </div>
864
  <?php
865
  }
866
 
 
 
 
 
 
867
  function wpt_do_server_check( $test = false ) {
868
  $wpt_server_string = get_option( 'wpt_server_string' );
869
- if ( !$wpt_server_string || isset( $_GET['refresh_wpt_server_string'] ) || $test == true ) {
870
  $server_time = date( DATE_COOKIE );
871
- $response = wp_remote_get( "https://twitter.com/", array( 'timeout' => 30, 'redirection' => 1 ) );
872
-
 
 
 
873
  if ( is_wp_error( $response ) ) {
874
  $warning = '';
875
  $error = $response->errors;
876
  if ( is_array( $error ) ) {
877
- $warning = "<ul>";
878
  foreach ( $error as $k => $e ) {
879
  foreach ( $e as $v ) {
880
- $warning .= "<li>" . $v . "</li>";
881
  }
882
  }
883
- $warning .= "</ul>";
884
  }
885
- $errors = "<li>" . $ssl . $warning . "</li>";
886
  } else {
887
  $date = date( DATE_COOKIE, strtotime( $response['headers']['date'] ) );
888
  $errors = '';
@@ -896,21 +932,21 @@ function wpt_do_server_check( $test = false ) {
896
  }
897
  $diff = "<li>$diff</li>";
898
  } else {
899
- $diff = "<li>" . __( 'WP to Twitter could not contact Twitter\'s remote server.', 'wp-to-twitter' ) . "</li>";
900
  }
901
 
902
  $timezone = '<li>' . __( 'Your server timezone:', 'wp-to-twitter' ) . ' ' . date_default_timezone_get() . '</li>';
903
 
904
- $search = array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' );
905
  $replace = array( 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun' );
906
-
907
  $server_time = str_replace( $search, $replace, $server_time );
908
- $date = str_replace( $search, $replace, $date );
909
-
910
  $wpt_server_string =
911
- "<ul>
912
- <li>" . __( 'Your server time:', 'wp-to-twitter' ) . '<br /><code>' . $server_time . '</code>' . "</li>" .
913
- "<li>" . __( 'Twitter\'s server time: ', 'wp-to-twitter' ) . '<br /><code>' . $date . '</code>' . "</li>
914
  $timezone
915
  $diff
916
  $errors
@@ -918,26 +954,31 @@ function wpt_do_server_check( $test = false ) {
918
  update_option( 'wpt_server_string', $wpt_server_string );
919
  }
920
  echo $wpt_server_string;
921
- $admin_url = admin_url( 'admin.php?page=wp-tweets-pro&amp;refresh_wpt_server_string=true' );
922
-
923
- echo "<p><a href='" . $admin_url . "'>" . __( 'Test again', 'wp-to-twitter' ) . "</a></p>";
924
  }
925
 
926
  add_filter( 'wpt_tweet_length', 'wpt_tweet_length' );
 
 
 
 
 
927
  function wpt_tweet_length() {
928
  $tweet_length = intval( ( get_option( 'wpt_tweet_length' ) ) ? get_option( 'wpt_tweet_length' ) : 140 );
929
- $control = "<p class='tweet_length_control'>
930
  <label for='wpt_tweet_length'>" . __( 'Tweet Length (max 280 characters)', 'wp-to-twitter' ) . "</label>
931
- <input type='number' min='0' max='280' step='1' value='$tweet_length' id='wpt_tweet_length' name='wpt_tweet_length' />
932
- <a href='https://www.joedolson.com/2017/11/twitter-expands-280-characters-sort/'>" . __( 'About this setting', 'wp-to-twitter' ) . "</a>
933
- </p>";
934
-
935
  return $control;
936
  }
937
 
938
  add_filter( 'wpt_settings', 'wpt_set_tweet_length' );
 
 
 
939
  function wpt_set_tweet_length() {
940
  if ( isset( $_POST['wpt_tweet_length'] ) ) {
941
  update_option( 'wpt_tweet_length', intval( $_POST['wpt_tweet_length'] ) );
942
  }
943
- }
1
  <?php
2
+ /**
3
+ * WP to Twitter Settings page
4
+ *
5
+ * @category Settings
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
+
16
+ /**
17
+ * Update WP to Twitter settings.
18
+ */
19
  function wpt_updated_settings() {
20
  wpt_check_version();
21
+
22
  if ( empty( $_POST ) ) {
23
  return;
24
  }
25
+
26
  $nonce = $_REQUEST['_wpnonce'];
27
  if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
28
+ die( 'Security check failed' );
29
  }
30
 
31
  if ( isset( $_POST['oauth_settings'] ) ) {
34
  $oauth_message = '';
35
  }
36
 
37
+ $message = '';
38
 
39
+ // notifications from oauth connection.
40
  if ( isset( $_POST['oauth_settings'] ) ) {
41
+ if ( 'success' == $oauth_message ) {
42
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro?tab=basic' );
43
 
44
  print( '
46
  <p>' . __( 'WP to Twitter is now connected with Twitter.', 'wp-to-twitter' ) . " <a href='$admin_url'>" . __( 'Configure your Tweet templates', 'wp-to-twitter' ) . '</a></p>
47
  </div>
48
  ' );
49
+ } elseif ( 'failed' == $oauth_message ) {
50
  print( '
51
  <div id="message" class="error fade">
52
  <p>' . __( 'WP to Twitter failed to connect with Twitter.', 'wp-to-twitter' ) . ' <strong>' . __( 'Error:', 'wp-to-twitter' ) . '</strong> ' . get_option( 'wpt_error' ) . '</p>
53
  </div>
54
  ' );
55
+ } elseif ( 'cleared' == $oauth_message ) {
56
  print( '
57
  <div id="message" class="updated fade">
58
  <p>' . __( 'OAuth Authentication Data Cleared.', 'wp-to-twitter' ) . '</p>
59
  </div>
60
  ' );
61
+ } elseif ( 'nosync' == $oauth_message ) {
62
  print( '
63
  <div id="message" class="error fade">
64
  <p>' . __( 'OAuth Authentication Failed. Your server time is not in sync with the Twitter servers. Talk to your hosting service to see what can be done.', 'wp-to-twitter' ) . '</p>
68
  print( '
69
  <div id="message" class="error fade">
70
  <p>' . __( 'OAuth Authentication response not understood.', 'wp-to-twitter' ) . '</p>
71
+ </div>
72
  ' );
73
  }
74
  }
75
 
76
+ if ( isset( $_POST['submit-type'] ) && 'advanced' == $_POST['submit-type'] ) {
77
  update_option( 'jd_tweet_default', ( isset( $_POST['jd_tweet_default'] ) ) ? $_POST['jd_tweet_default'] : 0 );
78
  update_option( 'jd_tweet_default_edit', ( isset( $_POST['jd_tweet_default_edit'] ) ) ? $_POST['jd_tweet_default_edit'] : 0 );
79
+
80
+ if ( isset( $_POST['wpt_rate_limiting'] ) && 1 != get_option( 'wpt_rate_limiting' ) ) {
81
  $extend = __( 'Rate Limiting is enabled. Default rate limits are set at 10 posts per category/term per hour. <a href="#special_cases">Edit global default</a> or edit individual terms to customize limits for each category or taxonomy term.', 'wp-to-twitter' );
82
+ wp_schedule_event( current_time( 'timestamp' ) + 3600, 'hourly', 'wptratelimits' );
83
  } else {
84
  $extend = '';
85
  wp_clear_scheduled_hook( 'wptratelimits' );
86
+ }
87
+
88
  update_option( 'wpt_rate_limiting', ( isset( $_POST['wpt_rate_limiting'] ) ) ? 1 : 0 );
89
  update_option( 'wpt_inline_edits', ( isset( $_POST['wpt_inline_edits'] ) ) ? $_POST['wpt_inline_edits'] : 0 );
90
  update_option( 'jd_twit_remote', ( isset( $_POST['jd_twit_remote'] ) ) ? $_POST['jd_twit_remote'] : 0 );
95
  update_option( 'jd_twit_append', $_POST['jd_twit_append'] );
96
  update_option( 'jd_post_excerpt', $_POST['jd_post_excerpt'] );
97
  update_option( 'jd_max_tags', $_POST['jd_max_tags'] );
98
+ $use_cats = ( isset( $_POST['wpt_use_cats'] ) ) ? $_POST['wpt_use_cats'] : 0;
99
  update_option( 'wpt_use_cats', $use_cats );
100
+ update_option( 'wpt_tag_source', ( ( isset( $_POST['wpt_tag_source'] ) && 'slug' == $_POST['wpt_tag_source'] ) ? 'slug' : '' ) );
101
  update_option( 'jd_max_characters', $_POST['jd_max_characters'] );
102
  update_option( 'jd_replace_character', $_POST['jd_replace_character'] );
103
  update_option( 'jd_date_format', $_POST['jd_date_format'] );
104
  update_option( 'jd_dynamic_analytics', $_POST['jd-dynamic-analytics'] );
105
 
106
  $twitter_analytics = ( isset( $_POST['twitter-analytics'] ) ) ? $_POST['twitter-analytics'] : 0;
107
+ if ( 1 == $twitter_analytics ) {
108
  update_option( 'use_dynamic_analytics', 0 );
109
  update_option( 'use-twitter-analytics', 1 );
110
  update_option( 'no-analytics', 0 );
111
+ } elseif ( 2 == $twitter_analytics ) {
112
  update_option( 'use_dynamic_analytics', 1 );
113
  update_option( 'use-twitter-analytics', 0 );
114
  update_option( 'no-analytics', 0 );
121
  update_option( 'twitter-analytics-campaign', $_POST['twitter-analytics-campaign'] );
122
  update_option( 'jd_individual_twitter_users', ( isset( $_POST['jd_individual_twitter_users'] ) ? $_POST['jd_individual_twitter_users'] : 0 ) );
123
 
 
124
  if ( isset( $_POST['wpt_caps'] ) ) {
125
  $perms = $_POST['wpt_caps'];
126
+ $caps = array( 'wpt_twitter_oauth', 'wpt_twitter_custom', 'wpt_twitter_switch', 'wpt_can_tweet', 'wpt_tweet_now' );
 
 
 
 
 
 
127
  foreach ( $perms as $key => $value ) {
128
  $role = get_role( $key );
129
  if ( is_object( $role ) ) {
146
  $message .= __( 'WP to Twitter Advanced Options Updated', 'wp-to-twitter' ) . '. ' . $extend;
147
  }
148
 
149
+ if ( isset( $_POST['submit-type'] ) && 'options' == $_POST['submit-type'] ) {
150
+ // UPDATE OPTIONS.
151
  $wpt_settings = get_option( 'wpt_post_types' );
152
+ if ( ! is_array( $wpt_settings ) ) {
153
  $wpt_settings = array();
154
  }
155
 
156
  $keys = array();
157
  $values = array();
158
  foreach ( $_POST['wpt_post_types'] as $key => $value ) {
159
+ // using wp_encode_emoji allows me to save emoji in templates.
160
+ // ...but I haven't found a way to convert the saved emoji *back* to unicode.
161
  // sending the HTML entity just yields a broken character on Twitter.
162
  $array = array(
163
+ 'post-published-update' => ( isset( $value['post-published-update'] ) ) ? $value['post-published-update'] : '',
164
+ 'post-published-text' => $value['post-published-text'],
165
+ 'post-edited-update' => ( isset( $value['post-edited-update'] ) ) ? $value['post-edited-update'] : '',
166
+ 'post-edited-text' => $value['post-edited-text'],
167
  );
168
+ array_push( $keys, $key );
169
  array_push( $values, $array );
170
  }
171
+
172
  $wpt_settings = array_combine( $keys, $values );
173
  update_option( 'wpt_post_types', $wpt_settings );
174
  update_option( 'newlink-published-text', $_POST['newlink-published-text'] );
175
+ update_option( 'jd_twit_blogroll', ( isset( $_POST['jd_twit_blogroll'] ) ) ? $_POST['jd_twit_blogroll'] : '' );
176
  $message = wpt_select_shortener( $_POST );
177
  $message .= __( 'WP to Twitter Options Updated', 'wp-to-twitter' );
178
  $message = apply_filters( 'wpt_settings', $message, $_POST );
179
  }
180
 
181
+ if ( isset( $_POST['wpt_shortener_update'] ) && 'true' == $_POST['wpt_shortener_update'] ) {
182
  $message = wpt_shortener_update( $_POST );
183
  }
184
 
185
  // Check whether the server has supported for needed functions.
186
+ if ( isset( $_POST['submit-type'] ) && 'check-support' == $_POST['submit-type'] ) {
187
  $message = wpt_check_functions();
188
  }
189
 
192
  }
193
  }
194
 
195
+ /**
196
+ * Show WP to Twitter settings form.
197
+ */
198
  function wpt_update_settings() {
199
  ?>
200
  <div class="wrap" id="wp-to-twitter">
201
+ <?php
202
+ if ( defined( 'WPT_STAGING_MODE' ) && true == WPT_STAGING_MODE ) {
203
+ echo "<div class='updated notice'><p>" . __( 'WP to Twitter is in staging mode. Tweets will be reported as if successfully sent to Twitter but will not be sent.', 'wp-to-twitter' ) . '</p></div>';
204
+ }
205
+ wpt_updated_settings();
206
+ wpt_show_last_tweet();
207
+ wpt_handle_errors();
208
  ?>
209
+ <h1><?php _e( 'WP to Twitter Options', 'wp-to-twitter' ); ?></h1>
210
+
 
211
  <?php wpt_max_length(); ?>
212
+
213
  <div class='nav-tab-wrapper'>
214
  <?php wpt_settings_tabs(); ?>
215
  </div>
216
  <div id="wpt_settings_page" class="postbox-container jcd-wide">
217
  <div class="metabox-holder">
218
 
219
+ <?php
220
+ $default = ( '' == get_option( 'wtt_twitter_username' ) ) ? 'connection' : 'basic';
221
  $current = ( isset( $_GET['tab'] ) ) ? $_GET['tab'] : $default;
222
+ if ( 'connection' == $current ) {
223
  if ( function_exists( 'wtt_connect_oauth' ) ) {
224
  wtt_connect_oauth();
225
  }
226
  }
227
+ if ( 'pro' == $current ) {
228
  if ( function_exists( 'wpt_pro_functions' ) ) {
229
  wpt_pro_functions();
230
  if ( function_exists( 'wpt_notes' ) ) {
231
  wpt_notes();
232
  }
233
  } else {
234
+ if ( ! function_exists( 'wpt_pro_exists' ) ) {
235
+ ?>
236
  <div class="ui-sortable meta-box-sortables">
237
  <div class="postbox">
238
  <h3 class='wpt-upgrade'><span><strong><?php _e( 'Upgrade Now!', 'wp-to-twitter' ); ?></strong></span></h3>
240
  <div class="inside purchase">
241
  <h4><strong><?php _e( 'What can WP Tweets PRO do for you?', 'wp-to-twitter' ); ?></strong></h4>
242
  <p>
243
+ <?php _e( 'WP Tweets PRO takes the great Tweeting abilities from WP to Twitter and puts them in high gear.', 'wp-to-twitter' ); ?>
 
 
244
  </p>
245
  <ul>
246
+ <li><?php _e( 'Publish to unique Twitter accounts for each site author.', 'wp-to-twitter' ); ?></li>
247
  <li><?php _e( 'Schedule up to 3 re-posts of Tweets at an interval of your choice.', 'wp-to-twitter' ); ?></li>
248
  <li><?php _e( 'With a delay between publishing and Tweeting, verify your tweets before you share online.', 'wp-to-twitter' ); ?></li>
249
  <li><?php _e( 'Automatically your great old posts every few hours, days, or weeks!', 'wp-to-twitter' ); ?></li>
250
  <li><?php _e( 'Upload your featured images to Twitter with each Tweet', 'wp-to-twitter' ); ?></li>
251
+ <li>
252
+ <?php
253
+ // Translators: Link to sales page.
254
+ printf( __( 'Take a look at the <a href="%s">complete feature list</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' );
255
+ ?>
256
+ </li>
257
  </ul>
258
  <p>
259
+ <strong><?php _e( 'Use WP Tweets PRO to keep traffic coming for every post.', 'wp-to-twitter' ); ?></strong>
260
  </p>
261
  <p class='wpt-button'>
262
  <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Upgrade to <strong>WP Tweets PRO</strong>!', 'wp-to-twitter' ); ?></a></strong>
263
+ </p>
264
+
265
  <h4><?php _e( 'What else does WP Tweets PRO do?', 'wp-to-twitter' ); ?></h4>
266
+
267
  <p>
268
  <?php _e( 'WP Tweets PRO is packed with features to help you increase engagement with your Twitter followers. Upload images, use Twitter Cards, and automated re-posting of your Tweets are just a few of the features available in the premium add-on to WP to Twitter.', 'wp-to-twitter' ); ?>
269
  </p>
270
  <p>
271
+ <?php
272
+ // Translators: link to GitHub repo of add-ons.
273
+ printf( __( 'Is there something that WP Tweets PRO <em>doesn\'t already do for you</em>? No problem! Take a look at the extensive <a href="%s">library of plug-in extensions</a> - you can try out or modify any of these code samples to extend and customize WP Tweets PRO.', 'wp-to-twitter' ), 'https://github.com/joedolson/plugin-extensions/tree/master/wp-to-twitter' );
274
+ ?>
275
  </p>
276
  <p>
277
+ <?php
278
+ // Translators: Link to sales page.
279
+ printf( __( '<a href="%s">Learn more about WP Tweets PRO</a>!', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro?campaign=get-wpt' );
280
+ ?>
281
  </p>
282
+
283
  <p class='wpt-button'>
284
  <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Buy WP Tweets PRO today!', 'wp-to-twitter' ); ?></a></strong>
285
  </p>
 
286
  </div>
287
  </div>
288
  </div>
290
  }
291
  }
292
  }
293
+ if ( 'basic' == $current ) {
294
  ?>
295
  <div class="ui-sortable meta-box-sortables">
296
  <div class="postbox">
298
 
299
  <div class="inside wpt-settings">
300
  <form method="post" action="">
301
+ <?php
302
+ $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
303
+ echo "<div>$nonce</div>";
304
+ ?>
305
  <div>
 
 
306
  <?php
307
+ echo apply_filters( 'wpt_tweet_length', '' );
308
+ echo apply_filters( 'wpt_pick_shortener', '' );
309
  $post_types = get_post_types( array( 'public' => true ), 'objects' );
310
  $wpt_settings = get_option( 'wpt_post_types' );
311
  $tabs = "<ul class='tabs' role='tablist'>";
312
  foreach ( $post_types as $type ) {
313
+ $name = $type->labels->name;
314
+ $slug = $type->name;
315
+ if ( 'attachment' == $slug || 'nav_menu_item' == $slug || 'revision' == $slug ) {
316
  } else {
317
  $tabs .= "<li><a href='#wpt_$slug' role='tab' id='tab_wpt_$slug' aria-controls='wpt_$slug'>$name</a></li>";
318
  }
319
  }
320
+ $tabs .= "<li><a href='#wpt_links' id='tab_wpt_links' aria-controls='wpt_links'>" . __( 'Links', 'wp-to-twitter' ) . '</a></li></ul>';
 
321
  echo $tabs;
322
  foreach ( $post_types as $type ) {
323
+ $name = $type->labels->name;
324
+ $slug = $type->name;
325
+ if ( 'attachment' == $slug || 'nav_menu_item' == $slug || 'revision' == $slug ) {
 
326
  continue;
327
  } else {
 
 
 
 
 
 
 
 
 
328
  ?>
 
329
  <div class='wptab wpt_types wpt_<?php echo $slug; ?>' aria-labelledby='tab_wpt_<?php echo $slug; ?>' role="tabpanel" id='wpt_<?php echo $slug; ?>'>
330
+ <?php
331
+ // share information about any usage of pre 2.8 category filters.
332
+ if ( '0' != get_option( 'limit_categories' ) && 'post' == $slug ) {
333
+ $falseness = get_option( 'jd_twit_cats' );
334
+ $categories = get_option( 'tweet_categories' );
335
+ if ( 1 == $falseness ) {
336
+ echo '<p>' . __( 'These categories are currently <strong>excluded</strong> by the deprecated WP to Twitter category filters.', 'wp-to-twitter' ) . '</p>';
337
+ } else {
338
+ echo '<p>' . __( 'These categories are currently <strong>allowed</strong> by the deprecated WP to Twitter category filters.', 'wp-to-twitter' ) . '</p>';
339
+ }
340
+ echo '<ul>';
341
+ if ( is_array( $categories ) ) {
342
+ foreach ( $categories as $cat ) {
343
+ $category = get_the_category_by_ID( $cat );
344
+ echo "<li>$category</li>";
 
 
 
 
 
 
 
345
  }
346
  }
347
+ echo '</ul>';
348
+ if ( ! function_exists( 'wpt_pro_exists' ) ) {
349
+ // Translators: Link to sales page.
350
+ printf( __( '<a href="%s">Upgrade to WP Tweets PRO</a> to filter posts in all custom post types on any taxonomy.', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro' );
351
+ } else {
352
+ _e( 'Updating the WP Tweets PRO taxonomy filters will overwrite your old category filters.', 'wp-to-twitter' );
353
+ }
354
+ }
355
+ ?>
356
+ <fieldset>
357
+ <legend><?php _e( 'Tweet Templates', 'wp-to-twitter' ); ?></legend>
358
+ <p>
359
+ <input type="checkbox" name="wpt_post_types[<?php echo $slug; ?>][post-published-update]" id="<?php echo $slug; ?>-post-published-update" value="1" <?php echo wpt_checkbox( 'wpt_post_types', $slug, 'post-published-update' ); ?> />
360
+ <label for="<?php echo $slug; ?>-post-published-update"><strong>
361
+ <?php
362
+ // Translators: post type.
363
+ printf( __( 'Update when %s are published', 'wp-to-twitter' ), $name );
364
+ ?>
365
+ </strong></label>
366
+ <label for="<?php echo $slug; ?>-post-published-text"><br/>
367
+ <?php
368
+ // Translators: post type.
369
+ printf( __( 'Template for new %s', 'wp-to-twitter' ), $name );
370
+ ?>
371
+ </label><br/>
372
+ <textarea class="wpt-template" name="wpt_post_types[<?php echo $slug; ?>][post-published-text]" id="<?php echo $slug; ?>-post-published-text" cols="60" rows="3"><?php echo ( isset( $wpt_settings[ $slug ] ) ) ? esc_attr( stripslashes( $wpt_settings[ $slug ]['post-published-text'] ) ) : ''; ?></textarea>
373
+ </p>
374
+
375
+ <p>
376
+ <input type="checkbox" name="wpt_post_types[<?php echo $slug; ?>][post-edited-update]" id="<?php echo $slug; ?>-post-edited-update" value="1" <?php echo wpt_checkbox( 'wpt_post_types', $slug, 'post-edited-update' ); ?> />
377
+ <label for="<?php echo $slug; ?>-post-edited-update"><strong>
378
+ <?php
379
+ // Translators: post type name.
380
+ printf( __( 'Update when %s are edited', 'wp-to-twitter' ), $name );
381
+ ?>
382
+ </strong></label><br/><label for="<?php echo $slug; ?>-post-edited-text">
383
+ <?php
384
+ // Translators: post type name.
385
+ printf( __( 'Template for %1$s edits', 'wp-to-twitter' ), $name );
386
+ ?>
387
+ </label><br/>
388
+ <textarea class="wpt-template" name="wpt_post_types[<?php echo $slug; ?>][post-edited-text]" id="<?php echo $slug; ?>-post-edited-text" cols="60" rows="3"><?php echo ( isset( $wpt_settings[ $slug ] ) ) ? esc_attr( stripslashes( $wpt_settings[ $slug ]['post-edited-text'] ) ) : ''; ?></textarea>
389
+ </p>
390
+ </fieldset>
391
+ <?php
392
+ if ( function_exists( 'wpt_list_terms' ) ) {
393
+ wpt_list_terms( $slug, $name );
394
+ }
395
+ ?>
396
  </div>
397
  <?php
398
  }
402
  <fieldset>
403
  <legend><span><?php _e( 'Links', 'wp-to-twitter' ); ?></span></legend>
404
  <p>
405
+ <input type="checkbox" name="jd_twit_blogroll" id="jd_twit_blogroll" value="1" <?php echo wpt_checkbox( 'jd_twit_blogroll' ); ?> />
406
+ <label for="jd_twit_blogroll"><strong><?php _e( 'Update Twitter when you post a Blogroll link', 'wp-to-twitter' ); ?></strong></label><br/>
407
+ <label for="newlink-published-text"><?php _e( 'Text for new link updates:', 'wp-to-twitter' ); ?></label>
408
+ <input aria-describedby="newlink-published-text-label" type="text" class="wpt-template" name="newlink-published-text" id="newlink-published-text" size="60" maxlength="120" value="<?php echo esc_attr( stripslashes( get_option( 'newlink-published-text' ) ) ); ?>"/><br/><span id="newlink-published-text-label"><?php _e( 'Available shortcodes: <code>#url#</code>, <code>#title#</code>, and <code>#description#</code>.', 'wp-to-twitter' ); ?></span>
 
 
 
 
 
 
 
409
  </p>
410
  </fieldset>
411
  </div>
412
  <div>
413
  <input type="hidden" name="submit-type" value="options" />
414
  </div>
415
+ <input type="submit" name="submit" value="<?php _e( 'Save WP to Twitter Options', 'wp-to-twitter' ); ?>" class="button-primary" />
416
  </div>
417
  </form>
418
  </div>
419
  </div>
420
  </div>
421
+
422
  <div class="ui-sortable meta-box-sortables">
423
  <div class="postbox">
424
  <h3><span><?php _e( 'Tweet Template Tags', 'wp-to-twitter' ); ?></span></h3>
 
425
  <div class="inside">
426
  <ul>
427
+ <li><?php _e( '<code>#title#</code>: the title of your blog post', 'wp-to-twitter' ); ?></li>
428
+ <li><?php _e( '<code>#blog#</code>: the title of your blog', 'wp-to-twitter' ); ?></li>
429
+ <li><?php _e( '<code>#post#</code>: a short excerpt of the post content', 'wp-to-twitter' ); ?></li>
430
+ <li><?php _e( '<code>#category#</code>: the first selected category for the post', 'wp-to-twitter' ); ?></li>
431
+ <li><?php _e( '<code>#cat_desc#</code>: custom value from the category description field', 'wp-to-twitter' ); ?></li>
432
+ <li><?php _e( '<code>#date#</code>: the post date', 'wp-to-twitter' ); ?></li>
433
+ <li><?php _e( '<code>#modified#</code>: the post modified date', 'wp-to-twitter' ); ?></li>
434
+ <li><?php _e( '<code>#url#</code>: the post URL', 'wp-to-twitter' ); ?></li>
435
+ <li><?php _e( '<code>#longurl#</code>: the unshortened post URL', 'wp-to-twitter' ); ?></li>
436
+ <li><?php _e( '<code>#author#</code>: the post author (@reference if available, otherwise display name)', 'wp-to-twitter' ); ?></li>
437
+ <li><?php _e( '<code>#displayname#</code>: post author\'s display name', 'wp-to-twitter' ); ?></li>
438
+ <li><?php _e( '<code>#account#</code>: the twitter @reference for the account (or the author, if author settings are enabled and set.)', 'wp-to-twitter' ); ?></li>
439
+ <li><?php _e( '<code>#@#</code>: the twitter @reference for the author or blank, if not set', 'wp-to-twitter' ); ?></li>
440
+ <li><?php _e( '<code>#tags#</code>: your tags modified into hashtags.', 'wp-to-twitter' ); ?></li>
441
+ <?php
442
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
443
+ ?>
444
+ <li><?php _e( '<code>#reference#</code>: Used only in co-tweeting. @reference to main account when posted to author account, @reference to author account in post to main account.', 'wp-to-twitter' ); ?></li>
445
+ <?php
446
+ }
447
+ ?>
448
  </ul>
449
  <p>
450
+ <?php _e( 'Create custom shortcodes and access WordPress custom fields by using square brackets and the name of your custom field.', 'wp-to-twitter' ); ?>
 
 
451
  <br />
452
+ <?php _e( '<strong>Example:</strong> <code>[[custom_field]]</code>', 'wp-to-twitter' ); ?>
 
 
453
  </p>
454
  <p>
455
+ <?php _e( 'Create custom shortcodes and access the post author\'s custom user meta fields by using curly brackets and the name of the custom field.', 'wp-to-twitter' ); ?>
 
 
456
  <br />
457
+ <?php _e( '<strong>Example:</strong> <code>{{user_meta}}</code>', 'wp-to-twitter' ); ?>
458
+ </p>
 
 
459
  </div>
460
  </div>
461
+ </div>
462
+ <?php
463
+ }
464
+ if ( 'shortener' == $current ) {
465
+ echo apply_filters( 'wpt_shortener_controls', '' );
466
  }
467
+
468
+ if ( 'advanced' == $current ) {
469
  ?>
470
+ <form method="post" action="">
471
  <div class="ui-sortable meta-box-sortables">
472
  <div class="postbox">
473
  <h3><span><?php _e( 'Advanced Settings', 'wp-to-twitter' ); ?></span></h3>
474
  <div class="inside">
 
475
  <div>
476
+ <?php
477
  $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
478
+ echo "<div>$nonce</div>";
479
  ?>
480
 
481
  <fieldset>
482
+ <legend class='screen-reader-text'><?php _e( 'Hashtags', 'wp-to-twitter' ); ?></legend>
483
  <p>
484
+ <input type="checkbox" name="jd_strip_nonan" id="jd_strip_nonan" value="1" <?php echo checked( get_option( 'jd_strip_nonan' ), 1 ); ?> /> <label for="jd_strip_nonan"><?php _e( 'Strip nonalphanumeric characters from tags', 'wp-to-twitter' ); ?></label>
 
 
485
  </p>
 
486
  <p>
487
+ <input type="checkbox" name="wpt_tag_source" id="wpt_tag_source" value="slug" <?php checked( get_option( 'wpt_tag_source' ), 'slug' ); ?> />
488
+ <label for="wpt_tag_source"><?php _e( 'Use tag slug as hashtag value', 'wp-to-twitter' ); ?></label><br/>
 
 
489
  </p>
490
+ <p>
491
  <input type="checkbox" name="wpt_use_cats" id="wpt_use_cats" value="1" <?php checked( get_option( 'wpt_use_cats' ), '1' ); ?> />
492
+ <label for="wpt_use_cats"><?php _e( 'Use categories instead of tags', 'wp-to-twitter' ); ?></label><br/>
493
  </p>
494
  <p>
495
+ <label for="jd_replace_character"><?php _e( 'Spaces in tags replaced with:', 'wp-to-twitter' ); ?></label>
496
+ <input type="text" name="jd_replace_character" id="jd_replace_character" value="<?php echo esc_attr( get_option( 'jd_replace_character' ) ); ?>" size="3"/>
 
 
 
497
  </p>
498
 
499
  <p>
500
+ <label for="jd_max_tags"><?php _e( 'Maximum number of tags to include:', 'wp-to-twitter' ); ?></label>
501
+ <input aria-describedby="jd_max_characters_label" type="text" name="jd_max_tags" id="jd_max_tags" value="<?php echo esc_attr( get_option( 'jd_max_tags' ) ); ?>" size="3"/>
 
 
 
502
  </p>
503
  <p>
504
+ <label for="jd_max_characters"><?php _e( 'Maximum length in characters for included tags:', 'wp-to-twitter' ); ?></label>
505
+ <input type="text" name="jd_max_characters" id="jd_max_characters" value="<?php echo esc_attr( get_option( 'jd_max_characters' ) ); ?>" size="3"/>
 
 
506
  </p>
507
  </fieldset>
508
+ </div>
509
+ </div>
510
+ </div>
511
+ <div class="ui-sortable meta-box-sortables">
512
+ <div class="postbox">
513
+ <h3><span><?php _e( 'Template Settings', 'wp-to-twitter' ); ?></span></h3>
514
+ <div class="inside">
515
  <fieldset>
516
+ <legend class='screen-reader-text'><?php _e( 'Template Settings', 'wp-to-twitter' ); ?></legend>
517
  <p>
518
+ <label for="jd_post_excerpt"><?php _e( 'Post excerpt (#post#) in characters:', 'wp-to-twitter' ); ?></label>
519
+ <input type="text" name="jd_post_excerpt" id="jd_post_excerpt" size="3" maxlength="3" value="<?php echo( esc_attr( get_option( 'jd_post_excerpt' ) ) ); ?>"/>
 
520
  </p>
 
521
  <p>
522
+ <label for="jd_date_format"><?php _e( 'Date Format (#date#):', 'wp-to-twitter' ); ?></label>
523
+ <input type="text" aria-describedby="date_format_label" name="jd_date_format" id="jd_date_format" size="12" maxlength="12" value="
524
+ <?php
525
+ if ( '' == get_option( 'jd_date_format' ) ) {
526
+ echo( esc_attr( stripslashes( get_option( 'date_format' ) ) ) );
527
+ } else {
528
+ echo( esc_attr( get_option( 'jd_date_format' ) ) );
529
+ }
530
+ ?>
531
+ "/>
532
+ <?php
533
+ if ( '' != get_option( 'jd_date_format' ) ) {
534
  echo date_i18n( get_option( 'jd_date_format' ) );
535
  } else {
536
+ echo '<em>' . date_i18n( get_option( 'date_format' ) ) . '</em>';
537
+ }
538
+ ?>
539
+ (<em id="date_format_label"><a href='http://codex.wordpress.org/Formatting_Date_and_Time'><?php _e( 'Date Formatting', 'wp-to-twitter' ); ?></a></em>)
540
  </p>
541
 
542
  <p>
543
+ <label for="jd_twit_prepend"><?php _e( 'Custom text before Tweets:', 'wp-to-twitter' ); ?></label>
544
+ <input type="text" name="jd_twit_prepend" id="jd_twit_prepend" size="20" value="<?php echo esc_attr( stripslashes( get_option( 'jd_twit_prepend' ) ) ); ?>"/>
 
545
  </p>
546
  <p>
547
+ <label for="jd_twit_append"><?php _e( 'Custom text after Tweets:', 'wp-to-twitter' ); ?></label>
548
+ <input type="text" name="jd_twit_append" id="jd_twit_append" size="20" value="<?php echo esc_attr( stripslashes( get_option( 'jd_twit_append' ) ) ); ?>"/>
 
549
  </p>
550
  <p>
551
+ <label for="jd_twit_custom_url"><?php _e( 'Custom field for alternate post URL:', 'wp-to-twitter' ); ?></label>
552
+ <input type="text" name="jd_twit_custom_url" id="jd_twit_custom_url" size="30" maxlength="120" value="<?php echo esc_attr( stripslashes( get_option( 'jd_twit_custom_url' ) ) ); ?>"/>
 
553
  </p>
554
  </fieldset>
555
+ </div>
556
+ </div>
557
+ </div>
558
+ <div class="ui-sortable meta-box-sortables">
559
+ <div class="postbox">
560
+ <h3><span><?php _e( 'Special Cases', 'wp-to-twitter' ); ?></span></h3>
561
+ <div class="inside">
562
  <fieldset>
563
+ <legend id="special_cases" class='screen-reader-text'><?php _e( 'Special Cases', 'wp-to-twitter' ); ?></legend>
564
  <p>
565
+ <input type="checkbox" name="jd_tweet_default" id="jd_tweet_default" value="1" <?php echo wpt_checkbox( 'jd_tweet_default' ); ?> />
566
+ <label for="jd_tweet_default"><?php _e( 'Do not post Tweets by default', 'wp-to-twitter' ); ?></label><br/>
567
+ <input type="checkbox" name="jd_tweet_default_edit" id="jd_tweet_default_edit" value="1" <?php echo wpt_checkbox( 'jd_tweet_default_edit' ); ?> />
568
+ <label for="jd_tweet_default_edit"><?php _e( 'Do not post Tweets by default (editing only)', 'wp-to-twitter' ); ?></label><br/>
569
+ <input type="checkbox" name="wpt_inline_edits" id="wpt_inline_edits" value="1" <?php echo wpt_checkbox( 'wpt_inline_edits' ); ?> />
570
+ <label for="wpt_inline_edits"><?php _e( 'Allow status updates from Quick Edit', 'wp-to-twitter' ); ?></label><br/>
571
+ <input type="checkbox" name="wpt_rate_limiting" id="wpt_rate_limiting" value="1" <?php echo wpt_checkbox( 'wpt_rate_limiting' ); ?> />
572
+ <label for="wpt_rate_limiting"><?php _e( 'Enable Rate Limiting', 'wp-to-twitter' ); ?></label><br/>
 
 
 
 
 
 
 
 
573
  <?php
574
  if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
575
+ ?>
576
+ <input type="number" name="wpt_default_rate_limit" min="1" id="wpt_default_rate_limit" value="<?php echo wpt_default_rate_limit(); ?>" />
577
+ <label for="wpt_default_rate_limit"><?php _e( 'Default Rate Limit per category per hour', 'wp-to-twitter' ); ?></label><br/>
578
+ <?php
 
 
579
  }
580
  ?>
581
  </p>
582
  </fieldset>
583
+ </div>
584
+ </div>
585
+ </div>
586
+ <div class="ui-sortable meta-box-sortables">
587
+ <div class="postbox">
588
+ <h3><span><?php _e( 'Google Analytics Settings', 'wp-to-twitter' ); ?></span></h3>
589
+ <div class="inside">
590
  <fieldset>
591
+ <legend class='screen-reader-text'><?php _e( 'Google Analytics Settings', 'wp-to-twitter' ); ?></legend>
592
 
593
  <p>
594
+ <input type="radio" name="twitter-analytics" id="use-twitter-analytics" value="1" <?php echo wpt_checkbox( 'use-twitter-analytics' ); ?> />
595
+ <label for="use-twitter-analytics"><?php _e( 'Use a Static Identifier', 'wp-to-twitter' ); ?></label><br/>
596
+ <label for="twitter-analytics-campaign"><?php _e( 'Static Campaign identifier', 'wp-to-twitter' ); ?></label>
597
+ <input type="text" name="twitter-analytics-campaign" id="twitter-analytics-campaign" size="40" maxlength="120" value="<?php echo esc_attr( get_option( 'twitter-analytics-campaign' ) ); ?>"/><br/>
 
 
 
 
 
598
  </p>
 
599
  <p>
600
+ <input type="radio" name="twitter-analytics" id="use-dynamic-analytics" value="2" <?php echo wpt_checkbox( 'use_dynamic_analytics' ); ?> />
601
+ <label for="use-dynamic-analytics"><?php _e( 'Use a dynamic identifier', 'wp-to-twitter' ); ?></label><br/>
602
+ <label for="jd-dynamic-analytics"><?php _e( 'What dynamic identifier would you like to use?', 'wp-to-twitter' ); ?></label>
 
 
 
603
  <select name="jd-dynamic-analytics" id="jd-dynamic-analytics">
604
+ <option value="post_category"<?php checked( get_option( 'jd_dynamic_analytics' ), 'post_category' ); ?>><?php _e( 'Category', 'wp-to-twitter' ); ?></option>
605
+ <option value="post_ID"<?php checked( get_option( 'jd_dynamic_analytics' ), 'post_ID' ); ?>><?php _e( 'Post ID', 'wp-to-twitter' ); ?></option>
606
+ <option value="post_title"<?php checked( get_option( 'jd_dynamic_analytics' ), 'post_title' ); ?>><?php _e( 'Post Title', 'wp-to-twitter' ); ?></option>
607
+ <option value="post_author"<?php checked( get_option( 'jd_dynamic_analytics' ), 'post_author' ); ?>><?php _e( 'Author', 'wp-to-twitter' ); ?></option>
 
 
 
 
608
  </select><br/>
609
  </p>
610
  <p>
611
+ <input type="radio" name="twitter-analytics" id="no-analytics" value="3" <?php echo wpt_checkbox( 'no-analytics' ); ?> /> <label for="no-analytics"><?php _e( 'No Analytics', 'wp-to-twitter' ); ?></label>
 
 
612
  </p>
613
  </fieldset>
614
+ </div>
615
+ </div>
616
+ </div>
617
+ <div class="ui-sortable meta-box-sortables">
618
+ <div class="postbox">
619
+ <h3><span><?php _e( 'Author Settings', 'wp-to-twitter' ); ?></span></h3>
620
+ <div class="inside">
621
+
622
+ <p>
623
+ <input type="checkbox" name="jd_individual_twitter_users" id="jd_individual_twitter_users" value="1" <?php echo wpt_checkbox( 'jd_individual_twitter_users' ); ?> />
624
+ <label for="jd_individual_twitter_users"><?php _e( 'Authors have individual Twitter accounts', 'wp-to-twitter' ); ?></label>
625
+ </p>
626
 
 
627
  <div class='wpt-permissions'>
628
  <fieldset>
629
  <legend><?php _e( 'Permissions', 'wp-to-twitter' ); ?></legend>
630
  <?php
631
  global $wp_roles;
632
+ $roles = $wp_roles->get_names();
633
+ $caps = array(
634
  'wpt_can_tweet' => __( 'Can send Tweets', 'wp-to-twitter' ),
635
  'wpt_twitter_custom' => __( 'See Custom Tweet Field when creating a Post', 'wp-to-twitter' ),
636
  'wpt_twitter_switch' => __( 'Toggle the Tweet/Don\'t Tweet option', 'wp-to-twitter' ),
637
  'wpt_tweet_now' => __( 'Can see Tweet Now button', 'wp-to-twitter' ),
638
+ 'wpt_twitter_oauth' => __( 'Allow user to authenticate with Twitter', 'wp-to-twitter' ),
639
  );
640
+ $role_tabs = '';
641
+ $role_container = '';
642
  foreach ( $roles as $role => $rolename ) {
643
+ if ( 'administrator' == $role ) {
644
  continue;
645
  }
646
+ $role_tabs .= "<li><a href='#wpt_" . sanitize_title( $role ) . "'>$rolename</a></li>\n";
647
  $role_container .= "<div class='wptab wpt_$role' id='wpt_" . sanitize_title( $role ) . "' aria-live='assertive'><fieldset id='wpt_$role' class='roles'><legend>$rolename</legend>";
648
  $role_container .= "<input type='hidden' value='none' name='wpt_caps[" . $role . "][none]' />
649
+ <ul class='wpt-settings checkboxes'>";
650
  foreach ( $caps as $cap => $name ) {
651
  $role_container .= wpt_cap_checkbox( $role, $cap, $name );
652
  }
653
+ $role_container .= '</ul></fieldset></div>';
 
654
  }
655
  echo "
656
  <ul class='tabs'>
660
  ?>
661
  </fieldset>
662
  </div>
663
+ </div>
664
+ </div>
665
+ </div>
666
+ <div class="ui-sortable meta-box-sortables">
667
+ <div class="postbox">
668
+ <h3><span><?php _e( 'Template tag priority order', 'wp-to-twitter' ); ?></span></h3>
669
+ <div class="inside">
670
+ <?php
671
  $inputs = '';
672
  $default_order = array(
673
  'excerpt' => 0,
680
  'tags' => 7,
681
  'modified' => 8,
682
  '@' => 9,
683
+ 'cat_desc' => 10,
684
  );
685
  $preferred_order = get_option( 'wpt_truncation_order' );
686
  if ( ! $preferred_order ) {
692
  }
693
  asort( $default_order );
694
  foreach ( $default_order as $k => $v ) {
695
+ if ( 'blogname' == $k ) {
696
+ $label = '<code>#blog#</code>';
697
+ } elseif ( 'excerpt' == $k ) {
698
  $label = '<code>#post#</code>';
699
  } else {
700
  $label = '<code>#' . $k . '#</code>';
703
  }
704
  ?>
705
  <fieldset>
706
+ <legend class='screen-reader-text'><?php _e( 'Template tag priority order', 'wp-to-twitter' ); ?></legend>
 
707
  <p>
708
+ <?php
709
+ _e( 'The order in which items will be abbreviated or removed from your Tweet if the Tweet is too long to send to Twitter.', 'wp-to-twitter' );
710
+ _e( 'Tags with lower values will be modified first.', 'wp-to-twitter' );
711
+ ?>
712
  </p>
713
+ <p>
714
+ <?php echo $inputs; ?>
715
+ </p>
716
+ </fieldset>
717
+ </div>
718
+ </div>
719
+ </div>
720
+ <div class="ui-sortable meta-box-sortables">
721
+ <div class="postbox">
722
+ <h3><span><?php _e( 'Miscellaneous Settings', 'wp-to-twitter' ); ?></span></h3>
723
+ <div class="inside">
724
  <fieldset>
725
+ <legend class='screen-reader-text'><?php _e( 'Miscellaneous Settings', 'wp-to-twitter' ); ?></legend>
726
  <ul>
727
  <li>
728
+ <input type="checkbox" name="wpt_permit_feed_styles" id="wpt_permit_feed_styles" value="1" <?php echo wpt_checkbox( 'wpt_permit_feed_styles' ); ?> />
729
+ <label for="wpt_permit_feed_styles"><?php _e( 'Disable Twitter Feed Stylesheet', 'wp-to-twitter' ); ?></label>
730
  </li>
731
  <li>
732
+ <input type="checkbox" name="wp_debug_oauth" id="wp_debug_oauth" value="1" <?php echo wpt_checkbox( 'wp_debug_oauth' ); ?> /> <label for="wp_debug_oauth"><?php _e( 'Get Debugging Data for OAuth Connection', 'wp-to-twitter' ); ?></label>
733
  </li>
734
+ <li>
735
+ <input type="checkbox" name="jd_donations" id="jd_donations" value="1" <?php echo wpt_checkbox( 'jd_donations' ); ?> /> <label for="jd_donations"><strong><?php _e( 'I made a donation, so stop whinging at me, please.', 'wp-to-twitter' ); ?></strong></label>
 
736
  </li>
737
  </ul>
738
  </fieldset>
739
  <div>
740
  <input type="hidden" name="submit-type" value="advanced"/>
741
  </div>
742
+ <input type="submit" name="submit" value="<?php _e( 'Save Advanced WP to Twitter Options', 'wp-to-twitter' ); ?>" class="button-primary"/>
 
 
743
  </div>
744
  </form>
745
  </div>
746
  </div>
747
  </div>
748
+ <?php
749
+ }
750
+ if ( 'support' == $current ) {
751
  ?>
752
  <div class="postbox" id="get-support">
753
  <h3><span><?php _e( 'Get Plug-in Support', 'wp-to-twitter' ); ?></span></h3>
754
 
755
  <div class="inside">
756
+ <?php
757
+ if ( ! function_exists( 'wpt_pro_exists' ) ) {
758
+ ?>
759
+ <div class='wpt-support-me'>
760
+ <p>
761
+ <?php
762
+ // Translators: Link to sales page.
763
+ printf( __( 'Please, consider a <a href="%s">purchase</a> to support WP to Twitter!', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro' );
764
+ ?>
765
+ </p>
766
+ </div>
767
+ <?php
768
+ }
769
+ wpt_get_support_form();
770
+ ?>
771
  </div>
772
  </div>
773
+ <?php
774
+ }
775
+ ?>
776
  </div>
777
  </div>
778
  <?php wpt_sidebar(); ?>
781
  <?php
782
  }
783
 
784
+ /**
785
+ * Show WP to Twitter sidebar content.
786
+ */
787
  function wpt_sidebar() {
788
  $context = ( ! function_exists( 'wpt_pro_exists' ) ) ? 'free' : 'premium';
789
  ?>
791
  <div class="metabox-holder">
792
  <div class="ui-sortable meta-box-sortables<?php echo ' ' . $context; ?>">
793
  <div class="postbox">
794
+ <?php
795
+ if ( 'free' == $context ) {
796
+ ?>
797
+ <h3><span><strong><?php _e( 'Support WP to Twitter', 'wp-to-twitter' ); ?></strong></span></h3>
798
+ <?php
799
+ } else {
800
+ ?>
801
+ <h3><span><strong><?php _e( 'WP to Twitter Support', 'wp-to-twitter' ); ?></strong></span></h3>
802
+ <?php
803
+ }
804
+ ?>
805
  <div class="inside resources">
806
+ <?php
807
+ if ( 1 != get_option( 'jd_donations' ) && ! function_exists( 'wpt_pro_exists' ) ) {
808
+ ?>
809
+ <p class='cta'><?php _e( '<a href="http://www.wptweetspro.com/wp-tweets-pro">Get WP Tweets Pro</a>', 'wp-to-twitter' ); ?></p>
810
+ <?php
811
+ }
812
+ ?>
813
  <p>
814
+ <a href="https://twitter.com/intent/follow?screen_name=joedolson" class="twitter-follow-button" data-size="small" data-related="joedolson">Follow @joedolson</a>
 
815
  <script>!function (d, s, id) {
816
  var js, fjs = d.getElementsByTagName(s)[0];
817
  if (!d.getElementById(id)) {
823
  }(document, "script", "twitter-wjs");</script>
824
  </p>
825
  <?php
826
+ if ( 'premium' == $context ) {
827
  $support_url = admin_url( 'admin.php?page=wp-tweets-pro' );
828
+ $support = '<a href="' . esc_url( add_query_arg( 'tab', 'support', $support_url ) ) . '#get-support">' . __( 'Get Support', 'wp-to-twitter' ) . '</a> &bull;';
829
  } else {
830
  $support_url = false;
831
+ $support = '';
832
+ }
833
  echo $support;
834
  ?>
835
  <a href="https://www.joedolson.com/wp-content/uploads/wp-tweets-pro-users-guide-current.pdf"><?php _e( 'Read the Manual', 'wp-to-twitter' ); ?></a>
836
  </div>
837
  </div>
838
  </div>
839
+
840
  <div class="ui-sortable meta-box-sortables">
841
  <div class="postbox">
842
+ <?php
843
+ $admin_url = admin_url( 'admin.php?page=wp-tweets-pro&amp;refresh_wpt_server_string=true' );
844
+ $link = "<a href='" . $admin_url . "'>" . __( 'Test again', 'wp-to-twitter' ) . '</a>';
845
+ ?>
846
+ <h3><?php _e( 'Twitter Time Check', 'wp-to-twitter' ); ?> &bull; <?php echo $link; ?></h3>
847
 
848
  <div class="inside server">
849
+ <?php wpt_do_server_check(); ?>
850
  </div>
851
  </div>
852
  </div>
853
+
854
  <div class="ui-sortable meta-box-sortables">
855
  <div class="postbox">
856
  <h3><?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?></h3>
857
+
858
  <div class="inside test">
859
  <p>
860
+ <?php _e( 'Check whether WP to Twitter is setup correctly for Twitter and your URL Shortener. The test sends a status update to Twitter and shortens a URL using your chosen shortener.', 'wp-to-twitter' ); ?>
861
  </p>
862
  <form method="post" action="">
863
  <input type="hidden" name="submit-type" value="check-support"/>
864
+ <?php
865
+ $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
866
+ echo "<div>$nonce</div>";
867
+ ?>
868
  <p>
869
+ <input type="submit" name="submit" value="<?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?>" class="button-secondary" />
870
  </p>
871
+ </form>
872
  </div>
873
  </div>
874
  </div>
875
 
876
+ <?php
877
+ if ( 1 == get_option( 'wpt_rate_limiting' ) ) {
878
+ ?>
879
  <div class="ui-sortable meta-box-sortables">
880
  <div class="postbox">
881
  <h3><?php _e( 'Monitor Rate Limiting', 'wp-to-twitter' ); ?></h3>
882
 
883
+ <div class="inside server">
884
  <?php echo wpt_view_rate_limits(); ?>
885
  </div>
886
  </div>
887
+ </div>
888
+ <?php
889
+ }
890
+ ?>
891
  </div>
892
  <?php
893
  }
894
 
895
+ /**
896
+ * Compare your server time to Twitter's time.
897
+ *
898
+ * @param boolean $test Doing a test.
899
+ */
900
  function wpt_do_server_check( $test = false ) {
901
  $wpt_server_string = get_option( 'wpt_server_string' );
902
+ if ( ! $wpt_server_string || isset( $_GET['refresh_wpt_server_string'] ) || true == $test ) {
903
  $server_time = date( DATE_COOKIE );
904
+ $response = wp_remote_get( 'https://twitter.com/', array(
905
+ 'timeout' => 30,
906
+ 'redirection' => 1,
907
+ ) );
908
+
909
  if ( is_wp_error( $response ) ) {
910
  $warning = '';
911
  $error = $response->errors;
912
  if ( is_array( $error ) ) {
913
+ $warning = '<ul>';
914
  foreach ( $error as $k => $e ) {
915
  foreach ( $e as $v ) {
916
+ $warning .= '<li>' . $v . '</li>';
917
  }
918
  }
919
+ $warning .= '</ul>';
920
  }
921
+ $errors = '<li>' . $ssl . $warning . '</li>';
922
  } else {
923
  $date = date( DATE_COOKIE, strtotime( $response['headers']['date'] ) );
924
  $errors = '';
932
  }
933
  $diff = "<li>$diff</li>";
934
  } else {
935
+ $diff = '<li>' . __( 'WP to Twitter could not contact Twitter\'s remote server.', 'wp-to-twitter' ) . '</li>';
936
  }
937
 
938
  $timezone = '<li>' . __( 'Your server timezone:', 'wp-to-twitter' ) . ' ' . date_default_timezone_get() . '</li>';
939
 
940
+ $search = array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' );
941
  $replace = array( 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun' );
942
+
943
  $server_time = str_replace( $search, $replace, $server_time );
944
+ $date = str_replace( $search, $replace, $date );
945
+
946
  $wpt_server_string =
947
+ '<ul>
948
+ <li>' . __( 'Your server time:', 'wp-to-twitter' ) . '<br /><code>' . $server_time . '</code>' . '</li>' .
949
+ '<li>' . __( 'Twitter\'s server time: ', 'wp-to-twitter' ) . '<br /><code>' . $date . '</code>' . "</li>
950
  $timezone
951
  $diff
952
  $errors
954
  update_option( 'wpt_server_string', $wpt_server_string );
955
  }
956
  echo $wpt_server_string;
 
 
 
957
  }
958
 
959
  add_filter( 'wpt_tweet_length', 'wpt_tweet_length' );
960
+ /**
961
+ * Add control to set maximum length for a Tweet.
962
+ *
963
+ * @return string HTML control.
964
+ */
965
  function wpt_tweet_length() {
966
  $tweet_length = intval( ( get_option( 'wpt_tweet_length' ) ) ? get_option( 'wpt_tweet_length' ) : 140 );
967
+ $control = "<p class='tweet_length_control'>
968
  <label for='wpt_tweet_length'>" . __( 'Tweet Length (max 280 characters)', 'wp-to-twitter' ) . "</label>
969
+ <input type='number' min='0' max='280' step='1' value='$tweet_length' id='wpt_tweet_length' name='wpt_tweet_length' />
970
+ <a href='https://www.joedolson.com/2017/11/twitter-expands-280-characters-sort/'>" . __( 'About this setting', 'wp-to-twitter' ) . '</a>
971
+ </p>';
972
+
973
  return $control;
974
  }
975
 
976
  add_filter( 'wpt_settings', 'wpt_set_tweet_length' );
977
+ /**
978
+ * Set the maximum length for a Tweet.
979
+ */
980
  function wpt_set_tweet_length() {
981
  if ( isset( $_POST['wpt_tweet_length'] ) ) {
982
  update_option( 'wpt_tweet_length', intval( $_POST['wpt_tweet_length'] ) );
983
  }
984
+ }
wp-to-twitter-oauth.php CHANGED
@@ -1,15 +1,32 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
5
 
6
- // function to test credentials
 
 
 
 
 
 
 
7
  function wtt_oauth_test( $auth = false, $context = '' ) {
8
  if ( ! $auth ) {
9
  return ( wtt_oauth_credentials_to_hash() == get_option( 'wtt_oauth_hash' ) );
10
  } else {
11
  $return = ( wtt_oauth_credentials_to_hash( $auth ) == wpt_get_user_verification( $auth ) );
12
- if ( ! $return && $context != 'verify' ) {
13
  return ( wtt_oauth_credentials_to_hash() == get_option( 'wtt_oauth_hash' ) );
14
  } else {
15
  return $return;
@@ -17,6 +34,13 @@ function wtt_oauth_test( $auth = false, $context = '' ) {
17
  }
18
  }
19
 
 
 
 
 
 
 
 
20
  function wpt_get_user_verification( $auth ) {
21
  if ( get_option( 'jd_individual_twitter_users' ) != '1' ) {
22
  return false;
@@ -27,8 +51,14 @@ function wpt_get_user_verification( $auth ) {
27
  }
28
  }
29
 
30
- // function to make connection
31
- function wtt_oauth_connection( $auth = false ) {
 
 
 
 
 
 
32
  if ( ! $auth ) {
33
  $ack = get_option( 'app_consumer_key' );
34
  $acs = get_option( 'app_consumer_secret' );
@@ -41,8 +71,8 @@ function wtt_oauth_connection( $auth = false ) {
41
  $ots = get_user_meta( $auth, 'oauth_token_secret', true );
42
  }
43
  if ( ! empty( $ack ) && ! empty( $acs ) && ! empty( $ot ) && ! empty( $ots ) ) {
44
- require_once( plugin_dir_path( __FILE__ ) . 'wpt_twitter_oauth.php' );
45
- $connection = new wpt_TwitterOAuth( $ack, $acs, $ot, $ots );
46
  $connection->useragent = get_option( 'blogname' ) . ' ' . home_url();
47
 
48
  return $connection;
@@ -51,7 +81,13 @@ function wtt_oauth_connection( $auth = false ) {
51
  }
52
  }
53
 
54
- // convert credentials to md5 hash
 
 
 
 
 
 
55
  function wtt_oauth_credentials_to_hash( $auth = false ) {
56
  if ( ! $auth ) {
57
  $hash = md5( get_option( 'app_consumer_key' ) . get_option( 'app_consumer_secret' ) . get_option( 'oauth_token' ) . get_option( 'oauth_token_secret' ) );
@@ -63,13 +99,11 @@ function wtt_oauth_credentials_to_hash( $auth = false ) {
63
  }
64
 
65
  /**
66
- * Back compat
 
 
 
67
  */
68
- function jd_update_oauth_settings( $auth = false, $post = false ) {
69
- return wpt_update_oauth_settings( $auth, $post );
70
- }
71
-
72
- // response to settings updates
73
  function wpt_update_oauth_settings( $auth = false, $post = false ) {
74
  if ( isset( $post['oauth_settings'] ) ) {
75
  switch ( $post['oauth_settings'] ) {
@@ -78,9 +112,9 @@ function wpt_update_oauth_settings( $auth = false, $post = false ) {
78
  wp_die( 'Oops, please try again.' );
79
  }
80
  if ( ! empty( $post['wtt_app_consumer_key'] )
81
- && ! empty( $post['wtt_app_consumer_secret'] )
82
- && ! empty( $post['wtt_oauth_token'] )
83
- && ! empty( $post['wtt_oauth_token_secret'] )
84
  ) {
85
  $ack = trim( $post['wtt_app_consumer_key'] );
86
  $acs = trim( $post['wtt_app_consumer_secret'] );
@@ -98,17 +132,17 @@ function wpt_update_oauth_settings( $auth = false, $post = false ) {
98
  update_user_meta( $auth, 'oauth_token_secret', $ots );
99
  }
100
  $message = 'failed';
101
- if ( $connection = wtt_oauth_connection( $auth ) ) {
102
  $data = $connection->get( 'https://api.twitter.com/1.1/account/verify_credentials.json' );
103
- if ( $connection->http_code != '200' ) {
104
  $data = json_decode( $data );
105
- $code = "<a href='https://dev.twitter.com/docs/error-codes-responses'>" . $data->errors[0]->code . "</a>";
106
  $error = $data->errors[0]->message;
107
  update_option( 'wpt_error', "$code: $error" );
108
  } else {
109
  delete_option( 'wpt_error' );
110
  }
111
- if ( $connection->http_code == '200' ) {
112
  $error_information = '';
113
  $decode = json_decode( $data );
114
  if ( ! $auth ) {
@@ -124,32 +158,33 @@ function wpt_update_oauth_settings( $auth = false, $post = false ) {
124
  }
125
  $message = 'success';
126
  delete_option( 'wpt_curl_error' );
127
- } else if ( $connection->http_code == 0 ) {
128
- $error_information = __( "WP to Twitter was unable to establish a connection to Twitter.", 'wp-to-twitter' );
129
  update_option( 'wpt_curl_error', "$error_information" );
130
  } else {
131
- $status = ( isset( $connection->http_header['status'] ) ) ? $connection->http_header['status'] : '404';
132
  $error_information = array(
133
- "http_code" => $connection->http_code,
134
- "status" => $status
135
  );
136
- $error_code = sprintf( __( "Twitter response: http_code %s", 'wp-to-twitter' ), "$error_information[http_code] - $error_information[status]" );
 
137
  update_option( 'wpt_curl_error', $error_code );
138
  }
139
- if ( get_option( 'wp_debug_oauth' ) == '1' ) {
140
- echo "<pre><strong>Summary Connection Response:</strong><br />";
141
  print_r( $error_information );
142
- echo "<br /><strong>Account Verification Data:</strong><br />";
143
  print_r( $data );
144
- echo "<br /><strong>Full Connection Response:</strong><br />";
145
  print_r( $connection );
146
- echo "</pre>";
147
  }
148
  }
149
  } else {
150
- $message = "nodata";
151
  }
152
- if ( $message == 'failed' && ( time() < strtotime( $connection->http_header['date'] ) - 300 || time() > strtotime( $connection->http_header['date'] ) + 300 ) ) {
153
  $message = 'nosync';
154
  }
155
 
@@ -172,7 +207,7 @@ function wpt_update_oauth_settings( $auth = false, $post = false ) {
172
  delete_user_meta( $auth, 'oauth_token_secret' );
173
  delete_user_meta( $auth, 'wtt_twitter_username' );
174
  }
175
- $message = "cleared";
176
 
177
  return $message;
178
  break;
@@ -182,7 +217,11 @@ function wpt_update_oauth_settings( $auth = false, $post = false ) {
182
  return '';
183
  }
184
 
185
- // connect or disconnect form
 
 
 
 
186
  function wtt_connect_oauth( $auth = false ) {
187
  if ( ! $auth ) {
188
  echo '<div class="ui-sortable meta-box-sortables">';
@@ -192,7 +231,7 @@ function wtt_connect_oauth( $auth = false ) {
192
  if ( $auth ) {
193
  wpt_update_authenticated_users();
194
  }
195
-
196
  $class = ( $auth ) ? 'wpt-profile' : 'wpt-settings';
197
  $form = ( ! $auth ) ? '<form action="" method="post">' : '';
198
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
@@ -202,7 +241,8 @@ function wtt_connect_oauth( $auth = false ) {
202
  // show notification to authenticate with OAuth. No longer global; settings only.
203
  if ( ! wpt_check_oauth() ) {
204
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
205
- $message = sprintf( __( "Twitter requires authentication by OAuth. You will need to <a href='%s'>update your settings</a> to complete installation of WP to Twitter.", 'wp-to-twitter' ), $admin_url );
 
206
  echo "<div class='error'><p>$message</p></div>";
207
  }
208
 
@@ -237,7 +277,7 @@ function wtt_connect_oauth( $auth = false ) {
237
  <li>' . __( 'Copy your Access token and Access token secret from the "Your Access Token" section.', 'wp-to-twitter' ) . '</li>
238
  </ul>
239
  ' . $form . '
240
- <fieldset class="options">
241
  <div class="tokens">
242
  <p>
243
  <label for="wtt_app_consumer_key">' . __( 'API Key', 'wp-to-twitter' ) . '</label>
@@ -264,21 +304,19 @@ function wtt_connect_oauth( $auth = false ) {
264
  ' . $submit . '
265
  <input type="hidden" name="oauth_settings" value="wtt_oauth_test" class="hidden" style="display: none;" />
266
  ' . $nonce . '
267
- </div>
268
  ' );
269
- } else if ( wtt_oauth_test( $auth ) ) {
270
  $ack = ( ! $auth ) ? get_option( 'app_consumer_key' ) : get_user_meta( $auth, 'app_consumer_key', true );
271
  $acs = ( ! $auth ) ? get_option( 'app_consumer_secret' ) : get_user_meta( $auth, 'app_consumer_secret', true );
272
  $ot = ( ! $auth ) ? get_option( 'oauth_token' ) : get_user_meta( $auth, 'oauth_token', true );
273
  $ots = ( ! $auth ) ? get_option( 'oauth_token_secret' ) : get_user_meta( $auth, 'oauth_token_secret', true );
274
  $uname = ( ! $auth ) ? get_option( 'wtt_twitter_username' ) : get_user_meta( $auth, 'wtt_twitter_username', true );
275
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
276
- if ( ! $auth ) {
277
- $submit = '
278
- <input type="submit" name="submit" class="button-primary" value="' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '" />
279
- <input type="hidden" name="oauth_settings" value="wtt_twitter_disconnect" class="hidden" />
280
- ';
281
- } else {
282
  $submit = '<input type="checkbox" name="oauth_settings" value="wtt_twitter_disconnect" id="disconnect" /> <label for="disconnect">' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '</label>';
283
  }
284
 
@@ -299,30 +337,44 @@ function wtt_connect_oauth( $auth = false ) {
299
  <div>
300
  ' . $submit . '
301
  </div>
302
- </div>
303
  ' . $nonce . '
304
  </div>' );
305
 
306
  }
307
  if ( ! $auth ) {
308
- echo "</div>";
309
- echo "</div>";
310
  }
311
  }
312
 
 
 
 
313
  function wpt_update_authenticated_users() {
314
- $args = array( 'meta_query' => array( array( 'key' => 'wtt_twitter_username', 'compare' => 'EXISTS' ) ) );
315
- // get all authorized users
316
- $users = get_users( $args );
 
 
 
 
 
 
 
317
  $authorized_users = array();
318
  if ( is_array( $users ) ) {
319
  foreach ( $users as $this_user ) {
320
- if ( wtt_oauth_test( $this_user->ID,'verify' ) ) {
321
- $twitter = get_user_meta( $this_user->ID, 'wtt_twitter_username', true );
322
- $authorized_users[] = array( 'ID'=>$this_user->ID, 'name'=>$this_user->display_name, 'twitter'=>$twitter );
 
 
 
 
323
  }
324
  }
325
  }
326
-
327
- update_option( 'wpt_authorized_users', $authorized_users );
328
- }
1
  <?php
2
+ /**
3
+ * Connect OAuth for WP to Twitter
4
+ *
5
+ * @category OAuth
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
+ /**
17
+ * Function to test validity of credentials
18
+ *
19
+ * @param mixed int/boolean $auth Current author.
20
+ * @param string $context Use context.
21
+ *
22
+ * @return Is authenticated.
23
+ */
24
  function wtt_oauth_test( $auth = false, $context = '' ) {
25
  if ( ! $auth ) {
26
  return ( wtt_oauth_credentials_to_hash() == get_option( 'wtt_oauth_hash' ) );
27
  } else {
28
  $return = ( wtt_oauth_credentials_to_hash( $auth ) == wpt_get_user_verification( $auth ) );
29
+ if ( ! $return && 'verify' != $context ) {
30
  return ( wtt_oauth_credentials_to_hash() == get_option( 'wtt_oauth_hash' ) );
31
  } else {
32
  return $return;
34
  }
35
  }
36
 
37
+ /**
38
+ * Get user verification hash.
39
+ *
40
+ * @param mixed int $auth Current author.
41
+ *
42
+ * @return author hash.
43
+ */
44
  function wpt_get_user_verification( $auth ) {
45
  if ( get_option( 'jd_individual_twitter_users' ) != '1' ) {
46
  return false;
51
  }
52
  }
53
 
54
+ /**
55
+ * Establish an OAuth connection to Twitter.
56
+ *
57
+ * @param mixed int/boolean $auth Current author.
58
+ *
59
+ * @return mixed $connection or false
60
+ */
61
+ function wpt_oauth_connection( $auth = false ) {
62
  if ( ! $auth ) {
63
  $ack = get_option( 'app_consumer_key' );
64
  $acs = get_option( 'app_consumer_secret' );
71
  $ots = get_user_meta( $auth, 'oauth_token_secret', true );
72
  }
73
  if ( ! empty( $ack ) && ! empty( $acs ) && ! empty( $ot ) && ! empty( $ots ) ) {
74
+ require_once( plugin_dir_path( __FILE__ ) . 'classes/class-wpt-twitteroauth.php' );
75
+ $connection = new Wpt_TwitterOAuth( $ack, $acs, $ot, $ots );
76
  $connection->useragent = get_option( 'blogname' ) . ' ' . home_url();
77
 
78
  return $connection;
81
  }
82
  }
83
 
84
+ /**
85
+ * Convert oauth credentials to hash value for storage.
86
+ *
87
+ * @param mixed int/boolean $auth Author.
88
+ *
89
+ * @return hash.
90
+ */
91
  function wtt_oauth_credentials_to_hash( $auth = false ) {
92
  if ( ! $auth ) {
93
  $hash = md5( get_option( 'app_consumer_key' ) . get_option( 'app_consumer_secret' ) . get_option( 'oauth_token' ) . get_option( 'oauth_token_secret' ) );
99
  }
100
 
101
  /**
102
+ * Update OAuth settings.
103
+ *
104
+ * @param mixed int/boolean $auth Author.
105
+ * @param mixed array/boolean $post POST data.
106
  */
 
 
 
 
 
107
  function wpt_update_oauth_settings( $auth = false, $post = false ) {
108
  if ( isset( $post['oauth_settings'] ) ) {
109
  switch ( $post['oauth_settings'] ) {
112
  wp_die( 'Oops, please try again.' );
113
  }
114
  if ( ! empty( $post['wtt_app_consumer_key'] )
115
+ && ! empty( $post['wtt_app_consumer_secret'] )
116
+ && ! empty( $post['wtt_oauth_token'] )
117
+ && ! empty( $post['wtt_oauth_token_secret'] )
118
  ) {
119
  $ack = trim( $post['wtt_app_consumer_key'] );
120
  $acs = trim( $post['wtt_app_consumer_secret'] );
132
  update_user_meta( $auth, 'oauth_token_secret', $ots );
133
  }
134
  $message = 'failed';
135
+ if ( wpt_oauth_connection( $auth ) == $connection ) {
136
  $data = $connection->get( 'https://api.twitter.com/1.1/account/verify_credentials.json' );
137
+ if ( '200' != $connection->http_code ) {
138
  $data = json_decode( $data );
139
+ $code = "<a href='https://dev.twitter.com/docs/error-codes-responses'>" . $data->errors[0]->code . '</a>';
140
  $error = $data->errors[0]->message;
141
  update_option( 'wpt_error', "$code: $error" );
142
  } else {
143
  delete_option( 'wpt_error' );
144
  }
145
+ if ( '200' == $connection->http_code ) {
146
  $error_information = '';
147
  $decode = json_decode( $data );
148
  if ( ! $auth ) {
158
  }
159
  $message = 'success';
160
  delete_option( 'wpt_curl_error' );
161
+ } elseif ( 0 == $connection->http_code ) {
162
+ $error_information = __( 'WP to Twitter was unable to establish a connection to Twitter.', 'wp-to-twitter' );
163
  update_option( 'wpt_curl_error', "$error_information" );
164
  } else {
165
+ $status = ( isset( $connection->http_header['status'] ) ) ? $connection->http_header['status'] : '404';
166
  $error_information = array(
167
+ 'http_code' => $connection->http_code,
168
+ 'status' => $status,
169
  );
170
+ // Translators: HTTP code & status message from Twitter.
171
+ $error_code = sprintf( __( 'Twitter response: http_code %s', 'wp-to-twitter' ), "$error_information[http_code] - $error_information[status]" );
172
  update_option( 'wpt_curl_error', $error_code );
173
  }
174
+ if ( '1' == get_option( 'wp_debug_oauth' ) ) {
175
+ echo '<pre><strong>Summary Connection Response:</strong><br />';
176
  print_r( $error_information );
177
+ echo '<br /><strong>Account Verification Data:</strong><br />';
178
  print_r( $data );
179
+ echo '<br /><strong>Full Connection Response:</strong><br />';
180
  print_r( $connection );
181
+ echo '</pre>';
182
  }
183
  }
184
  } else {
185
+ $message = 'nodata';
186
  }
187
+ if ( 'failed' == $message && ( time() < strtotime( $connection->http_header['date'] ) - 300 || time() > strtotime( $connection->http_header['date'] ) + 300 ) ) {
188
  $message = 'nosync';
189
  }
190
 
207
  delete_user_meta( $auth, 'oauth_token_secret' );
208
  delete_user_meta( $auth, 'wtt_twitter_username' );
209
  }
210
+ $message = 'cleared';
211
 
212
  return $message;
213
  break;
217
  return '';
218
  }
219
 
220
+ /**
221
+ * Connect or disconnect from OAuth form.
222
+ *
223
+ * @param mixed int/boolean $auth Current author.
224
+ */
225
  function wtt_connect_oauth( $auth = false ) {
226
  if ( ! $auth ) {
227
  echo '<div class="ui-sortable meta-box-sortables">';
231
  if ( $auth ) {
232
  wpt_update_authenticated_users();
233
  }
234
+
235
  $class = ( $auth ) ? 'wpt-profile' : 'wpt-settings';
236
  $form = ( ! $auth ) ? '<form action="" method="post">' : '';
237
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
241
  // show notification to authenticate with OAuth. No longer global; settings only.
242
  if ( ! wpt_check_oauth() ) {
243
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
244
+ // Translators: Settings page to authenticate via OAuth.
245
+ $message = sprintf( __( "Twitter requires authentication by OAuth. You will need to <a href='%s'>update your settings</a> to complete installation of WP to Twitter.", 'wp-to-twitter' ), $admin_url );
246
  echo "<div class='error'><p>$message</p></div>";
247
  }
248
 
277
  <li>' . __( 'Copy your Access token and Access token secret from the "Your Access Token" section.', 'wp-to-twitter' ) . '</li>
278
  </ul>
279
  ' . $form . '
280
+ <fieldset class="options">
281
  <div class="tokens">
282
  <p>
283
  <label for="wtt_app_consumer_key">' . __( 'API Key', 'wp-to-twitter' ) . '</label>
304
  ' . $submit . '
305
  <input type="hidden" name="oauth_settings" value="wtt_oauth_test" class="hidden" style="display: none;" />
306
  ' . $nonce . '
307
+ </div>
308
  ' );
309
+ } elseif ( wtt_oauth_test( $auth ) ) {
310
  $ack = ( ! $auth ) ? get_option( 'app_consumer_key' ) : get_user_meta( $auth, 'app_consumer_key', true );
311
  $acs = ( ! $auth ) ? get_option( 'app_consumer_secret' ) : get_user_meta( $auth, 'app_consumer_secret', true );
312
  $ot = ( ! $auth ) ? get_option( 'oauth_token' ) : get_user_meta( $auth, 'oauth_token', true );
313
  $ots = ( ! $auth ) ? get_option( 'oauth_token_secret' ) : get_user_meta( $auth, 'oauth_token_secret', true );
314
  $uname = ( ! $auth ) ? get_option( 'wtt_twitter_username' ) : get_user_meta( $auth, 'wtt_twitter_username', true );
315
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
316
+ if ( ! $auth ) {
317
+ $submit = '<input type="submit" name="submit" class="button-primary" value="' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '" />
318
+ <input type="hidden" name="oauth_settings" value="wtt_twitter_disconnect" class="hidden" />';
319
+ } else {
 
 
320
  $submit = '<input type="checkbox" name="oauth_settings" value="wtt_twitter_disconnect" id="disconnect" /> <label for="disconnect">' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '</label>';
321
  }
322
 
337
  <div>
338
  ' . $submit . '
339
  </div>
340
+ </div>
341
  ' . $nonce . '
342
  </div>' );
343
 
344
  }
345
  if ( ! $auth ) {
346
+ echo '</div>
347
+ </div>';
348
  }
349
  }
350
 
351
+ /**
352
+ * Update stored set of authenticated users.
353
+ */
354
  function wpt_update_authenticated_users() {
355
+ $args = array(
356
+ 'meta_query' => array(
357
+ array(
358
+ 'key' => 'wtt_twitter_username',
359
+ 'compare' => 'EXISTS',
360
+ ),
361
+ ),
362
+ );
363
+ // get all authorized users.
364
+ $users = get_users( $args );
365
  $authorized_users = array();
366
  if ( is_array( $users ) ) {
367
  foreach ( $users as $this_user ) {
368
+ if ( wtt_oauth_test( $this_user->ID, 'verify' ) ) {
369
+ $twitter = get_user_meta( $this_user->ID, 'wtt_twitter_username', true );
370
+ $authorized_users[] = array(
371
+ 'ID' => $this_user->ID,
372
+ 'name' => $this_user->display_name,
373
+ 'twitter' => $twitter,
374
+ );
375
  }
376
  }
377
  }
378
+
379
+ update_option( 'wpt_authorized_users', $authorized_users );
380
+ }
wp-to-twitter-shorteners.php CHANGED
@@ -1,42 +1,63 @@
1
  <?php
 
 
 
 
 
 
 
 
 
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
  exit;
5
- } // Exit if accessed directly
6
 
7
- if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in replacement.
 
8
  add_filter( 'wptt_shorten_link', 'wpt_shorten_url', 10, 4 );
9
 
10
- function wpt_shorten_url( $url, $thisposttitle, $post_ID, $testmode = false, $store_urls = true ) {
11
- wpt_mail( "Initial Link", "$url, $thisposttitle, $post_ID, $testmode" ); // DEBUG
12
- // filter link before sending to shortener or adding analytics
 
 
 
 
 
 
 
 
 
 
 
13
  $shortener = get_option( 'jd_shortener' );
14
- // if the URL already exists, return it without processing
15
- if ( get_post_meta( $post_ID, '_wpt_short_url', true ) ) {
16
- $shrink = get_post_meta( $post_ID, '_wpt_short_url', true );
17
-
18
  return $shrink;
19
  }
20
  $url = apply_filters( 'wpt_shorten_link', $url, $shortener, $post_ID );
21
- if ( $testmode == false ) {
22
- if ( get_option( 'use-twitter-analytics' ) == 1 || get_option( 'use_dynamic_analytics' ) == 1 ) {
23
- if ( get_option( 'use_dynamic_analytics' ) == '1' ) {
24
  $campaign_type = get_option( 'jd_dynamic_analytics' );
25
- if ( $campaign_type == "post_category" && $testmode != 'link' ) {
26
  $category = get_the_category( $post_ID );
27
  $campaign = sanitize_title( $category[0]->cat_name );
28
- } else if ( $campaign_type == "post_ID" ) {
29
  $campaign = $post_ID;
30
- } else if ( $campaign_type == "post_title" && $testmode != 'link' ) {
31
  $post = get_post( $post_ID );
32
  $campaign = sanitize_title( $post->post_title );
33
  } else {
34
- if ( $testmode != 'link' ) {
35
  $post = get_post( $post_ID );
36
  $post_author = $post->post_author;
37
  $campaign = urlencode( get_the_author_meta( 'user_login', $post_author ) );
38
  } else {
39
- $campaign = '';
40
  }
41
  }
42
  } else {
@@ -44,37 +65,37 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
44
  }
45
  $medium = urlencode( trim( apply_filters( 'wpt_utm_medium', 'twitter' ) ) );
46
  $source = urlencode( trim( apply_filters( 'wpt_utm_source', 'twitter' ) ) );
47
- $url = add_query_arg( array(
48
- 'utm_campaign' => $campaign,
49
- 'utm_medium' => $medium,
50
- 'utm_source' => $source ), $url
51
- );
52
  }
53
- $url = urldecode( trim( $url ) ); // prevent double-encoding
54
  $encoded = urlencode( $url );
55
  } else {
56
- $url = urldecode( trim( $url ) ); // prevent double-encoding
57
  $encoded = urlencode( $url );
58
  }
59
 
60
- // custom word setting
61
- $keyword_format = ( get_option( 'jd_keyword_format' ) == '1' ) ? $post_ID : '';
62
- $keyword_format = ( get_option( 'jd_keyword_format' ) == '2' ) ? get_post_meta( $post_ID, '_yourls_keyword', true ) : $keyword_format;
63
- // Generate and grab the short url
64
- $shrink = apply_filters( 'wpt_do_shortening', false, $shortener, $url, $thisposttitle, $post_ID, $testmode );
65
- // if an add-on has shortened the link, skip shortening
66
  $error = false;
67
- if ( !$shrink ) {
68
  switch ( $shortener ) {
69
- case 3: // no shortener
70
  $shrink = $url;
71
  break;
72
- case 2: // updated to v3 3/31/2010
73
  $bitlyapi = trim( get_option( 'bitlyapi' ) );
74
  $bitlylogin = trim( strtolower( get_option( 'bitlylogin' ) ) );
75
- $decoded = wpt_remote_json( "https://api-ssl.bitly.com/v3/shorten?longUrl=" . $encoded . "&login=" . $bitlylogin . "&apiKey=" . $bitlyapi . "&format=json" );
76
  if ( $decoded && isset( $decoded['status_code'] ) ) {
77
- if ( $decoded['status_code'] != 200 ) {
78
  $shrink = $url;
79
  $error = $decoded['status_txt'];
80
  } else {
@@ -90,33 +111,26 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
90
  case 4:
91
  if ( function_exists( 'wp_get_shortlink' ) ) {
92
  // wp_get_shortlink doesn't natively support custom post types; but don't return an error in that case.
93
- $shrink = ( $post_ID != false ) ? wp_get_shortlink( $post_ID, 'post' ) : $url;
94
  }
95
  if ( ! $shrink ) {
96
  $shrink = $url;
97
  }
98
- break;
99
  case 5:
100
- // local YOURLS installation
101
- global $yourls_reserved_URL;
102
- define( 'YOURLS_INSTALLING', true ); // Pretend we're installing YOURLS to bypass test for install or upgrade
103
- define( 'YOURLS_FLOOD_DELAY_SECONDS', 0 ); // Disable flood check
104
  $opath = get_option( 'yourlspath' );
105
  $ypath = str_replace( 'user', 'includes', $opath );
106
- if ( file_exists( dirname( $ypath ) . '/load-yourls.php' ) ) { // YOURLS 1.4+
107
  require_once( dirname( $ypath ) . '/load-yourls.php' );
108
  global $ydb;
109
  if ( function_exists( 'yourls_add_new_link' ) ) {
110
- $yourls_result = yourls_add_new_link( $url, $keyword_format, $thisposttitle );
111
  } else {
112
  $yourls_result = $url;
113
  }
114
- } else { // YOURLS 1.3
115
- if ( file_exists( get_option( 'yourslpath' ) ) ) {
116
- require_once( get_option( 'yourlspath' ) );
117
- $yourls_db = new wpdb( YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST );
118
- $yourls_result = yourls_add_new_link( $url, $keyword_format, $yourls_db );
119
- }
120
  }
121
  if ( $yourls_result ) {
122
  $shrink = $yourls_result['shorturl'];
@@ -125,7 +139,7 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
125
  }
126
  break;
127
  case 6:
128
- // remote YOURLS installation
129
  $yourlslogin = trim( get_option( 'yourlslogin' ) );
130
  $yourlsapi = stripcslashes( get_option( 'yourlsapi' ) );
131
  $token = stripcslashes( get_option( 'yourlstoken' ) );
@@ -135,8 +149,8 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
135
  'signature' => $token,
136
  'url' => $encoded,
137
  'action' => 'shorturl',
138
- 'format' => 'json',
139
- 'title' => urlencode( $thisposttitle )
140
  );
141
  } else {
142
  $args = array(
@@ -144,36 +158,36 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
144
  'password' => $yourlsapi,
145
  'url' => $encoded,
146
  'action' => 'shorturl',
147
- 'format' => 'json',
148
- 'title' => urlencode( $thisposttitle )
149
  );
150
  }
151
  if ( $keyword_format ) {
152
  $args['keyword'] = $keyword_format;
153
  }
154
-
155
  $api_url = add_query_arg( $args, $yourlsurl );
156
-
157
  $json = wpt_remote_json( $api_url, false );
158
- wpt_mail( "YOURLS JSON Response", print_r( $json, 1 ) ); // DEBUG YOURLS response
159
  if ( is_object( $json ) ) {
160
  $shrink = $json->shorturl;
161
  } else {
162
- $error = "Error code: " . $json->shorturl . ' ' . $json->message;
163
  $shrink = false;
164
  }
165
  break;
166
  case 7:
167
  $suprapi = trim( get_option( 'suprapi' ) );
168
  $suprlogin = trim( get_option( 'suprlogin' ) );
169
- if ( $suprapi != '' ) {
170
- $decoded = wpt_remote_json( "http://su.pr/api/shorten?longUrl=" . $encoded . "&login=" . $suprlogin . "&apiKey=" . $suprapi );
171
  } else {
172
- $decoded = wpt_remote_json( "http://su.pr/api/shorten?longUrl=" . $encoded );
173
  }
174
  if ( $decoded && isset( $decoded['statusCode'] ) ) {
175
- if ( $decoded['statusCode'] == 'OK' ) {
176
- $page = str_replace( "&", "&#38;", urldecode( $url ) );
177
  $shrink = $decoded['results'][ $page ]['shortUrl'];
178
  $error = $decoded['errorMessage'];
179
  } else {
@@ -189,53 +203,47 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
189
  }
190
  break;
191
  case 8:
192
- // Goo.gl
193
- $googl_api_key = ( get_option( 'googl_api_key' ) == '' ) ? 'AIzaSyBSnqQOg3vX1gwR7y2l-40yEG9SZiaYPUQ' : get_option( 'googl_api_key' );
194
- $target = "https://www.googleapis.com/urlshortener/v1/url?key=$googl_api_key";
195
- $body = "{'longUrl':'$url'}";
196
- $json = wpt_fetch_url( $target, 'POST', $body, 'Content-Type: application/json' );
197
- $decoded = json_decode( $json );
198
- $shrink = $decoded->id;
199
  if ( ! wpt_is_valid_url( $shrink ) ) {
200
  $shrink = false;
201
  }
202
  break;
203
  case 9:
204
- // Twitter Friendly Links
205
  $shrink = $url;
206
- if ( function_exists( 'twitter_link' ) ) { // use twitter_link if available
207
- $shrink = twitter_link( $post_ID );
208
- }
209
  break;
210
- case 10: // jotURL
211
- //jotURL, added: 2013-04-10
212
  $joturlapi = trim( get_option( 'joturlapi' ) );
213
  $joturllogin = trim( get_option( 'joturllogin' ) );
214
  $joturl_longurl_params = trim( get_option( 'joturl_longurl_params' ) );
215
- if ( $joturl_longurl_params != '' ) {
216
- if ( strpos( $url, "%3F" ) === false && strpos( $url, "?" ) === false ) {
217
- $ct = "?";
218
  } else {
219
- $ct = "&";
220
  }
221
- $url .= $ct . $joturl_longurl_params;
222
- $encoded = urlencode( urldecode( trim( $url ) ) ); // prevent double-encoding
223
  }
224
- //\jotURL
225
- $decoded = wpt_fetch_url( "https://api.joturl.com/a/v1/shorten?url=" . $encoded . "&login=" . $joturllogin . "&key=" . $joturlapi . "&format=plain" );
226
- if ( $decoded !== false ) {
227
- $shrink = $decoded;
228
- //jotURL, added: 2013-04-10
229
  $joturl_shorturl_params = trim( get_option( 'joturl_shorturl_params' ) );
230
- if ( $joturl_shorturl_params != '' ) {
231
- if ( strpos( $shrink, "%3F" ) === false && strpos( $shrink, "?" ) === false ) {
232
- $ct = "?";
233
  } else {
234
- $ct = "&";
235
  }
236
  $shrink .= $ct . $joturl_shorturl_params;
237
  }
238
- //\jotURL
239
  } else {
240
  $error = $decoded;
241
  $shrink = false;
@@ -244,14 +252,15 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
244
  $shrink = false;
245
  }
246
  break;
247
- default: $shrink = $url;
 
248
  }
249
  }
250
  if ( $error ) {
251
  update_option( 'wpt_shortener_status', "$shrink : $error" );
252
  }
253
  if ( ! $testmode ) {
254
- if ( $shrink === false || ( filter_var( $shrink, FILTER_VALIDATE_URL ) === false ) ) {
255
  update_option( 'wp_url_failure', '1' );
256
  $shrink = urldecode( $url );
257
  } else {
@@ -265,22 +274,21 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
265
 
266
  return $shrink;
267
  }
268
-
 
 
 
 
 
 
269
  function wpt_store_url( $post_ID, $url ) {
270
  $store_urls = apply_filters( 'wpt_store_urls', true, $post_ID, $url );
271
- if ( function_exists( 'wpt_shorten_url' ) && $store_urls ) {
272
  $shortener = get_option( 'jd_shortener' );
273
- if ( get_post_meta( $post_ID, '_wpt_short_url', true ) != $url && wpt_is_valid_url( $url ) ) {
274
  update_post_meta( $post_ID, '_wpt_short_url', $url );
275
  }
276
  switch ( $shortener ) {
277
- case 0:
278
- case 1:
279
- case 2:
280
- case 7:
281
- case 8:
282
- $target = wpt_expand_url( $url );
283
- break;
284
  case 5:
285
  case 6:
286
  $target = wpt_expand_yourl( $url, $shortener );
@@ -293,28 +301,21 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
293
  }
294
  update_post_meta( $post_ID, '_wp_jd_target', $target );
295
  }
296
-
297
- function jd_expand_url( $short_url ) {
298
- return wpt_expand_url( $short_url );
299
- }
300
-
301
- /**
302
- * LongUrl.org was taken off line; this no longer works.
 
303
  */
304
- function wpt_expand_url( $short_url ) {
305
- return $short_url;
306
- }
307
-
308
- function jd_expand_yourl( $short_url, $remote ) {
309
- return wpt_expand_yourl( $short_url, $remote );
310
- }
311
-
312
  function wpt_expand_yourl( $short_url, $remote ) {
313
- if ( $remote == 6 ) {
314
  $short_url = urlencode( $short_url );
315
  $yourl_api = get_option( 'yourlsurl' );
316
  $user = get_option( 'yourlslogin' );
317
- $pass = stripcslashes( get_option( 'yourlsapi' ) );
318
  $token = get_option( 'yourlstoken' );
319
  if ( $token ) {
320
  $decoded = wpt_remote_json( $yourl_api . "?action=expand&shorturl=$short_url&format=json&signature=$token&username=$user&password=$pass" );
@@ -325,19 +326,12 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
325
 
326
  return $url;
327
  } else {
328
- global $yourls_reserved_URL;
329
- define( 'YOURLS_INSTALLING', true ); // Pretend we're installing YOURLS to bypass test for install or upgrade
330
- define( 'YOURLS_FLOOD_DELAY_SECONDS', 0 ); // Disable flood check
331
- if ( file_exists( dirname( get_option( 'yourlspath' ) ) . '/load-yourls.php' ) ) { // YOURLS 1.4+
332
  global $ydb;
333
  require_once( dirname( get_option( 'yourlspath' ) ) . '/load-yourls.php' );
334
  $yourls_result = yourls_api_expand( $short_url );
335
- } else { // YOURLS 1.3
336
- if ( file_exists( get_option( 'yourlspath' ) ) ) {
337
- require_once( get_option( 'yourlspath' ) );
338
- $yourls_db = new wpdb( YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST );
339
- $yourls_result = yourls_api_expand( $short_url );
340
- }
341
  }
342
  if ( $yourls_result ) {
343
  $url = $yourls_result['longurl'];
@@ -349,21 +343,24 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
349
  }
350
 
351
  add_filter( 'wpt_shortener_controls', 'wpt_shortener_controls' );
 
 
 
352
  function wpt_shortener_controls() {
353
- $shortener = get_option( 'jd_shortener' );
354
- $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
355
  $form_start = '<div class="panel">
356
  <form method="post" action="' . add_query_arg( 'tab', 'shortener', $admin_url ) . '">
357
  <div><input type="hidden" name="wpt_shortener_update" value="true" /></div>
358
  <div>';
359
- $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false );
360
- $form_end = '<div>' . $nonce . '</div>
361
- <p>
362
- <input type="submit" name="submit" value="' . __( 'Save URL Shortener Settings', 'wp-to-twitter' ) . '" class="button-primary" />
363
- </p>
364
- </div>
365
- </form>
366
- </div>';
367
  // for the moment, this just displays the fields. Eventually, a real filter.
368
  ?>
369
  <div class="ui-sortable meta-box-sortables">
@@ -373,168 +370,157 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
373
  </h3>
374
 
375
  <div class="inside">
376
- <?php if ( $shortener == 7 ) { ?>
 
 
377
  <?php echo $form_start; ?>
378
  <p>
379
  <label
380
- for="suprlogin"><?php _e( "Your Su.pr Username:", 'wp-to-twitter' ); ?></label>
381
- <input type="text" name="suprlogin" id="suprlogin" size="40"
382
- value="<?php esc_attr_e( get_option( 'suprlogin' ) ) ?>"/>
383
  </p>
384
-
385
  <p>
386
  <label
387
  for="suprapi"><?php _e( "Your Su.pr <abbr title='application programming interface'>API</abbr> Key:", 'wp-to-twitter' ); ?></label>
388
- <input type="text" name="suprapi" id="suprapi" size="40"
389
- value="<?php esc_attr_e( get_option( 'suprapi' ) ) ?>"/>
390
  </p>
391
 
392
  <div>
393
  <input type="hidden" name="submit-type" value="suprapi"/>
394
  </div>
395
  <p><small><?php _e( "Don't have a Su.pr account or API key? <a href='http://su.pr/'>Get one here!</a> You'll need an API key in order to associate the URLs you create with your Su.pr account.", 'wp-to-twitter' ); ?></small></p>
396
- <?php echo $form_end; ?>
397
- <?php } else if ( $shortener == 2 ) { ?>
398
- <?php echo $form_start; ?>
 
 
399
  <p>
400
- <label
401
- for="bitlylogin"><?php _e( "Your Bit.ly username:", 'wp-to-twitter' ); ?></label>
402
- <input type="text" name="bitlylogin" id="bitlylogin"
403
- value="<?php esc_attr_e( get_option( 'bitlylogin' ) ) ?>"/>
404
  </p>
405
  <p>
406
- <label
407
- for="bitlyapi"><?php _e( "Your Bit.ly <abbr title='application programming interface'>API</abbr> Key:", 'wp-to-twitter' ); ?></label>
408
- <input type="text" name="bitlyapi" id="bitlyapi" size="40"
409
- value="<?php esc_attr_e( get_option( 'bitlyapi' ) ) ?>"/>
410
  </p>
411
-
412
  <p>
413
  <a href="http://bitly.com/a/your_api_key"><?php _e( 'View your Bit.ly username and API key', 'wp-to-twitter' ); ?></a>
414
  </p>
415
-
416
  <div>
417
  <input type="hidden" name="submit-type" value="bitlyapi"/>
418
  </div>
419
- <?php echo $form_end; ?>
420
- <?php } else if ( $shortener == 5 || $shortener == 6 ) { ?>
421
- <?php echo $form_start; ?>
422
- <?php if ( $shortener == 5 ) { ?>
 
 
423
  <p>
424
- <label
425
- for="yourlspath"><?php _e( 'Path to your YOURLS config file', 'wp-to-twitter' ); ?></label><br/><input
426
- type="text" id="yourlspath" name="yourlspath" size="60"
427
- value="<?php esc_attr_e( get_option( 'yourlspath' ) ); ?>"/><br/>
428
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>/home/username/www/www/yourls/user/config.php</code>
429
  </small>
430
  </p>
431
- <?php } ?>
432
- <?php if ( $shortener == 6 ) { ?>
 
 
433
  <p>
434
- <label
435
- for="yourlsurl"><?php _e( 'URI to the YOURLS API', 'wp-to-twitter' ); ?></label><br/><input
436
- type="text" id="yourlsurl" name="yourlsurl" size="60"
437
- value="<?php esc_attr_e( get_option( 'yourlsurl' ) ); ?>"/><br/>
438
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>http://domain.com/yourls-api.php</code>
439
  </small>
440
  </p>
441
- <?php } ?>
 
 
442
  <p>
443
- <label
444
- for="yourlstoken"><?php _e( "YOURLS signature token:", 'wp-to-twitter' ); ?></label>
445
- <input type="text" name="yourlstoken" id="yourlstoken" size="30"
446
- value="<?php esc_attr_e( get_option( 'yourlstoken' ) ) ?>"/>
447
  </p>
448
- <?php if ( get_option( 'yourlsapi' ) && get_option( 'yourlslogin' ) ) { ?>
 
 
449
  <p>
450
  <em><?php _e( 'Your YOURLS username and password are saved. If you add a signature token, that will be used for API calls and your username and password will be deleted from the database.', 'wp-to-twitter' ); ?></em>
451
  </p>
452
- <?php } ?>
 
 
453
  <p>
454
- <input type="radio" name="jd_keyword_format" id="jd_keyword_id"
455
- value="1" <?php echo jd_checkSelect( 'jd_keyword_format', 1, 'checkbox' ); ?> />
456
- <label
457
- for="jd_keyword_id"><?php _e( "Post ID for YOURLS url slug.", 'wp-to-twitter' ); ?></label><br/>
458
- <input type="radio" name="jd_keyword_format" id="jd_keyword"
459
- value="2" <?php echo jd_checkSelect( 'jd_keyword_format', 2, 'checkbox' ); ?> />
460
- <label
461
- for="jd_keyword"><?php _e( "Custom keyword for YOURLS url slug.", 'wp-to-twitter' ); ?></label><br/>
462
- <input type="radio" name="jd_keyword_format" id="jd_keyword_default"
463
- value="0" <?php echo jd_checkSelect( 'jd_keyword_format', 0, 'checkbox' ); ?> />
464
- <label
465
- for="jd_keyword_default"><?php _e( "Default: sequential URL numbering.", 'wp-to-twitter' ); ?></label>
466
  </p>
467
-
468
  <div>
469
  <input type="hidden" name="submit-type" value="yourlsapi" />
470
  </div>
471
- <?php echo $form_end; ?>
472
- <?php } else if ( $shortener == 8 ) { ?>
473
- <?php echo $form_start; ?>
 
 
 
474
  <p>
475
- <label for="googl_api_key"><?php _e( "Goo.gl API Key:", 'wp-to-twitter' ); ?></label>
476
- <input type="text" name="googl_api_key" id="googl_api_key" value="<?php esc_attr_e( get_option( 'googl_api_key' ) ) ?>"/>
477
  </p>
478
-
479
  <div><input type="hidden" name="submit-type" value="googlapi" /></div>
480
- <?php echo $form_end; ?>
481
- <?php } else if ( $shortener == 10 ) { ?>
482
- <?php echo $form_start; ?>
 
 
483
  <p>
484
- <label
485
- for="joturllogin"><?php _e( "Your jotURL public <abbr title='application programming interface'>API</abbr> key:", 'wp-to-twitter' ); ?></label>
486
- <input type="text" name="joturllogin" id="joturllogin"
487
- value="<?php esc_attr_e( get_option( 'joturllogin' ) ) ?>"/>
488
  </p>
489
-
490
  <p>
491
- <label
492
- for="joturlapi"><?php _e( "Your jotURL private <abbr title='application programming interface'>API</abbr> key:", 'wp-to-twitter' ); ?></label>
493
- <input type="text" name="joturlapi" id="joturlapi" size="40"
494
- value="<?php esc_attr_e( get_option( 'joturlapi' ) ) ?>"/>
495
  </p>
496
-
497
  <p>
498
- <label
499
- for="joturl_longurl_params"><?php _e( "Parameters to add to the long URL (before shortening):", 'wp-to-twitter' ); ?></label>
500
- <input type="text" name="joturl_longurl_params" id="joturl_longurl_params"
501
- size="40"
502
- value="<?php esc_attr_e( get_option( 'joturl_longurl_params' ) ) ?>"/>
503
  </p>
504
 
505
  <p>
506
- <label
507
- for="joturl_shorturl_params"><?php _e( "Parameters to add to the short URL (after shortening):", 'wp-to-twitter' ); ?></label>
508
- <input type="text" name="joturl_shorturl_params" id="joturl_shorturl_params"
509
- size="40"
510
- value="<?php esc_attr_e( get_option( 'joturl_shorturl_params' ) ) ?>"/>
511
  </p>
512
-
513
  <p>
514
  <a href="https://www.joturl.com/reserved/api.html"><?php _e( 'View your jotURL public and private API key', 'wp-to-twitter' ); ?></a>
515
  </p>
516
-
517
  <div><input type="hidden" name="submit-type" value="joturlapi"/></div>
518
- <?php echo $form_end;
 
519
  } else {
520
  $form = apply_filters( 'wpt_shortener_settings', '', $shortener );
521
- if ( $form != '' ) {
522
  echo $form_start . $form . $form_end;
523
  } else {
524
  _e( 'Your shortener does not require any account settings.', 'wp-to-twitter' );
525
  }
526
- } ?>
 
527
  </div>
528
  </div>
529
  </div>
530
  <?php
531
  }
532
 
 
 
 
 
 
533
  function wpt_shortener_update( $post ) {
534
  $message = '';
535
- if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'yourlsapi' ) {
536
  $message = '';
537
- if ( $post['yourlstoken'] != '' && isset( $post['submit'] ) ) {
538
  update_option( 'yourlstoken', trim( $post['yourlstoken'] ) );
539
  delete_option( 'yourlsapi' );
540
  delete_option( 'yourlslogin' );
@@ -542,22 +528,22 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
542
  }
543
  update_option( 'yourlsurl', trim( $post['yourlsurl'] ) );
544
  // yourls path is deprecated.
545
- if ( isset( $post['yourlspath'] ) && $post['yourlspath'] != '' ) {
546
  update_option( 'yourlspath', trim( $post['yourlspath'] ) );
547
  if ( file_exists( $post['yourlspath'] ) ) {
548
- $message .= ' ' . __( "YOURLS local server path added. ", 'wp-to-twitter' );
549
  } else {
550
- $message .= ' ' . __( "The path to your YOURLS installation is not correct. ", 'wp-to-twitter' );
551
  }
552
  }
553
- if ( $post['jd_keyword_format'] != '' ) {
554
  update_option( 'jd_keyword_format', $post['jd_keyword_format'] );
555
- if ( $post['jd_keyword_format'] == 1 ) {
556
- $message .= ' ' . __( "YOURLS will use Post ID for short URL slug.", 'wp-to-twitter' );
557
- } else if ( $post['jd_keyword_format'] == 0 ) {
558
  $message .= ' ' . __( 'YOURLS will use default URL structures.', 'wp-to-twitter' );
559
  } else {
560
- $message .= ' ' . __( "YOURLS will use your custom keyword for short URL slug.", 'wp-to-twitter' );
561
  }
562
  }
563
  if ( isset( $post['clear'] ) ) {
@@ -571,145 +557,175 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
571
  }
572
  }
573
 
574
- if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'suprapi' ) {
575
- if ( $post['suprapi'] != '' && isset( $post['submit'] ) ) {
576
  update_option( 'suprapi', trim( $post['suprapi'] ) );
577
  update_option( 'suprlogin', trim( $post['suprlogin'] ) );
578
- $message = __( "Su.pr API Key and Username Updated", 'wp-to-twitter' );
579
- } else if ( isset( $post['clear'] ) ) {
580
  update_option( 'suprapi', '' );
581
  update_option( 'suprlogin', '' );
582
- $message = __( "Su.pr API Key and username deleted. Su.pr URLs created by WP to Twitter will no longer be associated with your account. ", 'wp-to-twitter' );
583
  } else {
584
- $message = __( "Su.pr API Key not added - <a href='http://su.pr/'>get one here</a>! ", 'wp-to-twitter' );
585
  }
586
  }
587
-
588
- if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'bitlyapi' ) {
589
- if ( $post['bitlyapi'] != '' && isset( $post['submit'] ) ) {
590
  update_option( 'bitlyapi', trim( $post['bitlyapi'] ) );
591
- $message = __( "Bit.ly API Key Updated.", 'wp-to-twitter' );
592
- } else if ( isset( $post['clear'] ) ) {
593
  update_option( 'bitlyapi', '' );
594
- $message = __( "Bit.ly API Key deleted. You cannot use the Bit.ly API without an API key. ", 'wp-to-twitter' );
595
  } else {
596
  $message = __( "Bit.ly API Key not added - <a href='http://bit.ly/account/'>get one here</a>! An API key is required to use the Bit.ly URL shortening service.", 'wp-to-twitter' );
597
  }
598
- if ( $post['bitlylogin'] != '' && isset( $post['submit'] ) ) {
599
  update_option( 'bitlylogin', trim( $post['bitlylogin'] ) );
600
- $message .= __( " Bit.ly User Login Updated.", 'wp-to-twitter' );
601
- } else if ( isset( $post['clear'] ) ) {
602
  update_option( 'bitlylogin', '' );
603
- $message = __( "Bit.ly User Login deleted. You cannot use the Bit.ly API without providing your username. ", 'wp-to-twitter' );
604
  } else {
605
- $message = __( "Bit.ly Login not added - <a href='http://bit.ly/account/'>get one here</a>! ", 'wp-to-twitter' );
606
  }
607
  }
608
- if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'googlapi' ) {
609
- if ( $post['googl_api_key'] != '' && isset( $post['submit'] ) ) {
610
  update_option( 'googl_api_key', trim( $post['googl_api_key'] ) );
611
- $message .= __( "Goo.gl API Key Updated. ", 'wp-to-twitter' );
612
  } else {
613
  $message = __( "Goo.gl API Key not added - <a href='https://developers.google.com/url-shortener/v1/getting_started'>get one here</a>! ", 'wp-to-twitter' );
614
- }
615
  }
616
-
617
- if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'joturlapi' ) {
618
- if ( $post['joturlapi'] != '' && isset( $post['submit'] ) ) {
619
  update_option( 'joturlapi', trim( $post['joturlapi'] ) );
620
- $message = __( "jotURL private API Key Updated. ", 'wp-to-twitter' );
621
- } else if ( isset( $post['clear'] ) ) {
622
  update_option( 'joturlapi', '' );
623
- $message = __( "jotURL private API Key deleted. You cannot use the jotURL API without a private API key. ", 'wp-to-twitter' );
624
  } else {
625
  $message = __( "jotURL private API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! A private API key is required to use the jotURL URL shortening service. ", 'wp-to-twitter' );
626
  }
627
- if ( $post['joturllogin'] != '' && isset( $post['submit'] ) ) {
628
  update_option( 'joturllogin', trim( $post['joturllogin'] ) );
629
- $message .= __( "jotURL public API Key Updated. ", 'wp-to-twitter' );
630
- } else if ( isset( $post['clear'] ) ) {
631
  update_option( 'joturllogin', '' );
632
- $message = __( "jotURL public API Key deleted. You cannot use the jotURL API without providing your public API Key. ", 'wp-to-twitter' );
633
  } else {
634
  $message = __( "jotURL public API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! ", 'wp-to-twitter' );
635
- }
636
- if ( $post['joturl_longurl_params'] != '' && isset( $post['submit'] ) ) {
637
  $v = trim( $post['joturl_longurl_params'] );
638
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
639
  $v = substr( $v, 1 );
640
  }
641
  update_option( 'joturl_longurl_params', $v );
642
- $message .= __( "Long URL parameters added. ", 'wp-to-twitter' );
643
- } else if ( isset( $post['clear'] ) ) {
644
  update_option( 'joturl_longurl_params', '' );
645
- $message = __( "Long URL parameters deleted. ", 'wp-to-twitter' );
646
  }
647
- if ( $post['joturl_shorturl_params'] != '' && isset( $post['submit'] ) ) {
648
  $v = trim( $post['joturl_shorturl_params'] );
649
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
650
  $v = substr( $v, 1 );
651
  }
652
  update_option( 'joturl_shorturl_params', $v );
653
- $message .= __( "Short URL parameters added. ", 'wp-to-twitter' );
654
- } else if ( isset( $post['clear'] ) ) {
655
  update_option( 'joturl_shorturl_params', '' );
656
- $message = __( "Short URL parameters deleted. ", 'wp-to-twitter' );
657
  }
658
  }
659
-
660
  $message = apply_filters( 'wpt_save_shortener_settings', $message );
661
 
662
  return $message;
663
  }
664
 
 
 
 
 
 
 
 
665
  function wpt_select_shortener( $post ) {
666
  $message = '';
667
- // don't return a message if unchanged
668
- if ( $post['jd_shortener'] == get_option( 'jd_shortener' ) ) {
 
 
669
  return;
670
  }
671
  update_option( 'jd_shortener', sanitize_key( $post['jd_shortener'] ) );
672
-
673
- $short = get_option( 'jd_shortener' );
674
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
675
  $admin_url = add_query_arg( 'tab', 'shortener', $admin_url );
676
-
677
  // these are the URL shorteners which require settings.
678
- if ( $short == 2 || $short == 10 || $short == 6 ) {
 
679
  $message .= sprintf( __( 'You must <a href="%s">configure your URL shortener settings</a>.', 'wp-to-twitter' ), $admin_url );
680
  }
681
-
682
- if ( $message != '' ) {
683
- $message .= "<br />";
684
  }
685
-
686
  return $message;
687
  }
688
 
689
  add_filter( 'wpt_pick_shortener', 'wpt_pick_shortener' );
 
 
 
690
  function wpt_pick_shortener() {
691
  $shortener = get_option( 'jd_shortener' );
 
 
 
692
  ?>
693
  <p>
694
- <label for="jd_shortener"><?php _e( "Choose a URL shortener", 'wp-to-twitter' ); ?></label>
695
  <select name="jd_shortener" id="jd_shortener">
696
- <option value="3" <?php selected( $shortener, '3' ); ?>><?php _e( "Don't shorten URLs.", 'wp-to-twitter' ); ?></option>
697
- <option value="4" <?php selected( $shortener, '4' ); ?>>WordPress</option>
698
- <option value="2" <?php selected( $shortener, '2' ); ?>>Bit.ly</option>
 
 
 
699
  <option value="8" <?php selected( $shortener, '8' ); ?>>Goo.gl</option>
700
- <option value="7" <?php selected( $shortener, '7' ); ?>>Su.pr</option>
701
- <?php if ( $shortener == 5 ) { // if the user has already selected local server, leave available ?>
702
- <option value="5" <?php selected( $shortener, '5' ); ?>><?php _e( "YOURLS (this server)", 'wp-to-twitter' ); ?></option>
703
- <?php } ?>
704
- <option value="6" <?php selected( $shortener, '6' ); ?>><?php _e( "YOURLS (remote server)", 'wp-to-twitter' ); ?></option>
 
 
 
 
 
 
 
705
  <option value="10" <?php selected( $shortener, '10' ); ?>>jotURL</option>
706
- <?php if ( function_exists( 'twitter_link' ) ) { ?>
707
- <option value="9" <?php selected( $shortener, '9' ); ?>><?php _e( "Twitter Friendly Links", 'wp-to-twitter' ); ?></option>
708
- <?php }
709
- echo apply_filters( 'wpt_choose_shortener', '', $shortener );
710
  ?>
711
  </select>
 
 
 
 
 
 
 
712
  </p>
713
  <?php
714
  }
715
- }
1
  <?php
2
+ /**
3
+ * URL Shorteners WP to Twitter
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
 
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
+ if ( ! function_exists( 'wpt_shorten_url' ) ) {
17
+ // prep work for future plug-in replacement.
18
  add_filter( 'wptt_shorten_link', 'wpt_shorten_url', 10, 4 );
19
 
20
+ /**
21
+ * Given a URL, shorten it.
22
+ *
23
+ * @param string $url URL.
24
+ * @param string $post_title Post Title.
25
+ * @param int $post_ID Post ID.
26
+ * @param mixed string/boolean $testmode Testing function.
27
+ * @param boolean $store_urls Whether to store URL after creating.
28
+ *
29
+ * @return shortened URL.
30
+ */
31
+ function wpt_shorten_url( $url, $post_title, $post_ID, $testmode = false, $store_urls = true ) {
32
+ wpt_mail( 'Initial Link', "$url, $post_title, $post_ID, $testmode" ); // DEBUG.
33
+ // filter link before sending to shortener or adding analytics.
34
  $shortener = get_option( 'jd_shortener' );
35
+ // if the URL already exists, return it without processing.
36
+ if ( wpt_short_url( $post_ID ) ) {
37
+ $shrink = wpt_short_url( $post_ID );
38
+
39
  return $shrink;
40
  }
41
  $url = apply_filters( 'wpt_shorten_link', $url, $shortener, $post_ID );
42
+ if ( false == $testmode ) {
43
+ if ( 1 == get_option( 'use-twitter-analytics' ) || 1 == get_option( 'use_dynamic_analytics' ) ) {
44
+ if ( '1' == get_option( 'use_dynamic_analytics' ) ) {
45
  $campaign_type = get_option( 'jd_dynamic_analytics' );
46
+ if ( 'post_category' == $campaign_type && 'link' != $testmode ) {
47
  $category = get_the_category( $post_ID );
48
  $campaign = sanitize_title( $category[0]->cat_name );
49
+ } elseif ( 'post_ID' == $campaign_type ) {
50
  $campaign = $post_ID;
51
+ } elseif ( 'post_title' == $campaign_type && 'link' != $testmode ) {
52
  $post = get_post( $post_ID );
53
  $campaign = sanitize_title( $post->post_title );
54
  } else {
55
+ if ( 'link' != $testmode ) {
56
  $post = get_post( $post_ID );
57
  $post_author = $post->post_author;
58
  $campaign = urlencode( get_the_author_meta( 'user_login', $post_author ) );
59
  } else {
60
+ $campaign = '';
61
  }
62
  }
63
  } else {
65
  }
66
  $medium = urlencode( trim( apply_filters( 'wpt_utm_medium', 'twitter' ) ) );
67
  $source = urlencode( trim( apply_filters( 'wpt_utm_source', 'twitter' ) ) );
68
+ $url = add_query_arg( array(
69
+ 'utm_campaign' => $campaign,
70
+ 'utm_medium' => $medium,
71
+ 'utm_source' => $source,
72
+ ), $url );
73
  }
74
+ $url = urldecode( trim( $url ) ); // prevent double-encoding.
75
  $encoded = urlencode( $url );
76
  } else {
77
+ $url = urldecode( trim( $url ) ); // prevent double-encoding.
78
  $encoded = urlencode( $url );
79
  }
80
 
81
+ // custom word setting.
82
+ $keyword_format = ( '1' == get_option( 'jd_keyword_format' ) ) ? $post_ID : '';
83
+ $keyword_format = ( '2' == get_option( 'jd_keyword_format' ) ) ? get_post_meta( $post_ID, '_yourls_keyword', true ) : $keyword_format;
84
+ // Generate and grab the short url.
85
+ $shrink = apply_filters( 'wpt_do_shortening', false, $shortener, $url, $post_title, $post_ID, $testmode );
86
+ // if an add-on has shortened the link, skip shortening.
87
  $error = false;
88
+ if ( ! $shrink ) {
89
  switch ( $shortener ) {
90
+ case 3: // no shortener.
91
  $shrink = $url;
92
  break;
93
+ case 2: // updated to v3 3/31/2010.
94
  $bitlyapi = trim( get_option( 'bitlyapi' ) );
95
  $bitlylogin = trim( strtolower( get_option( 'bitlylogin' ) ) );
96
+ $decoded = wpt_remote_json( 'https://api-ssl.bitly.com/v3/shorten?longUrl=' . $encoded . '&login=' . $bitlylogin . '&apiKey=' . $bitlyapi . '&format=json' );
97
  if ( $decoded && isset( $decoded['status_code'] ) ) {
98
+ if ( 200 != $decoded['status_code'] ) {
99
  $shrink = $url;
100
  $error = $decoded['status_txt'];
101
  } else {
111
  case 4:
112
  if ( function_exists( 'wp_get_shortlink' ) ) {
113
  // wp_get_shortlink doesn't natively support custom post types; but don't return an error in that case.
114
+ $shrink = ( false != $post_ID ) ? wp_get_shortlink( $post_ID, 'post' ) : $url;
115
  }
116
  if ( ! $shrink ) {
117
  $shrink = $url;
118
  }
119
+ break;
120
  case 5:
121
+ // local YOURLS installation.
122
+ define( 'YOURLS_INSTALLING', true ); // Pretend we're installing YOURLS to bypass test for install or upgrade.
123
+ define( 'YOURLS_FLOOD_DELAY_SECONDS', 0 ); // Disable flood check.
 
124
  $opath = get_option( 'yourlspath' );
125
  $ypath = str_replace( 'user', 'includes', $opath );
126
+ if ( file_exists( dirname( $ypath ) . '/load-yourls.php' ) ) { // YOURLS 1.4+.
127
  require_once( dirname( $ypath ) . '/load-yourls.php' );
128
  global $ydb;
129
  if ( function_exists( 'yourls_add_new_link' ) ) {
130
+ $yourls_result = yourls_add_new_link( $url, $keyword_format, $post_title );
131
  } else {
132
  $yourls_result = $url;
133
  }
 
 
 
 
 
 
134
  }
135
  if ( $yourls_result ) {
136
  $shrink = $yourls_result['shorturl'];
139
  }
140
  break;
141
  case 6:
142
+ // remote YOURLS installation.
143
  $yourlslogin = trim( get_option( 'yourlslogin' ) );
144
  $yourlsapi = stripcslashes( get_option( 'yourlsapi' ) );
145
  $token = stripcslashes( get_option( 'yourlstoken' ) );
149
  'signature' => $token,
150
  'url' => $encoded,
151
  'action' => 'shorturl',
152
+ 'format' => 'json',
153
+ 'title' => urlencode( $post_title ),
154
  );
155
  } else {
156
  $args = array(
158
  'password' => $yourlsapi,
159
  'url' => $encoded,
160
  'action' => 'shorturl',
161
+ 'format' => 'json',
162
+ 'title' => urlencode( $post_title ),
163
  );
164
  }
165
  if ( $keyword_format ) {
166
  $args['keyword'] = $keyword_format;
167
  }
168
+
169
  $api_url = add_query_arg( $args, $yourlsurl );
170
+
171
  $json = wpt_remote_json( $api_url, false );
172
+ wpt_mail( 'YOURLS JSON Response', print_r( $json, 1 ) ); // DEBUG YOURLS response.
173
  if ( is_object( $json ) ) {
174
  $shrink = $json->shorturl;
175
  } else {
176
+ $error = 'Error code: ' . $json->shorturl . ' ' . $json->message;
177
  $shrink = false;
178
  }
179
  break;
180
  case 7:
181
  $suprapi = trim( get_option( 'suprapi' ) );
182
  $suprlogin = trim( get_option( 'suprlogin' ) );
183
+ if ( '' != $suprapi ) {
184
+ $decoded = wpt_remote_json( 'http://su.pr/api/shorten?longUrl=' . $encoded . '&login=' . $suprlogin . '&apiKey=' . $suprapi );
185
  } else {
186
+ $decoded = wpt_remote_json( 'http://su.pr/api/shorten?longUrl=' . $encoded );
187
  }
188
  if ( $decoded && isset( $decoded['statusCode'] ) ) {
189
+ if ( 'OK' == $decoded['statusCode'] ) {
190
+ $page = str_replace( '&', '&#38;', urldecode( $url ) );
191
  $shrink = $decoded['results'][ $page ]['shortUrl'];
192
  $error = $decoded['errorMessage'];
193
  } else {
203
  }
204
  break;
205
  case 8:
206
+ // Goo.gl.
207
+ $googl_api_key = ( '' == get_option( 'googl_api_key' ) ) ? 'AIzaSyBSnqQOg3vX1gwR7y2l-40yEG9SZiaYPUQ' : get_option( 'googl_api_key' );
208
+ $target = "https://www.googleapis.com/urlshortener/v1/url?key=$googl_api_key";
209
+ $body = "{'longUrl':'$url'}";
210
+ $json = wpt_fetch_url( $target, 'POST', $body, 'Content-Type: application/json' );
211
+ $decoded = json_decode( $json );
212
+ $shrink = $decoded->id;
213
  if ( ! wpt_is_valid_url( $shrink ) ) {
214
  $shrink = false;
215
  }
216
  break;
217
  case 9:
218
+ // Twitter Friendly Links. This plugin not updated in 8 years.
219
  $shrink = $url;
 
 
 
220
  break;
221
+ case 10:
222
+ // jotURL, added: 2013-04-10.
223
  $joturlapi = trim( get_option( 'joturlapi' ) );
224
  $joturllogin = trim( get_option( 'joturllogin' ) );
225
  $joturl_longurl_params = trim( get_option( 'joturl_longurl_params' ) );
226
+ if ( '' != $joturl_longurl_params ) {
227
+ if ( false === strpos( $url, '%3F' ) && false == strpos( $url, '?' ) ) {
228
+ $ct = '?';
229
  } else {
230
+ $ct = '&';
231
  }
232
+ $url .= $ct . $joturl_longurl_params;
233
+ $encoded = urlencode( urldecode( trim( $url ) ) ); // prevent double-encoding.
234
  }
235
+ $decoded = wpt_fetch_url( 'https://api.joturl.com/a/v1/shorten?url=' . $encoded . '&login=' . $joturllogin . '&key=' . $joturlapi . '&format=plain' );
236
+ if ( false !== $decoded ) {
237
+ $shrink = $decoded;
 
 
238
  $joturl_shorturl_params = trim( get_option( 'joturl_shorturl_params' ) );
239
+ if ( '' != $joturl_shorturl_params ) {
240
+ if ( false === strpos( $shrink, '%3F' ) && false === strpos( $shrink, '?' ) ) {
241
+ $ct = '?';
242
  } else {
243
+ $ct = '&';
244
  }
245
  $shrink .= $ct . $joturl_shorturl_params;
246
  }
 
247
  } else {
248
  $error = $decoded;
249
  $shrink = false;
252
  $shrink = false;
253
  }
254
  break;
255
+ default:
256
+ $shrink = $url;
257
  }
258
  }
259
  if ( $error ) {
260
  update_option( 'wpt_shortener_status', "$shrink : $error" );
261
  }
262
  if ( ! $testmode ) {
263
+ if ( false === $shrink || ( false === filter_var( $shrink, FILTER_VALIDATE_URL ) ) ) {
264
  update_option( 'wp_url_failure', '1' );
265
  $shrink = urldecode( $url );
266
  } else {
274
 
275
  return $shrink;
276
  }
277
+
278
+ /**
279
+ * Store shortened URL for re-use.
280
+ *
281
+ * @param int $post_ID Post ID.
282
+ * @param string $url Shortened URL.
283
+ */
284
  function wpt_store_url( $post_ID, $url ) {
285
  $store_urls = apply_filters( 'wpt_store_urls', true, $post_ID, $url );
286
+ if ( function_exists( 'wpt_shorten_url' ) && $store_urls ) {
287
  $shortener = get_option( 'jd_shortener' );
288
+ if ( wpt_short_url( $post_ID ) != $url && wpt_is_valid_url( $url ) ) {
289
  update_post_meta( $post_ID, '_wpt_short_url', $url );
290
  }
291
  switch ( $shortener ) {
 
 
 
 
 
 
 
292
  case 5:
293
  case 6:
294
  $target = wpt_expand_yourl( $url, $shortener );
301
  }
302
  update_post_meta( $post_ID, '_wp_jd_target', $target );
303
  }
304
+
305
+ /**
306
+ * Expand a saved YOURL URl.
307
+ *
308
+ * @param string $short_url Shortened URL.
309
+ * @param int $remote Remote or local install.
310
+ *
311
+ * @return long url.
312
  */
 
 
 
 
 
 
 
 
313
  function wpt_expand_yourl( $short_url, $remote ) {
314
+ if ( 6 == $remote ) {
315
  $short_url = urlencode( $short_url );
316
  $yourl_api = get_option( 'yourlsurl' );
317
  $user = get_option( 'yourlslogin' );
318
+ $pass = stripslashes( get_option( 'yourlsapi' ) );
319
  $token = get_option( 'yourlstoken' );
320
  if ( $token ) {
321
  $decoded = wpt_remote_json( $yourl_api . "?action=expand&shorturl=$short_url&format=json&signature=$token&username=$user&password=$pass" );
326
 
327
  return $url;
328
  } else {
329
+ define( 'YOURLS_INSTALLING', true ); // Pretend we're installing YOURLS to bypass test for install or upgrade.
330
+ define( 'YOURLS_FLOOD_DELAY_SECONDS', 0 ); // Disable flood check.
331
+ if ( file_exists( dirname( get_option( 'yourlspath' ) ) . '/load-yourls.php' ) ) { // YOURLS 1.4+.
 
332
  global $ydb;
333
  require_once( dirname( get_option( 'yourlspath' ) ) . '/load-yourls.php' );
334
  $yourls_result = yourls_api_expand( $short_url );
 
 
 
 
 
 
335
  }
336
  if ( $yourls_result ) {
337
  $url = $yourls_result['longurl'];
343
  }
344
 
345
  add_filter( 'wpt_shortener_controls', 'wpt_shortener_controls' );
346
+ /**
347
+ * Controls for adding shortener relevant data.
348
+ */
349
  function wpt_shortener_controls() {
350
+ $shortener = get_option( 'jd_shortener' );
351
+ $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
352
  $form_start = '<div class="panel">
353
  <form method="post" action="' . add_query_arg( 'tab', 'shortener', $admin_url ) . '">
354
  <div><input type="hidden" name="wpt_shortener_update" value="true" /></div>
355
  <div>';
356
+ $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false );
357
+ $form_end = '<div>' . $nonce . '</div>
358
+ <p>
359
+ <input type="submit" name="submit" value="' . __( 'Save URL Shortener Settings', 'wp-to-twitter' ) . '" class="button-primary" />
360
+ </p>
361
+ </div>
362
+ </form>
363
+ </div>';
364
  // for the moment, this just displays the fields. Eventually, a real filter.
365
  ?>
366
  <div class="ui-sortable meta-box-sortables">
370
  </h3>
371
 
372
  <div class="inside">
373
+ <?php
374
+ if ( 7 == $shortener ) {
375
+ ?>
376
  <?php echo $form_start; ?>
377
  <p>
378
  <label
379
+ for="suprlogin"><?php _e( 'Your Su.pr Username:', 'wp-to-twitter' ); ?></label>
380
+ <input type="text" name="suprlogin" id="suprlogin" size="40" value="<?php echo esc_attr( get_option( 'suprlogin' ) ); ?> "/>
 
381
  </p>
 
382
  <p>
383
  <label
384
  for="suprapi"><?php _e( "Your Su.pr <abbr title='application programming interface'>API</abbr> Key:", 'wp-to-twitter' ); ?></label>
385
+ <input type="text" name="suprapi" id="suprapi" size="40" value="<?php echo esc_attr( get_option( 'suprapi' ) ); ?> "/>
 
386
  </p>
387
 
388
  <div>
389
  <input type="hidden" name="submit-type" value="suprapi"/>
390
  </div>
391
  <p><small><?php _e( "Don't have a Su.pr account or API key? <a href='http://su.pr/'>Get one here!</a> You'll need an API key in order to associate the URLs you create with your Su.pr account.", 'wp-to-twitter' ); ?></small></p>
392
+ <?php echo $form_end; ?>
393
+ <?php
394
+ } elseif ( 2 == $shortener ) {
395
+ echo $form_start;
396
+ ?>
397
  <p>
398
+ <label for="bitlylogin"><?php _e( 'Your Bit.ly username:', 'wp-to-twitter' ); ?></label>
399
+ <input type="text" name="bitlylogin" id="bitlylogin" value="<?php echo esc_attr( get_option( 'bitlylogin' ) ); ?>"/>
 
 
400
  </p>
401
  <p>
402
+ <label for="bitlyapi"><?php _e( "Your Bit.ly <abbr title='application programming interface'>API</abbr> Key:", 'wp-to-twitter' ); ?></label>
403
+ <input type="text" name="bitlyapi" id="bitlyapi" size="40" value="<?php echo esc_attr( get_option( 'bitlyapi' ) ); ?>"/>
 
 
404
  </p>
 
405
  <p>
406
  <a href="http://bitly.com/a/your_api_key"><?php _e( 'View your Bit.ly username and API key', 'wp-to-twitter' ); ?></a>
407
  </p>
 
408
  <div>
409
  <input type="hidden" name="submit-type" value="bitlyapi"/>
410
  </div>
411
+ <?php
412
+ echo $form_end;
413
+ } elseif ( 5 == $shortener || 6 == $shortener ) {
414
+ echo $form_start;
415
+ if ( 5 == $shortener ) {
416
+ ?>
417
  <p>
418
+ <label for="yourlspath"><?php _e( 'Path to your YOURLS config file', 'wp-to-twitter' ); ?></label><br/>
419
+ <input type="text" id="yourlspath" name="yourlspath" size="60" value="<?php echo esc_attr( get_option( 'yourlspath' ) ); ?>"/><br/>
 
 
420
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>/home/username/www/www/yourls/user/config.php</code>
421
  </small>
422
  </p>
423
+ <?php
424
+ }
425
+ if ( 6 == $shortener ) {
426
+ ?>
427
  <p>
428
+ <label for="yourlsurl"><?php _e( 'URI to the YOURLS API', 'wp-to-twitter' ); ?></label><br/>
429
+ <input type="text" id="yourlsurl" name="yourlsurl" size="60" value="<?php echo esc_attr( get_option( 'yourlsurl' ) ); ?>"/><br/>
 
 
430
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>http://domain.com/yourls-api.php</code>
431
  </small>
432
  </p>
433
+ <?php
434
+ }
435
+ ?>
436
  <p>
437
+ <label for="yourlstoken"><?php _e( 'YOURLS signature token:', 'wp-to-twitter' ); ?></label>
438
+ <input type="text" name="yourlstoken" id="yourlstoken" size="30" value="<?php echo esc_attr( get_option( 'yourlstoken' ) ); ?>"/>
 
 
439
  </p>
440
+ <?php
441
+ if ( get_option( 'yourlsapi' ) && get_option( 'yourlslogin' ) ) {
442
+ ?>
443
  <p>
444
  <em><?php _e( 'Your YOURLS username and password are saved. If you add a signature token, that will be used for API calls and your username and password will be deleted from the database.', 'wp-to-twitter' ); ?></em>
445
  </p>
446
+ <?php
447
+ }
448
+ ?>
449
  <p>
450
+ <input type="radio" name="jd_keyword_format" id="jd_keyword_id" value="1" <?php checked( get_option( 'jd_keyword_format' ), 1 ); ?> />
451
+ <label for="jd_keyword_id"><?php _e( 'Post ID for YOURLS url slug.', 'wp-to-twitter' ); ?></label><br/>
452
+ <input type="radio" name="jd_keyword_format" id="jd_keyword" value="2" <?php checked( get_option( 'jd_keyword_format' ), 2 ); ?> />
453
+ <label for="jd_keyword"><?php _e( 'Custom keyword for YOURLS url slug.', 'wp-to-twitter' ); ?></label><br/>
454
+ <input type="radio" name="jd_keyword_format" id="jd_keyword_default" value="0" <?php checked( get_option( 'jd_keyword_format' ), 0 ); ?> />
455
+ <label for="jd_keyword_default"><?php _e( 'Default: sequential URL numbering.', 'wp-to-twitter' ); ?></label>
 
 
 
 
 
 
456
  </p>
 
457
  <div>
458
  <input type="hidden" name="submit-type" value="yourlsapi" />
459
  </div>
460
+ <?php
461
+ echo $form_end;
462
+ } elseif ( 8 == $shortener ) {
463
+ echo '<p>' . __( 'The Goo.gl URL shortener will be shut down by Google on March 30th, 2019, and will be removed from WP to Twitter in the near future.', 'wp-to-twitter' ) . '</p>';
464
+ echo $form_start;
465
+ ?>
466
  <p>
467
+ <label for="googl_api_key"><?php _e( 'Goo.gl API Key:', 'wp-to-twitter' ); ?></label>
468
+ <input type="text" name="googl_api_key" id="googl_api_key" value="<?php echo esc_attr( get_option( 'googl_api_key' ) ); ?>"/>
469
  </p>
 
470
  <div><input type="hidden" name="submit-type" value="googlapi" /></div>
471
+ <?php
472
+ echo $form_end;
473
+ } elseif ( 10 == $shortener ) {
474
+ echo $form_start;
475
+ ?>
476
  <p>
477
+ <label for="joturllogin"><?php _e( "Your jotURL public <abbr title='application programming interface'>API</abbr> key:", 'wp-to-twitter' ); ?></label>
478
+ <input type="text" name="joturllogin" id="joturllogin" value="<?php echo esc_attr( get_option( 'joturllogin' ) ); ?>"/>
 
 
479
  </p>
 
480
  <p>
481
+ <label for="joturlapi"><?php _e( "Your jotURL private <abbr title='application programming interface'>API</abbr> key:", 'wp-to-twitter' ); ?></label>
482
+ <input type="text" name="joturlapi" id="joturlapi" size="40" value="<?php echo esc_attr( get_option( 'joturlapi' ) ); ?>"/>
 
 
483
  </p>
 
484
  <p>
485
+ <label for="joturl_longurl_params"><?php _e( 'Parameters to add to the long URL (before shortening):', 'wp-to-twitter' ); ?></label>
486
+ <input type="text" name="joturl_longurl_params" id="joturl_longurl_params" size="40" value="<?php echo esc_attr( get_option( 'joturl_longurl_params' ) ); ?>"/>
 
 
 
487
  </p>
488
 
489
  <p>
490
+ <label for="joturl_shorturl_params"><?php _e( 'Parameters to add to the short URL (after shortening):', 'wp-to-twitter' ); ?></label>
491
+ <input type="text" name="joturl_shorturl_params" id="joturl_shorturl_params" size="40" value="<?php echo esc_attr( get_option( 'joturl_shorturl_params' ) ); ?>"/>
 
 
 
492
  </p>
 
493
  <p>
494
  <a href="https://www.joturl.com/reserved/api.html"><?php _e( 'View your jotURL public and private API key', 'wp-to-twitter' ); ?></a>
495
  </p>
 
496
  <div><input type="hidden" name="submit-type" value="joturlapi"/></div>
497
+ <?php
498
+ echo $form_end;
499
  } else {
500
  $form = apply_filters( 'wpt_shortener_settings', '', $shortener );
501
+ if ( '' != $form ) {
502
  echo $form_start . $form . $form_end;
503
  } else {
504
  _e( 'Your shortener does not require any account settings.', 'wp-to-twitter' );
505
  }
506
+ }
507
+ ?>
508
  </div>
509
  </div>
510
  </div>
511
  <?php
512
  }
513
 
514
+ /**
515
+ * Update settings for shorteners.
516
+ *
517
+ * @param array $post POST data.
518
+ */
519
  function wpt_shortener_update( $post ) {
520
  $message = '';
521
+ if ( isset( $post['submit-type'] ) && 'yourlsapi' == $post['submit-type'] ) {
522
  $message = '';
523
+ if ( '' != $post['yourlstoken'] && isset( $post['submit'] ) ) {
524
  update_option( 'yourlstoken', trim( $post['yourlstoken'] ) );
525
  delete_option( 'yourlsapi' );
526
  delete_option( 'yourlslogin' );
528
  }
529
  update_option( 'yourlsurl', trim( $post['yourlsurl'] ) );
530
  // yourls path is deprecated.
531
+ if ( isset( $post['yourlspath'] ) && '' != $post['yourlspath'] ) {
532
  update_option( 'yourlspath', trim( $post['yourlspath'] ) );
533
  if ( file_exists( $post['yourlspath'] ) ) {
534
+ $message .= ' ' . __( 'YOURLS local server path added. ', 'wp-to-twitter' );
535
  } else {
536
+ $message .= ' ' . __( 'The path to your YOURLS installation is not correct. ', 'wp-to-twitter' );
537
  }
538
  }
539
+ if ( '' != $post['jd_keyword_format'] ) {
540
  update_option( 'jd_keyword_format', $post['jd_keyword_format'] );
541
+ if ( 1 == $post['jd_keyword_format'] ) {
542
+ $message .= ' ' . __( 'YOURLS will use Post ID for short URL slug.', 'wp-to-twitter' );
543
+ } elseif ( 0 == $post['jd_keyword_format'] ) {
544
  $message .= ' ' . __( 'YOURLS will use default URL structures.', 'wp-to-twitter' );
545
  } else {
546
+ $message .= ' ' . __( 'YOURLS will use your custom keyword for short URL slug.', 'wp-to-twitter' );
547
  }
548
  }
549
  if ( isset( $post['clear'] ) ) {
557
  }
558
  }
559
 
560
+ if ( isset( $post['submit-type'] ) && 'suprapi' == $post['submit-type'] ) {
561
+ if ( '' != $post['suprapi'] && isset( $post['submit'] ) ) {
562
  update_option( 'suprapi', trim( $post['suprapi'] ) );
563
  update_option( 'suprlogin', trim( $post['suprlogin'] ) );
564
+ $message = __( 'Su.pr API Key and Username Updated', 'wp-to-twitter' );
565
+ } elseif ( isset( $post['clear'] ) ) {
566
  update_option( 'suprapi', '' );
567
  update_option( 'suprlogin', '' );
568
+ $message = __( 'Su.pr API Key and username deleted. Su.pr URLs created by WP to Twitter will no longer be associated with your account.', 'wp-to-twitter' );
569
  } else {
570
+ $message = __( "Su.pr API Key not added - <a href='http://su.pr/'>get one here</a>!", 'wp-to-twitter' );
571
  }
572
  }
573
+
574
+ if ( isset( $post['submit-type'] ) && 'bitlyapi' == $post['submit-type'] ) {
575
+ if ( '' != $post['bitlyapi'] && isset( $post['submit'] ) ) {
576
  update_option( 'bitlyapi', trim( $post['bitlyapi'] ) );
577
+ $message = __( 'Bit.ly API Key Updated.', 'wp-to-twitter' );
578
+ } elseif ( isset( $post['clear'] ) ) {
579
  update_option( 'bitlyapi', '' );
580
+ $message = __( 'Bit.ly API Key deleted. You cannot use the Bit.ly API without an API key.', 'wp-to-twitter' );
581
  } else {
582
  $message = __( "Bit.ly API Key not added - <a href='http://bit.ly/account/'>get one here</a>! An API key is required to use the Bit.ly URL shortening service.", 'wp-to-twitter' );
583
  }
584
+ if ( '' != $post['bitlylogin'] && isset( $post['submit'] ) ) {
585
  update_option( 'bitlylogin', trim( $post['bitlylogin'] ) );
586
+ $message .= __( 'Bit.ly User Login Updated.', 'wp-to-twitter' );
587
+ } elseif ( isset( $post['clear'] ) ) {
588
  update_option( 'bitlylogin', '' );
589
+ $message = __( 'Bit.ly User Login deleted. You cannot use the Bit.ly API without providing your username.', 'wp-to-twitter' );
590
  } else {
591
+ $message = __( "Bit.ly Login not added - <a href='http://bit.ly/account/'>get one here</a>!", 'wp-to-twitter' );
592
  }
593
  }
594
+ if ( isset( $post['submit-type'] ) && 'googlapi' == $post['submit-type'] ) {
595
+ if ( '' != $post['googl_api_key'] && isset( $post['submit'] ) ) {
596
  update_option( 'googl_api_key', trim( $post['googl_api_key'] ) );
597
+ $message .= __( 'Goo.gl API Key Updated.', 'wp-to-twitter' );
598
  } else {
599
  $message = __( "Goo.gl API Key not added - <a href='https://developers.google.com/url-shortener/v1/getting_started'>get one here</a>! ", 'wp-to-twitter' );
600
+ }
601
  }
602
+
603
+ if ( isset( $post['submit-type'] ) && 'joturlapi' == $post['submit-type'] ) {
604
+ if ( '' != $post['joturlapi'] && isset( $post['submit'] ) ) {
605
  update_option( 'joturlapi', trim( $post['joturlapi'] ) );
606
+ $message = __( 'jotURL private API Key Updated.', 'wp-to-twitter' );
607
+ } elseif ( isset( $post['clear'] ) ) {
608
  update_option( 'joturlapi', '' );
609
+ $message = __( 'jotURL private API Key deleted. You cannot use the jotURL API without a private API key.', 'wp-to-twitter' );
610
  } else {
611
  $message = __( "jotURL private API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! A private API key is required to use the jotURL URL shortening service. ", 'wp-to-twitter' );
612
  }
613
+ if ( '' != $post['joturllogin'] && isset( $post['submit'] ) ) {
614
  update_option( 'joturllogin', trim( $post['joturllogin'] ) );
615
+ $message .= __( 'jotURL public API Key Updated.', 'wp-to-twitter' );
616
+ } elseif ( isset( $post['clear'] ) ) {
617
  update_option( 'joturllogin', '' );
618
+ $message = __( 'jotURL public API Key deleted. You cannot use the jotURL API without providing your public API Key.', 'wp-to-twitter' );
619
  } else {
620
  $message = __( "jotURL public API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! ", 'wp-to-twitter' );
621
+ }
622
+ if ( '' != $post['joturl_longurl_params'] && isset( $post['submit'] ) ) {
623
  $v = trim( $post['joturl_longurl_params'] );
624
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
625
  $v = substr( $v, 1 );
626
  }
627
  update_option( 'joturl_longurl_params', $v );
628
+ $message .= __( 'Long URL parameters added.', 'wp-to-twitter' );
629
+ } elseif ( isset( $post['clear'] ) ) {
630
  update_option( 'joturl_longurl_params', '' );
631
+ $message = __( 'Long URL parameters deleted.', 'wp-to-twitter' );
632
  }
633
+ if ( '' != $post['joturl_shorturl_params'] && isset( $post['submit'] ) ) {
634
  $v = trim( $post['joturl_shorturl_params'] );
635
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
636
  $v = substr( $v, 1 );
637
  }
638
  update_option( 'joturl_shorturl_params', $v );
639
+ $message .= __( 'Short URL parameters added.', 'wp-to-twitter' );
640
+ } elseif ( isset( $post['clear'] ) ) {
641
  update_option( 'joturl_shorturl_params', '' );
642
+ $message = __( 'Short URL parameters deleted.', 'wp-to-twitter' );
643
  }
644
  }
 
645
  $message = apply_filters( 'wpt_save_shortener_settings', $message );
646
 
647
  return $message;
648
  }
649
 
650
+ /**
651
+ * Select a shortener.
652
+ *
653
+ * @param array $post POST data.
654
+ *
655
+ * @return message.
656
+ */
657
  function wpt_select_shortener( $post ) {
658
  $message = '';
659
+ // don't return a message if unchanged.
660
+ $stored = ( isset( $_POST['wpt_use_stored_urls'] ) ) ? 'false' : 'true';
661
+ update_option( 'wpt_use_stored_urls', $stored );
662
+ if ( get_option( 'jd_shortener' ) == $post['jd_shortener'] ) {
663
  return;
664
  }
665
  update_option( 'jd_shortener', sanitize_key( $post['jd_shortener'] ) );
666
+ $short = get_option( 'jd_shortener' );
 
667
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
668
  $admin_url = add_query_arg( 'tab', 'shortener', $admin_url );
669
+
670
  // these are the URL shorteners which require settings.
671
+ if ( 2 == $short || 10 == $short || 6 == $short ) {
672
+ // Translators: Settings URL for shortener configuration.
673
  $message .= sprintf( __( 'You must <a href="%s">configure your URL shortener settings</a>.', 'wp-to-twitter' ), $admin_url );
674
  }
675
+
676
+ if ( '' != $message ) {
677
+ $message .= '<br />';
678
  }
679
+
680
  return $message;
681
  }
682
 
683
  add_filter( 'wpt_pick_shortener', 'wpt_pick_shortener' );
684
+ /**
685
+ * Form to select your shortener.
686
+ */
687
  function wpt_pick_shortener() {
688
  $shortener = get_option( 'jd_shortener' );
689
+ if ( 8 == $shortener ) {
690
+ echo '<p>' . __( 'The Goo.gl URL shortener will be shut down by Google on March 30th, 2019, and will be removed from WP to Twitter in the near future.', 'wp-to-twitter' ) . '</p>';
691
+ }
692
  ?>
693
  <p>
694
+ <label for="jd_shortener"><?php _e( 'Choose a URL shortener', 'wp-to-twitter' ); ?></label>
695
  <select name="jd_shortener" id="jd_shortener">
696
+ <option value="3" <?php selected( $shortener, '3' ); ?>><?php _e( "Don't shorten URLs.", 'wp-to-twitter' ); ?></option>
697
+ <option value="4" <?php selected( $shortener, '4' ); ?>>WordPress</option>
698
+ <option value="2" <?php selected( $shortener, '2' ); ?>>Bit.ly</option>
699
+ <?php
700
+ if ( 8 == $shortener ) { // if already selected, leave available.
701
+ ?>
702
  <option value="8" <?php selected( $shortener, '8' ); ?>>Goo.gl</option>
703
+ <?php
704
+ }
705
+ ?>
706
+ <option value="7" <?php selected( $shortener, '7' ); ?>>Su.pr</option>
707
+ <?php
708
+ if ( 5 == $shortener ) { // if the user has already selected local server, leave available.
709
+ ?>
710
+ <option value="5" <?php selected( $shortener, '5' ); ?>><?php _e( 'YOURLS (this server)', 'wp-to-twitter' ); ?></option>
711
+ <?php
712
+ }
713
+ ?>
714
+ <option value="6" <?php selected( $shortener, '6' ); ?>><?php _e( 'YOURLS (remote server)', 'wp-to-twitter' ); ?></option>
715
  <option value="10" <?php selected( $shortener, '10' ); ?>>jotURL</option>
716
+ <?php
717
+ // Add a custom shortener.
718
+ echo apply_filters( 'wpt_choose_shortener', '', $shortener );
 
719
  ?>
720
  </select>
721
+ <?php
722
+ if ( 3 != $shortener ) {
723
+ ?>
724
+ <input type='checkbox' value='false' name='wpt_use_stored_urls' id='wpt_use_stored_urls' <?php checked( get_option( 'wpt_use_stored_urls' ), 'false' ); ?>> <label for='wpt_use_stored_urls'><?php _e( 'Always request a new short URL for Tweets', 'wp-to-twitter' ); ?></label>
725
+ <?php
726
+ }
727
+ ?>
728
  </p>
729
  <?php
730
  }
731
+ }
wp-to-twitter.php CHANGED
@@ -1,57 +1,87 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  /*
3
- Plugin Name: WP to Twitter
4
- Plugin URI: http://www.joedolson.com/wp-to-twitter/
5
- Description: Posts a Tweet when you update your WordPress blog or post a link, using your URL shortening service. Rich in features for customizing and promoting your Tweets.
6
- Version: 3.3.2
7
- Author: Joseph Dolson
8
- Text Domain: wp-to-twitter
9
- Author URI: http://www.joedolson.com/
10
- */
11
- /* Copyright 2008-2017 Joseph C Dolson (email : plugins@joedolson.com)
12
 
13
- This program is free software; you can redistribute it and/or modify
14
- it under the terms of the GNU General Public License as published by
15
- the Free Software Foundation; either version 2 of the License, or
16
- (at your option) any later version.
17
 
18
- This program is distributed in the hope that it will be useful,
19
- but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- GNU General Public License for more details.
22
 
23
- You should have received a copy of the GNU General Public License
24
- along with this program; if not, write to the Free Software
25
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
  */
27
  if ( ! defined( 'ABSPATH' ) ) {
28
  exit;
29
- } // Exit if accessed directly
30
 
31
- define( 'WPT_DEBUG', false ); // Debugging only works with WP Tweets PRO.
32
- define( 'WPT_DEBUG_BY_EMAIL', false ); // Email debugging no longer default as of 3.3.0
33
  define( 'WPT_DEBUG_ADDRESS', get_option( 'admin_email' ) );
34
- define( 'WPT_FROM', "From: \"" . get_option( 'blogname' ) . "\" <" . get_option( 'admin_email' ) . ">" );
35
- // define( 'WPT_DEBUG_ADDRESS', 'debug@joedolson.com, yourname@youraddress.com' ); // for multiple recipients.
36
-
37
- require_once( plugin_dir_path( __FILE__ ) . '/wpt-functions.php' );
38
- require_once( plugin_dir_path( __FILE__ ) . '/wp-to-twitter-oauth.php' );
39
- require_once( plugin_dir_path( __FILE__ ) . '/wp-to-twitter-shorteners.php' );
40
- require_once( plugin_dir_path( __FILE__ ) . '/wp-to-twitter-manager.php' );
41
- require_once( plugin_dir_path( __FILE__ ) . '/wpt-truncate.php' );
42
- require_once( plugin_dir_path( __FILE__ ) . '/wpt-feed.php' );
43
- require_once( plugin_dir_path( __FILE__ ) . '/wpt-widget.php' );
44
- require_once( plugin_dir_path( __FILE__ ) . '/wpt-rate-limiting.php' );
45
 
46
  global $wpt_version;
47
- $wpt_version = "3.3.2";
48
 
49
  add_action( 'init', 'wpt_load_textdomain' );
 
 
 
50
  function wpt_load_textdomain() {
51
  load_plugin_textdomain( 'wp-to-twitter' );
52
  }
53
 
54
- // check for OAuth configuration
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  function wpt_check_oauth( $auth = false ) {
56
  if ( ! function_exists( 'wtt_oauth_test' ) ) {
57
  $oauth = false;
@@ -62,31 +92,37 @@ function wpt_check_oauth( $auth = false ) {
62
  return $oauth;
63
  }
64
 
 
 
 
65
  function wpt_check_version() {
66
  global $wpt_version;
67
- $prev_version = ( get_option( 'wp_to_twitter_version' ) != '' ) ? get_option( 'wp_to_twitter_version' ) : '1.0.0';
68
- if ( version_compare( $prev_version, $wpt_version, "<" ) ) {
69
  wptotwitter_activate();
70
  }
71
  }
72
 
 
 
 
73
  function wptotwitter_activate() {
74
  // If this has never run before, do the initial setup.
75
- $new_install = ( get_option( 'wpt_twitter_setup' ) == 1 || get_option( 'twitterInitialised' ) == 1 ) ? false : true;
76
  if ( $new_install ) {
77
  $initial_settings = array(
78
  'post' => array(
79
  'post-published-update' => 1,
80
  'post-published-text' => 'New post: #title# #url#',
81
  'post-edited-update' => 0,
82
- 'post-edited-text' => 'Post Edited: #title# #url#'
83
  ),
84
  'page' => array(
85
  'post-published-update' => 0,
86
  'post-published-text' => 'New page: #title# #url#',
87
  'post-edited-update' => 0,
88
- 'post-edited-text' => 'Page edited: #title# #url#'
89
- )
90
  );
91
  update_option( 'wpt_post_types', $initial_settings );
92
  update_option( 'jd_twit_blogroll', '1' );
@@ -98,7 +134,8 @@ function wptotwitter_activate() {
98
  update_option( 'jd_replace_character', '' );
99
  $administrator = get_role( 'administrator' );
100
  if ( is_object( $administrator ) ) {
101
- $administrator->add_cap( 'wpt_twitter_oauth' ); // wpt_twitter_oauth is the general permission for editing user accounts
 
102
  $administrator->add_cap( 'wpt_twitter_custom' );
103
  $administrator->add_cap( 'wpt_twitter_switch' );
104
  $administrator->add_cap( 'wpt_can_tweet' );
@@ -119,15 +156,15 @@ function wptotwitter_activate() {
119
 
120
  update_option( 'jd_twit_remote', '0' );
121
  update_option( 'jd_post_excerpt', 30 );
122
- // Use Google Analytics with Twitter
123
  update_option( 'twitter-analytics-campaign', 'twitter' );
124
  update_option( 'use-twitter-analytics', '0' );
125
  update_option( 'jd_dynamic_analytics', '0' );
126
  update_option( 'no-analytics', 1 );
127
  update_option( 'use_dynamic_analytics', 'category' );
128
- // Use custom external URLs to point elsewhere.
129
  update_option( 'jd_twit_custom_url', 'external_link' );
130
- // Error checking
131
  update_option( 'wp_url_failure', '0' );
132
  // Default publishing options.
133
  update_option( 'jd_tweet_default', '0' );
@@ -135,185 +172,95 @@ function wptotwitter_activate() {
135
  update_option( 'wpt_inline_edits', '0' );
136
  // Note that default options are set.
137
  update_option( 'wpt_twitter_setup', '1' );
138
- update_option( 'jd_keyword_format', '0' );
139
  }
140
-
141
  global $wpt_version;
142
- $prev_version = get_option( 'wp_to_twitter_version' );
143
- // this is a switch to plan for future versions
144
  $administrator = get_role( 'administrator' );
145
- // version 2.4.0: 05/20/2012
146
- $upgrade = version_compare( $prev_version, "2.4.0", "<" );
147
- if ( $upgrade ) {
148
- $perms = get_option( 'wtt_user_permissions' );
149
- switch ( $perms ) {
150
- case 'read':
151
- $update = 'subscriber';
152
- break;
153
- case 'edit_posts':
154
- $update = 'contributor';
155
- break;
156
- case 'publish_posts':
157
- $update = 'author';
158
- break;
159
- case 'moderate_comments':
160
- $update = 'editor';
161
- break;
162
- case 'manage_options':
163
- $update = 'administrator';
164
- break;
165
- default:
166
- $update = 'administrator';
167
- }
168
- update_option( 'wtt_user_permissions', $update );
169
- }
170
- $upgrade = version_compare( $prev_version, "2.4.1", "<" );
171
- if ( $upgrade ) {
172
- $subscriber = get_role( 'subscriber' );
173
- $contributor = get_role( 'contributor' );
174
- $author = get_role( 'author' );
175
- $editor = get_role( 'editor' );
176
- $administrator->add_cap( 'wpt_twitter_oauth' );
177
- $administrator->add_cap( 'wpt_twitter_custom' );
178
- $administrator->add_cap( 'wpt_twitter_switch' ); // can toggle tweet/don't tweet
179
- switch ( get_option( 'wtt_user_permissions' ) ) { // users that can add twitter information
180
- case 'subscriber':
181
- $subscriber->add_cap( 'wpt_twitter_oauth' );
182
- $contributor->add_cap( 'wpt_twitter_oauth' );
183
- $author->add_cap( 'wpt_twitter_oauth' );
184
- $editor->add_cap( 'wpt_twitter_oauth' );
185
- break;
186
- case 'contributor':
187
- $contributor->add_cap( 'wpt_twitter_oauth' );
188
- $author->add_cap( 'wpt_twitter_oauth' );
189
- $editor->add_cap( 'wpt_twitter_oauth' );
190
- break;
191
- case 'author':
192
- $author->add_cap( 'wpt_twitter_oauth' );
193
- $editor->add_cap( 'wpt_twitter_oauth' );
194
- break;
195
- case 'editor':
196
- $editor->add_cap( 'wpt_twitter_oauth' );
197
- break;
198
- case 'administrator':
199
- break;
200
- default:
201
- $role = get_role( get_option( 'wtt_user_permissions' ) );
202
- if ( is_object( $role ) ) {
203
- $role->add_cap( 'wpt_twitter_oauth' );
204
- }
205
- break;
206
- }
207
- switch ( get_option( 'wtt_show_custom_tweet' ) ) { // users that can compose a custom tweet
208
- case 'subscriber':
209
- $subscriber->add_cap( 'wpt_twitter_custom' );
210
- $contributor->add_cap( 'wpt_twitter_custom' );
211
- $author->add_cap( 'wpt_twitter_custom' );
212
- $editor->add_cap( 'wpt_twitter_custom' );
213
- break;
214
- case 'contributor':
215
- $contributor->add_cap( 'wpt_twitter_custom' );
216
- $author->add_cap( 'wpt_twitter_custom' );
217
- $editor->add_cap( 'wpt_twitter_custom' );
218
- break;
219
- case 'author':
220
- $author->add_cap( 'wpt_twitter_custom' );
221
- $editor->add_cap( 'wpt_twitter_custom' );
222
- break;
223
- case 'editor':
224
- $editor->add_cap( 'wpt_twitter_custom' );
225
- break;
226
- case 'administrator':
227
- break;
228
- default:
229
- $role = get_role( get_option( 'wtt_show_custom_tweet' ) );
230
- if ( is_object( $role ) ) {
231
- $role->add_cap( 'wpt_twitter_custom' );
232
- }
233
- break;
234
- }
235
- }
236
- // version 2.4.13: 10/12/2012
237
- $upgrade = version_compare( $prev_version, "2.4.13", "<" );
238
- if ( $upgrade ) {
239
- $administrator->add_cap( 'wpt_can_tweet' );
240
- $editor = get_role( 'editor' );
241
- if ( is_object( $editor ) ) {
242
- $editor->add_cap( 'wpt_can_tweet' );
243
- }
244
- $author = get_role( 'author' );
245
- if ( is_object( $author ) ) {
246
- $author->add_cap( 'wpt_can_tweet' );
247
- }
248
- $contributor = get_role( 'contributor' );
249
- if ( is_object( $contributor ) ) {
250
- $contributor->add_cap( 'wpt_can_tweet' );
251
- }
252
- update_option( 'wpt_can_tweet', 'contributor' );
253
- }
254
- $upgrade = version_compare( $prev_version, "2.9.0", "<" );
255
  if ( $upgrade ) {
256
  $administrator->add_cap( 'wpt_tweet_now' );
257
  }
258
-
259
  update_option( 'wp_to_twitter_version', $wpt_version );
260
  }
261
 
262
- // Function checks for an alternate URL to be Tweeted. Contribution by Bill Berry.
 
 
 
 
 
 
263
  function wpt_link( $post_ID ) {
264
  $ex_link = false;
265
  $external_link = get_option( 'jd_twit_custom_url' );
266
  $permalink = get_permalink( $post_ID );
267
- if ( $external_link != '' ) {
268
  $ex_link = get_post_meta( $post_ID, $external_link, true );
269
  }
270
 
271
  return ( $ex_link ) ? $ex_link : $permalink;
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
274
  function wpt_saves_error( $id, $auth, $twit, $error, $http_code, $ts ) {
275
  $http_code = (int) $http_code;
276
- if ( $http_code != 200 ) {
277
  add_post_meta( $id, '_wpt_failed', array(
278
- 'author' => $auth,
279
- 'sentence' => $twit,
280
- 'error' => $error,
281
- 'code' => $http_code,
282
- 'timestamp' => $ts
283
- ) );
284
  } else {
285
- if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
286
  wpt_log_success( $auth, $ts, $id );
287
  }
288
  }
289
  }
290
 
291
 
292
- /*
293
- * Checks whether WP to Twitter has sent a tweet on this post to this author within the last 30 seconds and blocks it if so. Prevents double posting.
294
  *
295
- * uses filter wpt_recent_tweet_threshold
 
 
 
 
296
  */
297
  function wpt_check_recent_tweet( $id, $auth ) {
298
  if ( ! $id ) {
299
  return false;
300
  } else {
301
- if ( $auth == false ) {
302
  $transient = get_transient( "_wpt_most_recent_tweet_$id" );
303
  } else {
304
- $transient = get_transient( "_wpt_" . $auth . "_most_recent_tweet_$id" );
305
  }
306
  if ( $transient ) {
307
  return true;
308
  } else {
309
  $expire = apply_filters( 'wpt_recent_tweet_threshold', 30 );
310
  // if expiration is 0, don't set the transient. We don't want permanent transients.
311
- if ( $expire !== 0 ) {
312
- wpt_mail( "Tweet transient set", "$expire / $auth / $id" );
313
- if ( $auth == false ) {
314
  set_transient( "_wpt_most_recent_tweet_$id", true, $expire );
315
  } else {
316
- set_transient( "_wpt_" . $auth . "_most_recent_tweet_$id", true, $expire );
317
  }
318
  }
319
  }
@@ -324,21 +271,21 @@ function wpt_check_recent_tweet( $id, $auth ) {
324
 
325
  /**
326
  * Performs the API post to Twitter
327
- *
328
- * @param string $twit Text of Tweet to be sent to Twitter
329
- * @param integer $auth Author ID
330
- * @param integer $id Post ID
331
- * @param boolean $media Whether to upload media attached to the post specified in $id
332
- *
333
- * @return boolean Success of query.
334
  */
335
  function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false ) {
336
- $recent = wpt_check_recent_tweet( $id, $auth );
337
- $error = false;
338
- if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
339
  // check whether this post needs to be rate limited.
340
  $continue = wpt_test_rate_limit( $id, $auth );
341
- if ( !$continue ) {
342
  return false;
343
  }
344
  }
@@ -347,26 +294,26 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
347
  if ( $recent ) {
348
  return false;
349
  }
350
-
351
  if ( ! wpt_check_oauth( $auth ) ) {
352
  $error = __( 'This account is not authorized to post to Twitter.', 'wp-to-twitter' );
353
  wpt_saves_error( $id, $auth, $twit, $error, '401', time() );
354
  wpt_set_log( 'wpt_status_message', $id, $error );
355
 
356
  return false;
357
- } // exit silently if not authorized
358
 
359
- $check = ( ! $auth ) ? get_option( 'jd_last_tweet' ) : get_user_meta( $auth, 'wpt_last_tweet', true ); // get user's last tweet
360
- // prevent duplicate Tweets
361
  if ( $check == $twit ) {
362
- wpt_mail( "Matched: tweet identical", "This Tweet: $twit; Check Tweet: $check; $auth, $id, $media" ); // DEBUG
363
  $error = __( 'This tweet is identical to another Tweet recently sent to this account.', 'wp-to-twitter' ) . ' ' . __( 'Twitter requires all Tweets to be unique.', 'wp-to-twitter' );
364
  wpt_saves_error( $id, $auth, $twit, $error, '403-1', time() );
365
  wpt_set_log( 'wpt_status_message', $id, $error );
366
 
367
  return false;
368
- } else if ( $twit == '' || ! $twit ) {
369
- wpt_mail( "Tweet check: empty sentence", "$twit, $auth, $id, $media" ); // DEBUG
370
  $error = __( 'This tweet was blank and could not be sent to Twitter.', 'wp-tweets-pro' );
371
  wpt_saves_error( $id, $auth, $twit, $error, '403-2', time() );
372
  wpt_set_log( 'wpt_status_message', $id, $error );
@@ -374,7 +321,7 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
374
  return false;
375
  } else {
376
  $media_id = false;
377
- // must be designated as media and have a valid attachment
378
  $attachment = ( $media ) ? wpt_post_attachment( $id ) : false;
379
  if ( $attachment ) {
380
  wpt_mail( 'Post has upload', "$auth, $attachment" );
@@ -384,20 +331,40 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
384
  $attachment = false;
385
  }
386
  }
387
- $api = "https://api.twitter.com/1.1/statuses/update.json";
388
- $upload_api = 'https://upload.twitter.com/1.1/media/upload.json';
389
- $status = array(
390
- 'status' => $twit,
391
- 'source' => 'wp-to-twitter',
392
- 'include_entities' => 'true'
393
- );
394
-
395
- if ( wtt_oauth_test( $auth ) && ( $connection = wtt_oauth_connection( $auth ) ) ) {
396
- if ( $media && $attachment && !$media_id ) {
397
- $media_id = $connection->media( $upload_api, array( 'auth'=>$auth, 'media'=>$attachment ) );
398
- wpt_mail( 'Media Uploaded', "$auth, $media_id, $attachment" );
399
- if ( $media_id ) {
400
- $status['media_ids'] = $media_id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  }
402
  }
403
  }
@@ -405,20 +372,21 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
405
  $connection = array( 'connection' => 'undefined' );
406
  } else {
407
  $staging_mode = apply_filters( 'wpt_staging_mode', false, $auth, $id );
408
- if ( ( defined( 'WPT_STAGING_MODE' ) && WPT_STAGING_MODE == true ) || $staging_mode ) {
409
  // if in staging mode, we'll behave as if the Tweet succeeded, but not send it.
410
  $connection = true;
411
- $http_code = 200;
412
- $notice = __( 'In Staging Mode:', 'wp-to-twitter' ) . ' ';
413
  } else {
414
  $connection->post( $api, $status );
415
  $http_code = ( $connection ) ? $connection->http_code : 'failed';
416
- $notice = '';
417
- }
418
  }
419
  wpt_mail( 'Twitter Connection', print_r( $connection, 1 ) . " - $twit, $auth, $id, $media" );
420
  if ( $connection ) {
421
- if ( isset( $connection->http_header['x-access-level'] ) && $connection->http_header['x-access-level'] == 'read' ) {
 
422
  $supplement = sprintf( __( 'Your Twitter application does not have read and write permissions. Go to <a href="%s">your Twitter apps</a> to modify these settings.', 'wp-to-twitter' ), 'https://dev.twitter.com/apps/' );
423
  } else {
424
  $supplement = '';
@@ -426,65 +394,64 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
426
  $return = false;
427
  switch ( $http_code ) {
428
  case '100':
429
- $error = __( "100 Continue: Twitter received the header of your submission, but your server did not follow through by sending the body of the data.", 'wp-to-twitter' );
430
- break;
431
  case '200':
432
  $return = true;
433
- $error = __( "200 OK: Success!", 'wp-to-twitter' );
434
  update_option( 'wpt_authentication_missing', false );
435
  break;
436
  case '304':
437
- $error = __( "304 Not Modified: There was no new data to return", 'wp-to-twitter' );
438
  break;
439
  case '400':
440
- $error = __( "400 Bad Request: The request was invalid. This is the status code returned during rate limiting.", 'wp-to-twitter' );
441
  break;
442
  case '401':
443
- $error = __( "401 Unauthorized: Authentication credentials were missing or incorrect.", 'wp-to-twitter' );
444
  update_option( 'wpt_authentication_missing', "$auth" );
445
  break;
446
  case '403':
447
- $error = __( "403 Forbidden: The request is understood, but has been refused by Twitter.", 'wp-to-twitter' );
448
  break;
449
  case '404':
450
- $error = __( "404 Not Found: The URI requested is invalid or the resource requested does not exist.", 'wp-to-twitter' );
451
  break;
452
  case '406':
453
- $error = __( "406 Not Acceptable: Invalid Format Specified.", 'wp-to-twitter' );
454
  break;
455
  case '422':
456
- $error = __( "422 Unprocessable Entity: The image uploaded could not be processed..", 'wp-to-twitter' );
457
  break;
458
  case '429':
459
- $error = __( "429 Too Many Requests: You have exceeded your rate limits.", 'wp-to-twitter' );
460
  break;
461
  case '500':
462
- $error = __( "500 Internal Server Error: Something is broken at Twitter.", 'wp-to-twitter' );
463
  break;
464
  case '502':
465
- $error = __( "502 Bad Gateway: Twitter is down or being upgraded.", 'wp-to-twitter' );
466
  break;
467
  case '503':
468
- $error = __( "503 Service Unavailable: The Twitter servers are up, but overloaded with requests - Please try again later.", 'wp-to-twitter' );
469
  break;
470
  case '504':
471
  $error = __( "504 Gateway Timeout: The Twitter servers are up, but the request couldn't be serviced due to some failure within our stack. Try again later.", 'wp-to-twitter' );
472
  break;
473
  default:
474
- $error = __( "<strong>Code $http_code</strong>: Twitter did not return a recognized response code.", 'wp-to-twitter' );
 
475
  break;
476
  }
477
  $body = $connection->body;
478
- $error_code = ( $http_code != 200 ) ? $body->errors[0]->code : '';
479
- $error_message = ( $http_code != 200 ) ? $body->errors[0]->message : '';
480
- $error_supplement = ($error_code != '' ) ? " (Error Code: " . $error_code . ': ' . $error_message . ")" : '';
481
- $error .= ( $supplement != '' ) ? " $supplement" : '';
482
  $error .= $error_supplement;
483
- // debugging
484
- wpt_mail( "Twitter Response: $http_code", "$error" ); // DEBUG
485
- // end debugging
486
- // only save last Tweet if successful
487
- if ( $http_code == '200' ) {
488
  if ( ! $auth ) {
489
  update_option( 'jd_last_tweet', $twit );
490
  } else {
@@ -492,7 +459,7 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
492
  }
493
  }
494
  wpt_saves_error( $id, $auth, $twit, $error, $http_code, time() );
495
- if ( $http_code == '200' ) {
496
  $jwt = get_post_meta( $id, '_jd_wp_twitter', true );
497
  if ( ! is_array( $jwt ) ) {
498
  $jwt = array();
@@ -505,7 +472,7 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
505
  update_post_meta( $id, '_jd_wp_twitter', $jwt );
506
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
507
  // schedule a one-time promotional box for 4 weeks after first successful Tweet.
508
- if ( get_option( 'wpt_promotion_scheduled' ) == false ) {
509
  wp_schedule_single_event( time() + ( 60 * 60 * 24 * 7 * 4 ), 'wpt_schedule_promotion_action' );
510
  update_option( 'wpt_promotion_scheduled', 1 );
511
  }
@@ -514,7 +481,7 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
514
  if ( ! $return ) {
515
  wpt_set_log( 'wpt_status_message', $id, $error );
516
  } else {
517
- do_action( 'wpt_tweet_posted', $connection, $id );
518
  wpt_set_log( 'wpt_status_message', $id, $notice . __( 'Tweet sent successfully.', 'wp-to-twitter' ) );
519
  }
520
 
@@ -530,9 +497,9 @@ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false
530
 
531
  /**
532
  * For servers without PEAR normalize installed, approximates normalization. With normalizer, executes normalization on string.
533
- *
534
- * @param string Text to normalize
535
- *
536
  * @return string Normalized text.
537
  */
538
  function wpt_normalize( $string ) {
@@ -545,17 +512,17 @@ function wpt_normalize( $string ) {
545
  } else {
546
  $normalizer = new WPT_Normalizer();
547
  if ( $normalizer->isNormalized( $string ) ) {
548
- return $string;
549
  }
550
-
551
  return $normalizer->normalize( $string );
552
  }
553
  }
554
 
555
  /**
556
  * Test URL to see if is pointing to https location.
557
- *
558
- * @param string $url
559
  *
560
  * @return boolean
561
  */
@@ -568,12 +535,17 @@ function wpt_is_ssl( $url ) {
568
  }
569
 
570
  /**
571
- * Deprecated; still used if configured. Uses old option 'tweet_categories' and verifies whether category of current post allows it to be Tweeted.
 
 
 
 
 
572
  */
573
  function wpt_in_allowed_category( $array ) {
574
  $allowed_categories = get_option( 'tweet_categories' );
575
  if ( is_array( $array ) && is_array( $allowed_categories ) ) {
576
- $common = @array_intersect( $array, $allowed_categories );
577
  if ( count( $common ) >= 1 ) {
578
  return true;
579
  } else {
@@ -586,47 +558,48 @@ function wpt_in_allowed_category( $array ) {
586
 
587
  /**
588
  * Builds array of post info for use in Tweet functions.
589
- *
590
  * @param integer $post_ID Post ID.
591
  *
592
- * @return array Post data used in Tweet functions.
593
  */
594
  function wpt_post_info( $post_ID ) {
595
  $encoding = get_option( 'blog_charset' );
596
- if ( $encoding == '' ) {
597
  $encoding = 'UTF-8';
598
  }
599
  $post = get_post( $post_ID );
600
  $category_ids = false;
601
  $values = array();
602
  $values['id'] = $post_ID;
603
- // get post author
604
  $values['postinfo'] = $post;
605
  $values['postContent'] = $post->post_content;
606
  $values['authId'] = $post->post_author;
607
  $postdate = $post->post_date;
608
- $altformat = "Y-m-d H:i:s";
609
- $dateformat = ( get_option( 'jd_date_format' ) == '' ) ? get_option( 'date_format' ) : get_option( 'jd_date_format' );
610
  $thisdate = mysql2date( $dateformat, $postdate );
611
- $altdate = mysql2date( $altformat, $postdate );
612
  $values['_postDate'] = $altdate;
613
  $values['postDate'] = $thisdate;
614
  $moddate = $post->post_modified;
615
- $values['_postModified'] = mysql2date( $altformat, $moddate );
616
  $values['postModified'] = mysql2date( $dateformat, $moddate );
617
- // get first category
618
- $category = $cat_desc = null;
 
619
  $categories = get_the_category( $post_ID );
620
- $cats = $cat_descs = array();
 
621
  if ( is_array( $categories ) ) {
622
  if ( count( $categories ) > 0 ) {
623
  $category = $categories[0]->cat_name;
624
  $cat_desc = $categories[0]->description;
625
  }
626
- foreach ( $categories AS $cat ) {
627
  $category_ids[] = $cat->term_id;
628
- $cats[] = $cat->cat_name;
629
- $cat_descs[] = $cat->description;
630
  }
631
  $cat_names = implode( ' ', apply_filters( 'wpt_twitter_category_names', $cats ) );
632
  $cat_descs = implode( ' ', apply_filters( 'wpt_twitter_category_descs', $cat_descs ) );
@@ -641,17 +614,17 @@ function wpt_post_info( $post_ID ) {
641
  $values['category'] = html_entity_decode( $category, ENT_COMPAT, $encoding );
642
  $values['cat_desc'] = html_entity_decode( $cat_desc, ENT_COMPAT, $encoding );
643
  $excerpt_length = get_option( 'jd_post_excerpt' );
644
- $post_excerpt = ( trim( $post->post_excerpt ) == "" ) ? @mb_substr( strip_tags( strip_shortcodes( $post->post_content ) ), 0, $excerpt_length ) : @mb_substr( strip_tags( strip_shortcodes( $post->post_excerpt ) ), 0, $excerpt_length );
645
  $values['postExcerpt'] = html_entity_decode( $post_excerpt, ENT_COMPAT, $encoding );
646
  $thisposttitle = $post->post_title;
647
- if ( $thisposttitle == "" && isset( $_POST['title'] ) ) {
648
  $thisposttitle = $_POST['title'];
649
  }
650
- $thisposttitle = strip_tags( apply_filters( 'the_title', stripcslashes( $thisposttitle ) ) );
651
- // These are common sequences that may not be fixed by html_entity_decode due to double encoding
652
  $search = array( '&apos;', '&#039;', '&quot;', '&#034;', '&amp;', '&#038;' );
653
  $replace = array( "'", "'", '"', '"', '&', '&' );
654
- $thisposttitle = str_replace( $search, $replace, $thisposttitle );
655
  $values['postTitle'] = html_entity_decode( $thisposttitle, ENT_QUOTES, $encoding );
656
  $values['postLink'] = wpt_link( $post_ID );
657
  $values['blogTitle'] = get_bloginfo( 'name' );
@@ -660,19 +633,20 @@ function wpt_post_info( $post_ID ) {
660
  $values['postType'] = $post->post_type;
661
  /**
662
  * Filters post array to insert custom data that can be used in Tweet process.
663
- *
664
- * @param array $values
665
- * @param integer $post_ID
666
- * @return array $values
667
  */
668
- $values = apply_filters( 'wpt_post_info', $values, $post_ID );
669
 
670
  return $values;
671
  }
672
 
673
  /**
674
  * Retrieve stored short URL.
675
- * @param $post_id
 
676
  *
677
  * @return mixed
678
  */
@@ -681,25 +655,26 @@ function wpt_short_url( $post_id ) {
681
  if ( ! $post_id ) {
682
  $post_id = $post_ID;
683
  }
684
- $short = get_post_meta( $post_id, '_wpt_short_url', true );
685
-
 
686
  return $short;
687
  }
688
 
689
  /**
690
  * Identify whether a post should be uploading media. Test settings and verify whether post has images that can be uploaded.
691
  *
692
- * @param integer $post_ID
693
- * @param array $post_info
694
  * @return boolean
695
- */
696
  function wpt_post_with_media( $post_ID, $post_info = array() ) {
697
  $return = false;
698
- if ( isset( $post_info['wpt_image'] ) && $post_info['wpt_image'] == 1 ) {
699
  return $return;
700
  }
701
 
702
- if ( ! function_exists( 'wpt_pro_exists' ) || get_option( 'wpt_media' ) != '1' ) {
703
  $return = false;
704
  } else {
705
  if ( has_post_thumbnail( $post_ID ) || wpt_post_attachment( $post_ID ) ) {
@@ -711,6 +686,12 @@ function wpt_post_with_media( $post_ID, $post_info = array() ) {
711
  }
712
 
713
  /**
 
 
 
 
 
 
714
  * @deprecated
715
  */
716
  function wpt_category_limit( $post_type, $post_info, $post_ID ) {
@@ -718,37 +699,45 @@ function wpt_category_limit( $post_type, $post_info, $post_ID ) {
718
  $continue = true;
719
  if ( in_array( 'category', $post_type_cats ) ) {
720
  // 'category' is assigned to this post type, so apply filters.
721
- if ( get_option( 'jd_twit_cats' ) == '1' ) {
722
  $continue = ( ! wpt_in_allowed_category( $post_info['categoryIds'] ) ) ? true : false;
723
  } else {
724
  $continue = ( wpt_in_allowed_category( $post_info['categoryIds'] ) ) ? true : false;
725
  }
726
  }
727
 
728
- $continue = ( get_option( 'limit_categories' ) == '0' ) ? true : $continue;
729
- $args = array( 'type' => $post_type, 'info' => $post_info, 'id' => $post_ID );
 
 
 
 
730
 
731
  return apply_filters( 'wpt_filter_terms', $continue, $args );
732
  }
733
 
734
  /**
735
- * Set up a Tweet to be sent.
736
- *
737
- * @param integer $post_ID Post ID.
738
- * @param string $type Publishing context (publishing, scheduled, xmlrpc, etc.)
739
- *
740
- * @return integer $post_ID
741
  */
742
  function wpt_tweet( $post_ID, $type = 'instant' ) {
743
  if ( wp_is_post_autosave( $post_ID ) || wp_is_post_revision( $post_ID ) ) {
744
  return $post_ID;
745
  }
746
-
747
  wpt_check_version();
748
- $tweet_this = get_post_meta( $post_ID, '_jd_tweet_this', true );
749
- $newpost = $oldpost = $is_inline_edit = false;
750
- $sentence = $template = $nptext = '';
751
- if ( get_option( 'wpt_inline_edits' ) != 1 ) {
 
 
 
 
752
  if ( isset( $_POST['_inline_edit'] ) || isset( $_REQUEST['bulk_edit'] ) ) {
753
  return false;
754
  }
@@ -757,109 +746,108 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
757
  $is_inline_edit = true;
758
  }
759
  }
760
- if ( get_option( 'jd_tweet_default' ) == 0 ) {
761
- $default = ( $tweet_this != 'no' ) ? true : false;
762
  } else {
763
- $default = ( $tweet_this == 'yes' ) ? true : false;
764
  }
765
- wpt_mail( "1: Tweet Template", "$tweet_this / (Original: " . get_option( 'jd_tweet_default' ) . ") / $type" ); // DEBUG
766
  if ( $default ) { // default switch: depend on default settings.
767
  $post_info = wpt_post_info( $post_ID );
768
  $media = wpt_post_with_media( $post_ID, $post_info );
769
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
770
- $auth = ( get_option( 'wpt_cotweet_lock' ) == 'false' || ! get_option( 'wpt_cotweet_lock' ) ) ? $post_info['authId'] : get_option( 'wpt_cotweet_lock' );
771
  } else {
772
  $auth = $post_info['authId'];
773
  }
774
- /* debug data */
775
- wpt_mail( "2: POST Debug Data", "Post_Info: " . print_r( $post_info, 1 ) . " / $type" );
776
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true && function_exists( 'wpt_filter_post_info' ) ) {
777
  $filter = wpt_filter_post_info( $post_info );
778
- if ( $filter == true ) {
779
- wpt_mail( "3: Post caught by wpt_filter_post_info", print_r( $post_info, 1 ) . " / $type" );
780
 
781
  return false;
782
  }
783
  }
784
- /* Filter Tweet based on POST data -- allows custom filtering of unknown plug-ins, etc. */
785
  $filter = apply_filters( 'wpt_filter_post_data', false, $_POST );
786
  if ( $filter ) {
787
  return false;
788
  }
789
  $post_type = $post_info['postType'];
790
- if ( $type == 'future' || get_post_meta( $post_ID, 'wpt_publishing' ) == 'future' ) {
791
- $new = 1; // if this is a future action, then it should be published regardless of relationship
792
- wpt_mail( "4a: Is a future post", print_r( $post_info, 1 ) . " / $type" );
793
  delete_post_meta( $post_ID, 'wpt_publishing' );
794
  } else {
795
  // if the post modified date and the post date are the same, this is new.
796
- // true if first date before or equal to last date
797
  $new = wpt_date_compare( $post_info['_postModified'], $post_info['_postDate'] );
798
  }
799
- // post is not previously published but has been backdated:
800
- // (post date is edited, but save option is 'publish')
801
- if ( $new == 0 && ( isset( $_POST['edit_date'] ) && $_POST['edit_date'] == 1 && ! isset( $_POST['save'] ) ) ) {
802
  $new = 1;
803
  }
804
- // can't catch posts that were set to a past date as a draft, then published.
805
  $post_type_settings = get_option( 'wpt_post_types' );
806
  $post_types = array_keys( $post_type_settings );
807
  if ( in_array( $post_type, $post_types ) ) {
808
- // identify whether limited by category/taxonomy
809
  $continue = wpt_category_limit( $post_type, $post_info, $post_ID );
810
- if ( $continue == false ) {
811
  return false;
812
  }
813
- // create Tweet and ID whether current action is edit or new
814
- $cT = get_post_meta( $post_ID, '_jd_twitter', true );
815
- if ( isset( $_POST['_jd_twitter'] ) && $_POST['_jd_twitter'] != '' ) {
816
- $cT = $_POST['_jd_twitter'];
817
  }
818
- $customTweet = ( $cT != '' ) ? stripcslashes( trim( $cT ) ) : '';
819
  // if ops is set and equals 'publish', this is being edited. Otherwise, it's a new post.
820
- if ( $new == 0 || $is_inline_edit == true ) {
821
- // if this is an old post and editing updates are enabled
822
- if ( get_option( 'jd_tweet_default_edit' ) == 1 ) {
823
  $tweet_this = apply_filters( 'wpt_tweet_this_edit', $tweet_this, $_POST );
824
- if ( $tweet_this != 'yes' ) {
825
  return false;
826
  }
827
  }
828
- wpt_mail( "4b: Is edited post", "Tweet this: " . print_r( $post_info, 1 ) . " / $type" ); // DEBUG
829
- if ( $post_type_settings[ $post_type ]['post-edited-update'] == '1' ) {
830
  $nptext = stripcslashes( $post_type_settings[ $post_type ]['post-edited-text'] );
831
  $oldpost = true;
832
  }
833
  } else {
834
- wpt_mail( "4c: Is new post", "Tweet this: " . print_r( $post_info, 1 ) . " / $type" ); // DEBUG
835
- if ( $post_type_settings[ $post_type ]['post-published-update'] == '1' ) {
836
  $nptext = stripcslashes( $post_type_settings[ $post_type ]['post-published-text'] );
837
  $newpost = true;
838
  }
839
  }
840
  if ( $newpost || $oldpost ) {
841
- $template = ( $customTweet != "" ) ? $customTweet : $nptext;
842
  $sentence = jd_truncate_tweet( $template, $post_info, $post_ID );
843
- wpt_mail( "5: Tweet Truncated", "Truncated Tweet: $sentence / $template / $type" ); // DEBUG
844
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
845
  $sentence2 = jd_truncate_tweet( $template, $post_info, $post_ID, false, $auth );
846
  }
847
  }
848
- if ( $sentence != '' ) {
849
- // WPT PRO //
850
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
851
  $wpt_selected_users = $post_info['wpt_authorized_users'];
852
- /* set up basic author/main account values */
853
  $auth_verified = wtt_oauth_test( $auth, 'verify' );
854
- if ( empty( $wpt_selected_users ) && get_option( 'jd_individual_twitter_users' ) == 1 ) {
855
  $wpt_selected_users = ( $auth_verified ) ? array( $auth ) : array( false );
856
  }
857
- if ( $post_info['wpt_cotweet'] == 1 || get_option( 'jd_individual_twitter_users' ) != 1 || in_array( 'main', $wpt_selected_users ) ) {
858
  $wpt_selected_users['main'] = false;
859
  }
860
- // filter selected users before using
861
  $wpt_selected_users = apply_filters( 'wpt_filter_users', $wpt_selected_users, $post_info );
862
- if ( $post_info['wpt_delay_tweet'] == 0 || $post_info['wpt_delay_tweet'] == '' || $post_info['wpt_no_delay'] == 'on' ) {
863
  foreach ( $wpt_selected_users as $acct ) {
864
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
865
  wpt_post_to_twitter( $sentence2, $acct, $post_ID, $media );
@@ -867,35 +855,35 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
867
  }
868
  } else {
869
  foreach ( $wpt_selected_users as $acct ) {
870
- $acct = ( $acct == 'main' ) ? false : $acct;
871
  $offset = ( $auth != $acct ) ? apply_filters( 'wpt_random_delay', rand( 60, 480 ) ) : 0;
872
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
873
- $time = apply_filters( 'wpt_schedule_delay', ( (int) $post_info['wpt_delay_tweet'] ) * 60, $acct );
874
  wp_schedule_single_event( time() + $time + $offset, 'wpt_schedule_tweet_action', array(
875
- 'id' => $acct,
876
- 'sentence' => $sentence,
877
- 'rt' => 0,
878
- 'post_id' => $post_ID
879
- ) );
880
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
881
  $author_id = ( $acct ) ? "#$acct" : 'Main';
882
  wpt_mail( "7a: Tweet Scheduled for author $author_id", print_r( array(
883
- 'id' => $acct,
884
- 'sentence' => $sentence,
885
- 'rt' => 0,
886
- 'post_id' => $post_ID,
887
- 'timestamp' => time() + $time + $offset,
888
- 'current_time' => time(),
889
- 'timezone' => get_option( 'gmt_offset' ),
890
- 'timestamp_string' => date( 'Y-m-d H:i:s', time() + $time + $offset ),
891
- 'current_time_string' => date( 'Y-m-d H:i:s', time() ),
892
- ), 1 ) ); // DEBUG
893
  }
894
  }
895
  }
896
  }
897
- /* This cycle handles scheduling the automatic retweets */
898
- if ( $post_info['wpt_retweet_after'] != 0 && $post_info['wpt_no_repost'] != 'on' ) {
899
  $repeat = $post_info['wpt_retweet_repeat'];
900
  $first = true;
901
  foreach ( $wpt_selected_users as $acct ) {
@@ -905,17 +893,17 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
905
  if ( $continue ) {
906
  $retweet = apply_filters( 'wpt_set_retweet_text', $template, $i );
907
  $retweet = jd_truncate_tweet( $retweet, $post_info, $post_ID, true, $acct );
908
- // add original delay to schedule
909
  $delay = ( isset( $post_info['wpt_delay_tweet'] ) ) ? ( (int) $post_info['wpt_delay_tweet'] ) * 60 : 0;
910
- /* Don't delay the first Tweet of the group */
911
- $offset = ( $first == true ) ? 0 : rand( 60, 240 ); // delay each co-tweet by 1-4 minutes
912
- $time = apply_filters( 'wpt_schedule_retweet', ( $post_info['wpt_retweet_after'] ) * ( 60 * 60 ) * $i, $acct, $i, $post_info );
913
  wp_schedule_single_event( time() + $time + $offset + $delay, 'wpt_schedule_tweet_action', array(
914
- 'id' => $acct,
915
- 'sentence' => $retweet,
916
- 'rt' => $i,
917
- 'post_id' => $post_ID
918
- ) );
919
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
920
  if ( $acct ) {
921
  $author_id = "#$acct";
@@ -923,19 +911,13 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
923
  $author_id = 'Main';
924
  }
925
  wpt_mail( "7b: Retweet Scheduled for author $author_id", print_r( array(
926
- 'id' => $acct,
927
- 'sentence' => $retweet,
928
- 'rt' => $i,
929
- 'post_id' => $post_ID,
930
- 'timestamp' => time() + $time + $offset + $delay,
931
- 'time' => $time,
932
- 'offset' => $offset,
933
- 'delay' => $delay,
934
- 'current_time' => time(),
935
- 'timezone' => get_option( 'gmt_offset' ),
936
- 'timestamp_string' => date( 'Y-m-d H:i:s', time() + $time + $offset + $delay ),
937
- 'current_time_string' => date( 'Y-m-d H:i:s', time() ),
938
- ), 1 ), true ); // DEBUG
939
  }
940
  $tweet_limit = apply_filters( 'wpt_tweet_repeat_limit', 4, $post_ID );
941
  if ( $i == $tweet_limit ) {
@@ -950,11 +932,11 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
950
  } else {
951
  wpt_post_to_twitter( $sentence, false, $post_ID, $media );
952
  }
953
- // END WPT PRO //
954
  }
955
  } else {
956
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
957
- wpt_mail( "3c: Not a Tweeted post type", "Post_Info: " . print_r( $post_info, 1 ) . " / $type" );
958
  }
959
 
960
  return $post_ID;
@@ -966,66 +948,67 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
966
 
967
  /**
968
  * Send Tweets on links in link manager. Only active if Link plug-in is installed.
969
- *
970
- * @param integer $link_ID Database ID for link.
971
- *
972
  * @return mixed boolean/integer link ID if successful, false if failure.
973
  */
974
- function wpt_twit_link( $link_ID ) {
975
  wpt_check_version();
976
  $thislinkprivate = $_POST['link_visible'];
977
- if ( $thislinkprivate != 'N' ) {
978
- $thislinkname = stripcslashes( $_POST['link_name'] );
979
  $thispostlink = $_POST['link_url'];
980
  $thislinkdescription = stripcslashes( $_POST['link_description'] );
981
  $sentence = stripcslashes( get_option( 'newlink-published-text' ) );
982
- $sentence = str_ireplace( "#title#", $thislinkname, $sentence );
983
- $sentence = str_ireplace( "#description#", $thislinkdescription, $sentence );
984
 
985
  if ( mb_strlen( $sentence ) > 118 ) {
986
  $sentence = mb_substr( $sentence, 0, 114 ) . '...';
987
  }
988
  $shrink = apply_filters( 'wptt_shorten_link', $thispostlink, $thislinkname, false, 'link' );
989
- if ( stripos( $sentence, "#url#" ) === false ) {
990
- $sentence = $sentence . " " . $shrink;
991
  } else {
992
- $sentence = str_ireplace( "#url#", $shrink, $sentence );
993
  }
994
-
995
- if ( stripos( $sentence, "#longurl#" ) === false ) {
996
- $sentence = $sentence . " " . $thispostlink;
997
  } else {
998
- $sentence = str_ireplace( "#longurl#", $thispostlink, $sentence );
999
  }
1000
-
1001
- if ( $sentence != '' ) {
1002
- wpt_post_to_twitter( $sentence, false, $link_ID );
1003
  }
1004
 
1005
- return $link_ID;
1006
  } else {
1007
  return false;
1008
  }
1009
  }
1010
 
1011
- /**
1012
  * Generate hash tags from tags set on post.
1013
- *
1014
- * @param integer $post_ID Post ID.
1015
  *
1016
- * @return string $hashtags Hashtags in format needed for Tweet.
 
 
1017
  */
1018
  function wpt_generate_hash_tags( $post_ID ) {
1019
  $hashtags = '';
1020
- $term_meta = $t_id = false;
 
1021
  $max_tags = get_option( 'jd_max_tags' );
1022
  $max_characters = get_option( 'jd_max_characters' );
1023
- $max_characters = ( $max_characters == 0 || $max_characters == "" ) ? 100 : $max_characters + 1;
1024
- if ( $max_tags == 0 || $max_tags == "" ) {
1025
  $max_tags = 100;
1026
  }
1027
- $use_cats = ( get_option( 'wpt_use_cats' ) == '1' ) ? true : false;
1028
- $tags = ( $use_cats == true ) ? wp_get_post_categories( $post_ID, array( 'fields' => 'all' ) ) : get_the_tags( $post_ID );
1029
  $tags = apply_filters( 'wpt_hash_source', $tags, $post_ID );
1030
  if ( $tags && count( $tags ) > 0 ) {
1031
  $i = 1;
@@ -1034,25 +1017,34 @@ function wpt_generate_hash_tags( $post_ID ) {
1034
  $t_id = $value->term_id;
1035
  $term_meta = get_option( "wpt_taxonomy_$t_id" );
1036
  }
1037
- if ( get_option( 'wpt_tag_source' ) == 'slug' ) {
1038
  $tag = $value->slug;
1039
  } else {
1040
  $tag = $value->name;
1041
  }
1042
  $strip = get_option( 'jd_strip_nonan' );
1043
- $search = "/[^\p{L}\p{N}\s]/u";
1044
  $replace = get_option( 'jd_replace_character' );
1045
- $replace = ( $replace == "[ ]" || $replace == "" ) ? "" : $replace;
1046
- $tag = str_ireplace( " ", $replace, trim( $tag ) );
1047
  $tag = preg_replace( '/[\/]/', $replace, $tag ); // remove forward slashes.
1048
- $tag = ( $strip == '1' ) ? preg_replace( $search, $replace, $tag ) : $tag;
1049
-
1050
  switch ( $term_meta ) {
1051
- case 1 : $newtag = "#$tag"; break;
1052
- case 2 : $newtag = "$$tag"; break;
1053
- case 3 : $newtag = ''; break;
1054
- case 4 : $newtag = $tag; break;
1055
- default: $newtag = apply_filters( 'wpt_tag_default', "#", $t_id ) . $tag;
 
 
 
 
 
 
 
 
 
1056
  }
1057
  if ( mb_strlen( $newtag ) > 2 && ( mb_strlen( $newtag ) <= $max_characters ) && ( $i <= $max_tags ) ) {
1058
  $hashtags .= "$newtag ";
@@ -1062,14 +1054,14 @@ function wpt_generate_hash_tags( $post_ID ) {
1062
  }
1063
  $hashtags = trim( $hashtags );
1064
  if ( mb_strlen( $hashtags ) <= 1 ) {
1065
- $hashtags = "";
1066
  }
1067
 
1068
  return $hashtags;
1069
  }
1070
 
1071
  add_action( 'admin_menu', 'wpt_add_twitter_outer_box' );
1072
- /**
1073
  * Set up post meta box.
1074
  */
1075
  function wpt_add_twitter_outer_box() {
@@ -1079,7 +1071,7 @@ function wpt_add_twitter_outer_box() {
1079
  if ( function_exists( 'add_meta_box' ) ) {
1080
  if ( is_array( $wpt_post_types ) ) {
1081
  foreach ( $wpt_post_types as $key => $value ) {
1082
- if ( $value['post-published-update'] == 1 || $value['post-edited-update'] == 1 ) {
1083
  add_meta_box( 'wp2t', 'WP to Twitter', 'wpt_add_twitter_inner_box', $key, 'side' );
1084
  }
1085
  }
@@ -1089,7 +1081,7 @@ function wpt_add_twitter_outer_box() {
1089
 
1090
 
1091
  add_action( 'admin_menu', 'wpt_add_twitter_debug_box' );
1092
- /**
1093
  * Set up post meta box.
1094
  */
1095
  function wpt_add_twitter_debug_box() {
@@ -1100,18 +1092,20 @@ function wpt_add_twitter_debug_box() {
1100
  if ( function_exists( 'add_meta_box' ) ) {
1101
  if ( is_array( $wpt_post_types ) ) {
1102
  foreach ( $wpt_post_types as $key => $value ) {
1103
- if ( $value['post-published-update'] == 1 || $value['post-edited-update'] == 1 ) {
1104
  add_meta_box( 'wp2t-debug', 'WP to Twitter Debugging', 'wpt_show_debug', $key, 'advanced' );
1105
  }
1106
  }
1107
  }
1108
  }
1109
  }
1110
- }
1111
-
1112
-
1113
  /**
1114
  * Print post meta box
 
 
1115
  */
1116
  function wpt_add_twitter_inner_box( $post ) {
1117
  if ( current_user_can( 'wpt_can_tweet' ) ) {
@@ -1120,52 +1114,55 @@ function wpt_add_twitter_inner_box( $post ) {
1120
  <?php
1121
  $tweet_status = '';
1122
  $options = get_option( 'wpt_post_types' );
1123
- $type = $post->post_type;
1124
- $status = $post->post_status;
1125
- $post_id = $post->ID;
1126
-
1127
- $tweet_this = get_post_meta( $post_id, '_jd_tweet_this', true );
1128
  if ( ! $tweet_this ) {
1129
- $tweet_this = ( get_option( 'jd_tweet_default' ) == '1' ) ? 'no' : 'yes';
1130
  }
1131
- if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && get_option( 'jd_tweet_default_edit' ) == '1' && $status == 'publish' ) {
1132
  $tweet_this = 'no';
1133
  }
1134
- if ( isset( $_REQUEST['message'] ) && $_REQUEST['message'] != 10 ) { // don't display when draft is updated or if no message
1135
- if ( ! ( ( $_REQUEST['message'] == 1 ) && ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) ) && $tweet_this != 'no' ) {
 
1136
  $log = wpt_log( 'wpt_status_message', $post_id );
1137
- $class = ( $log != __( 'Tweet sent successfully.', 'wp-to-twitter' ) ) ? 'error' : 'updated';
1138
- if ( $log != '' ) {
1139
  echo "<div class='$class'><p>$log</p></div>";
1140
  }
1141
  }
1142
  }
1143
- $previous_tweets = get_post_meta( $post_id, '_jd_wp_twitter', true );
1144
- $failed_tweets = get_post_meta( $post_id, '_wpt_failed' );
1145
- $tweet = esc_attr( stripcslashes( get_post_meta( $post_id, '_jd_twitter', true ) ) );
1146
- $tweet = apply_filters( 'wpt_user_text', $tweet, $status );
1147
- $template = ( $status == 'publish' ) ? $options[ $type ]['post-edited-text'] : $options[ $type ]['post-published-text'];
1148
 
1149
- if ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) {
 
1150
  $tweet_status = sprintf( __( '%s will not be Tweeted on update.', 'wp-to-twitter' ), ucfirst( $type ) );
1151
  }
1152
 
1153
- if ( $status == 'publish' && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1154
  ?>
1155
  <div class='tweet-buttons'>
1156
  <button type='button' class='tweet button-primary' data-action='tweet'><span class='dashicons dashicons-twitter' aria-hidden='true'></span><?php _e( 'Tweet Now', 'wp-to-twitter' ); ?></button>
1157
- <?php if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) { ?>
1158
- <button type='button' class='tweet schedule button-secondary' data-action='schedule' disabled><?php _e( 'Schedule', 'wp-to-twitter' ); ?></button>
1159
- <button type='button' class='time button-secondary'>
1160
- <span class="dashicons dashicons-clock" aria-hidden="true"></span><span class="screen-reader-text"><?php _e( 'Set Date/Time', 'wp-to-twitter' ); ?></span>
1161
- </button>
1162
- <div id="jts">
1163
- <label for='wpt_date'><?php _e( 'Date', 'wp-to-twitter' ); ?></label>
1164
- <input type='date' value='' class='wpt_date date' name='wpt_datetime' id='wpt_date' data-value='<?php echo date( 'Y-m-d', current_time( 'timestamp' ) ); ?>' /><br/>
1165
- <label for='wpt_time'><?php _e( 'Time', 'wp-to-twitter' ); ?></label>
1166
- <input type='text' value='<?php echo date_i18n( 'h:s a', current_time( 'timestamp' ) + 3600 ); ?>' class='wpt_time time' name='wpt_datetime' id='wpt_time'/>
1167
- </div>
1168
- <?php } ?>
 
 
 
 
1169
  <div class='wpt_log' aria-live='assertive'></div>
1170
  </div>
1171
  <?php
@@ -1173,17 +1170,17 @@ function wpt_add_twitter_inner_box( $post ) {
1173
  if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1174
  ?>
1175
  <p class='jtw'>
1176
- <label for="jtw"><?php _e( "Custom Twitter Post", 'wp-to-twitter', 'wp-to-twitter' ) ?></label><br/>
1177
  <textarea class="wpt_tweet_box" name="_jd_twitter" id="jtw" rows="2" cols="60"><?php echo esc_attr( $tweet ); ?></textarea>
1178
- <?php echo apply_filters( 'wpt_custom_box', '', $tweet, $post_id ); ?>
1179
  </p>
1180
  <?php
1181
  $expanded = $template;
1182
- if ( get_option( 'jd_twit_prepend' ) != "" ) {
1183
- $expanded = "<span title='" . __( 'Your prepended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_prepend' ) ) . "</span> " . $expanded;
1184
  }
1185
- if ( get_option( 'jd_twit_append' ) != "" ) {
1186
- $expanded = $expanded . " <span title='" . __( 'Your appended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_append' ) ) . "</span>";
1187
  }
1188
  ?>
1189
  <p class='template'>
@@ -1198,186 +1195,201 @@ function wpt_add_twitter_inner_box( $post ) {
1198
  echo "<label for='yourls_keyword'>" . __( 'YOURLS Custom Keyword', 'wp-to-twitter' ) . "</label> <input type='text' name='_yourls_keyword' id='yourls_keyword' value='$custom_keyword' />";
1199
  }
1200
  } else {
1201
- ?>
1202
- <input type="hidden" name='_jd_twitter' value='<?php esc_attr_e( $tweet ); ?>'/>
1203
  <?php
1204
  }
1205
  ?>
1206
  <div class='wpt-options'>
1207
- <?php
1208
- if ( $is_pro == 'pro' ) {
1209
- $pro_active = " class='active'";
1210
- $free_active = '';
1211
- } else {
1212
- $free_active = " class='active'";
1213
- $pro_active = '';
1214
- }
1215
- ?>
1216
- <ul class='tabs' role="tablist">
1217
- <?php if ( get_option( 'jd_individual_twitter_users' ) == 1 ) { ?>
1218
- <li><a href='#authors'<?php echo $pro_active; ?> aria-controls="authors" role="tab" id="tab_authors"><?php _e( 'Tweet to', 'wp-to-twitter' ); ?></a></li>
1219
- <?php } ?>
1220
- <li><a href='#custom' aria-controls="custom" role="tab" id="tab_custom"><?php _e( 'Options', 'wp-to-twitter' ); ?></a></li>
1221
- <li><a href='#notes'<?php echo $free_active; ?> aria-controls="notes" role="tab" id="tab_notes"><?php _e( 'Notes', 'wp-to-twitter' ); ?></a></li>
1222
- </ul>
1223
- <?php
1224
- /* WPT PRO OPTIONS */
1225
- if ( current_user_can( 'edit_others_posts' ) ) {
1226
- if ( get_option( 'jd_individual_twitter_users' ) == 1 ) {
1227
- echo "<div class='wptab' id='authors' aria-labelledby='tab_authors' role='tabpanel'>";
1228
- $selected = ( get_post_meta( $post_id, '_wpt_authorized_users', true ) ) ? get_post_meta( $post_id, '_wpt_authorized_users', true ) : array();
1229
- if ( function_exists( 'wpt_authorized_users' ) ) {
1230
- echo wpt_authorized_users( $selected );
1231
- do_action( 'wpt_authors_tab', $post_id, $selected );
 
 
 
 
 
1232
  } else {
1233
- echo "<p>";
1234
- if ( function_exists( 'wpt_pro_exists' ) ) {
1235
- printf( __( 'WP Tweets PRO allows you to select Twitter accounts. <a href="%s">Log in and download now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/account/' );
1236
- } else {
1237
- printf( __( 'Upgrade to WP Tweets PRO to select Twitter accounts! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' );
1238
- }
1239
- echo "</p>";
1240
  }
1241
- echo "</div>";
1242
- }
 
1243
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1244
  ?>
1245
- <div class='wptab' id='custom' aria-labelledby='tab_custom' role='tabpanel'><?php
1246
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true && ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) ) {
1247
- wpt_schedule_values( $post_id );
1248
- do_action( 'wpt_custom_tab', $post_id, 'visible' );
1249
- } else {
1250
- if ( ! function_exists( 'wpt_pro_exists' ) ) {
1251
- echo "<p>" . sprintf( __( 'Upgrade to WP Tweets PRO to configure options! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' ) . "</p>";
1252
- }
1253
  }
1254
  ?>
1255
- </div>
1256
- <?php
1257
- /* WPT PRO */
1258
- if ( ! current_user_can( 'wpt_twitter_custom' ) && ! current_user_can( 'manage_options' ) ) {
1259
- ?>
1260
- <div class='wptab' id='custom' aria-labelledby='tab_custom' role='tabpanel'>
1261
- <p><?php _e( 'Access to customizing WP to Twitter values is not allowed for your user role.', 'wp-to-twitter' ); ?></p>
1262
- <?php
1263
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
1264
- wpt_schedule_values( $post_id, 'hidden' );
1265
- do_action( 'wpt_custom_tab', $post_id, 'hidden' );
1266
- } ?>
1267
- </div>
1268
- <?php
1269
- }
1270
- if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1271
  ?>
1272
- <div class='wptab' id='notes' aria-labelledby='tab_notes' role='tabpanel'>
1273
- <p>
1274
- <?php _e( "Template Tags: <code>#url#</code>, <code>#title#</code>, <code>#post#</code>, <code>#category#</code>, <code>#date#</code>, <code>#modified#</code>, <code>#author#</code>, <code>#account#</code>, <code>#tags#</code>, <code>#blog#</code>, <code>#longurl#</code>.", 'wp-to-twitter' );
1275
- do_action( 'wpt_notes_tab', $post_id );
1276
- ?>
1277
- </p>
1278
- </div>
1279
- <?php
1280
- } ?>
1281
  </div>
1282
  <?php
1283
  if ( current_user_can( 'wpt_twitter_switch' ) || current_user_can( 'manage_options' ) ) {
1284
  // "no" means 'Don't Tweet' (is checked)
1285
- $nochecked = ( $tweet_this == 'no' ) ? ' checked="checked"' : '';
1286
- $yeschecked = ( $tweet_this == 'yes' ) ? ' checked="checked"' : '';
1287
- ?>
1288
- <p class='toggle-btn-group'>
1289
- <input type="radio" name="_jd_tweet_this" value="no" id="jtn"<?php echo $nochecked; ?> /><label for="jtn"><?php _e( "Don't Tweet", 'wp-to-twitter' ); ?></label>
1290
- <input type="radio" name="_jd_tweet_this" value="yes" id="jty"<?php echo $yeschecked; ?> /><label for="jty"><?php _e( "Tweet", 'wp-to-twitter' ); ?></label>
1291
- </p>
1292
  <?php
1293
  } else {
1294
- ?>
1295
- <input type='hidden' name='_jd_tweet_this' value='<?php echo $tweet_this; ?>'/>
1296
  <?php
1297
  }
1298
- wpt_show_tweets( $previous_tweets, $failed_tweets );
1299
  ?>
1300
  <p class="wpt-support">
1301
- <?php if ( ! function_exists( 'wpt_pro_exists' ) ) {
1302
- /* These aren't actually usages that require esc_url. But using it will give people the illusion that it does something. */
1303
  ?>
1304
- <strong><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) ?></a></strong> &raquo;
1305
- <?php } else { ?>
1306
- <a href="<?php echo esc_url( add_query_arg( 'tab', 'support', admin_url( 'admin.php?page=wp-tweets-pro' ) ) ); ?>#get-support"><?php _e( 'Get Support', 'wp-to-twitter', 'wp-to-twitter' ); ?></a> &raquo;
1307
- <?php } ?>
1308
- </p>
1309
- <?php
1310
- if ( $tweet_status != '' ) {
 
 
 
 
1311
  echo "<p class='disabled'>$tweet_status</p>";
1312
  }
1313
  ?>
1314
  </div>
1315
  <?php
1316
- } else { // permissions: this user isn't allowed to Tweet;
1317
- _e( 'Your role does not have the ability to Post Tweets from this site.', 'wp-to-twitter' ); ?> <input type='hidden' name='_jd_tweet_this' value='no'/> <?php
 
 
 
 
1318
  }
1319
  }
1320
 
1321
  /**
1322
  * Format history of Tweets attempted on current post.
1323
- *
1324
- * @param array $previous_tweets Array of successfully sent Tweets on this post.
1325
- * @param array $failed_tweets Array of failed Tweets sent on this post.
1326
- *
1327
- * @return string Formatted list of Tweets.
1328
  */
1329
- function wpt_show_tweets( $previous_tweets, $failed_tweets ) {
1330
- if ( ! is_array( $previous_tweets ) && $previous_tweets != '' ) {
 
 
 
1331
  $previous_tweets = array( 0 => $previous_tweets );
1332
  }
1333
  if ( ! empty( $previous_tweets ) || ! empty( $failed_tweets ) ) {
1334
- ?>
1335
- <hr>
1336
- <p class='panel-toggle'>
1337
- <a href='#wpt_tweet_history' class='history-toggle'><span class='dashicons dashicons-plus' aria-hidden="true"></span><?php _e( 'View Tweet History', 'wp-to-twitter' ); ?></a>
1338
- </p>
1339
- <div class='history'>
1340
- <p class='error'><em><?php _e( 'Previous Tweets', 'wp-to-twitter' ); ?>:</em></p>
1341
- <ul>
1342
- <?php
1343
- $has_history = false;
1344
- $hidden_fields = '';
1345
- if ( is_array( $previous_tweets ) ) {
1346
- foreach ( $previous_tweets as $previous_tweet ) {
1347
- if ( $previous_tweet != '' ) {
1348
- $has_history = true;
1349
- $hidden_fields .= "<input type='hidden' name='_jd_wp_twitter[]' value='" . esc_attr( $previous_tweet ) . "' />";
1350
- echo "<li>$previous_tweet <a href='http://twitter.com/intent/tweet?text=" . urlencode( $previous_tweet ) . "'>Retweet this</a></li>";
1351
- }
1352
- }
1353
- }
1354
- ?>
1355
- </ul>
1356
- <?php
1357
- $list = false;
1358
- $error_list = '';
1359
- if ( is_array( $failed_tweets ) ) {
1360
- foreach ( $failed_tweets as $failed_tweet ) {
1361
- if ( ! empty( $failed_tweet ) ) {
1362
- $ft = $failed_tweet['sentence'];
1363
- $reason = $failed_tweet['code'];
1364
- $error = $failed_tweet['error'];
1365
- $list = true;
1366
- $error_list .= "<li> <code>Error: $reason</code> $ft <a href='http://twitter.com/intent/tweet?text=" . urlencode( $ft ) . "'>Tweet this</a><br /><em>$error</em></li>";
1367
- }
1368
  }
1369
- if ( $list == true ) {
1370
- echo "<p class='error'><em>" . __( 'Failed Tweets', 'wp-to-twitter' ) . ":</em></p>
1371
- <ul>$error_list</ul>";
 
 
 
 
 
 
 
 
 
 
 
 
1372
  }
1373
  }
1374
- echo "<div>" . $hidden_fields . "</div>";
1375
- if ( $has_history || $list ) {
1376
- echo "<p><input type='checkbox' name='wpt_clear_history' id='wptch' value='clear' /> <label for='wptch'>" . __( 'Delete Tweet History', 'wp-to-twitter' ) . "</label></p>";
1377
  }
1378
- ?>
1379
- </div>
1380
- <?php
 
 
 
 
 
1381
  }
1382
  }
1383
 
@@ -1387,18 +1399,18 @@ add_action( 'admin_enqueue_scripts', 'wpt_admin_scripts', 10, 1 );
1387
  */
1388
  function wpt_admin_scripts() {
1389
  global $current_screen, $wpt_version;
1390
- if ( $current_screen->base == 'post' || $current_screen->id == 'wp-tweets-pro_page_wp-to-twitter-schedule' ) {
1391
  wp_enqueue_script( 'charCount', plugins_url( 'wp-to-twitter/js/jquery.charcount.js' ), array( 'jquery' ), $wpt_version );
1392
  }
1393
- if ( $current_screen->base == 'post' && isset( $_GET['post'] ) && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1394
  wp_enqueue_script( 'wpt.ajax', plugins_url( 'js/ajax.js', __FILE__ ), array( 'jquery' ), $wpt_version );
1395
  wp_localize_script( 'wpt.ajax', 'wpt_data', array(
1396
  'post_ID' => (int) $_GET['post'],
1397
  'action' => 'wpt_tweet',
1398
- 'security' => wp_create_nonce( 'wpt-tweet-nonce' )
1399
  ) );
1400
  }
1401
- if ( $current_screen->id == 'settings_page_wp-to-twitter/wp-to-twitter' || $current_screen->id == 'toplevel_page_wp-tweets-pro' ) {
1402
  wp_enqueue_script( 'wpt.tabs', plugins_url( 'js/tabs.js', __FILE__ ), array( 'jquery' ), $wpt_version );
1403
  wp_localize_script( 'wpt.tabs', 'firstItem', 'wpt_post' );
1404
  wp_localize_script( 'wpt.tabs', 'firstPerm', 'wpt_editor' );
@@ -1409,21 +1421,20 @@ function wpt_admin_scripts() {
1409
  add_action( 'wp_ajax_wpt_tweet', 'wpt_ajax_tweet' );
1410
  /**
1411
  * Handle Tweets sent via Ajax Tweet Now/Schedule Tweet buttons.
1412
- *
1413
- * @return string Confirmation message indicating success or failure of Tweeting.
1414
  */
1415
  function wpt_ajax_tweet() {
1416
  if ( ! check_ajax_referer( 'wpt-tweet-nonce', 'security', false ) ) {
1417
- echo "Invalid Security Check";
1418
  die;
1419
  }
1420
- $action = ( $_REQUEST['tweet_action'] == 'tweet' ) ? 'tweet' : 'schedule';
1421
- $authors = ( isset( $_REQUEST['tweet_auth'] ) && $_REQUEST['tweet_auth'] != null ) ? $_REQUEST['tweet_auth'] : false;
1422
- $upload = ( isset( $_REQUEST['tweet_upload'] ) && $_REQUEST['tweet_upload'] != null ) ? $_REQUEST['tweet_upload'] : 1;
1423
  $current_user = wp_get_current_user();
1424
  if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) {
1425
  if ( wtt_oauth_test( $current_user->ID, 'verify' ) ) {
1426
- $auth = $user_ID = $current_user->ID;
 
1427
  } else {
1428
  $auth = false;
1429
  $user_ID = $current_user->ID;
@@ -1433,44 +1444,45 @@ function wpt_ajax_tweet() {
1433
  $user_ID = $current_user->ID;
1434
  }
1435
 
1436
- $authors = ( is_array( $authors ) && !empty( $authors ) ) ? $authors : array( $auth );
1437
-
1438
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1439
  $options = get_option( 'wpt_post_types' );
1440
  $post_ID = intval( $_REQUEST['tweet_post_id'] );
1441
  $type = get_post_type( $post_ID );
1442
  $default = ( isset( $options[ $type ]['post-edited-text'] ) ) ? $options[ $type ]['post-edited-text'] : '';
1443
- $sentence = ( isset( $_REQUEST['tweet_text'] ) && trim( $_REQUEST['tweet_text'] ) != '' ) ? $_REQUEST['tweet_text'] : $default;
1444
  $sentence = stripcslashes( trim( $sentence ) );
1445
- $post_info = wpt_post_info( $post_ID );
1446
  $sentence = jd_truncate_tweet( $sentence, $post_info, $post_ID, false, $user_ID );
1447
  $schedule = ( isset( $_REQUEST['tweet_schedule'] ) ) ? strtotime( $_REQUEST['tweet_schedule'] ) : rand( 60, 240 );
1448
  $print_schedule = date_i18n( get_option( 'date_format' ) . ' @ ' . get_option( 'time_format' ), $schedule );
1449
  $offset = ( 60 * 60 * get_option( 'gmt_offset' ) );
1450
  $schedule = $schedule - $offset;
1451
- $media = ( $upload == 1 ) ? false: true; // this is correct; the boolean logic is reversed. Blah.
1452
-
1453
- foreach( $authors as $auth ) {
1454
-
1455
- $auth = ( $auth == 'main' ) ? false : $auth;
1456
-
1457
  switch ( $action ) {
1458
- case 'tweet' :
1459
  wpt_post_to_twitter( $sentence, $auth, $post_ID, $media );
1460
  break;
1461
- case 'schedule' :
1462
  wp_schedule_single_event( $schedule, 'wpt_schedule_tweet_action', array(
1463
- 'id' => $auth,
1464
- 'sentence' => $sentence,
1465
- 'rt' => 0,
1466
- 'post_id' => $post_ID
1467
- ) );
1468
  break;
1469
  }
1470
- $return = ( $action == 'tweet' ) ? wpt_log( 'wpt_status_message', $post_ID ) : sprintf( __( "Tweet scheduled: '%s' for %s", 'wp-tweets-pro' ), $sentence, $print_schedule );
 
1471
  echo $return;
1472
  if ( count( $authors ) > 1 ) {
1473
- echo "<br />";
1474
  }
1475
  }
1476
  } else {
@@ -1481,23 +1493,23 @@ function wpt_ajax_tweet() {
1481
 
1482
  add_action( 'admin_head', 'wpt_admin_script' );
1483
  /**
1484
- * Print scripts to WP Tweets PRO pages.
1485
  */
1486
  function wpt_admin_script() {
1487
  global $current_screen;
1488
- if ( $current_screen->base == 'post' || $current_screen->id == 'wp-tweets-pro_page_wp-to-twitter-schedule' ) {
1489
  wp_register_style( 'wpt-post-styles', plugins_url( 'css/post-styles.css', __FILE__ ) );
1490
  wp_enqueue_style( 'wpt-post-styles' );
1491
  $config = wpt_max_length();
1492
  // add one; character count starts from 1.
1493
- if ( $current_screen->base == 'post' ) {
1494
  $allowed = $config['base_length'] - mb_strlen( stripslashes( get_option( 'jd_twit_prepend' ) . get_option( 'jd_twit_append' ) ) ) + 1;
1495
  } else {
1496
  $allowed = $config['base_length'] + 1;
1497
  }
1498
- if ( function_exists( 'wpt_pro_exists' ) && get_option( 'jd_individual_twitter_users' ) == 1 ) {
1499
  $first = '#authors';
1500
- } else if ( function_exists( 'wpt_pro_exists' ) ) {
1501
  $first = '#custom';
1502
  } else {
1503
  $first = '#notes';
@@ -1505,15 +1517,15 @@ function wpt_admin_script() {
1505
  wp_register_script( 'wpt-base-js', plugins_url( 'js/base.js', __FILE__ ), array( 'jquery' ) );
1506
  wp_enqueue_script( 'wpt-base-js' );
1507
  wp_localize_script( 'wpt-base-js', 'wptSettings', array(
1508
- 'allowed' => $allowed,
1509
- 'first' => $first,
1510
- 'is_ssl' => ( wpt_is_ssl( home_url() ) ) ? 'true' : 'false',
1511
- 'text' => __( 'Characters left: ', 'wp-to-twitter' )
1512
- ) );
1513
  echo "
1514
  <style type='text/css'>
1515
- #wp2t h3 span, #wp2t h2 span { padding-left: 30px; background: url(" . plugins_url( 'wp-to-twitter/images/twitter-bird-light-bgs.png' ) . ") left 50% no-repeat; }
1516
- </style>";
1517
  }
1518
  }
1519
 
@@ -1521,7 +1533,6 @@ function wpt_admin_script() {
1521
  * Post the Custom Tweet & custom Tweet data into the post meta table
1522
  *
1523
  * @param integer $id Post ID.
1524
- *
1525
  */
1526
  function wpt_save_post( $id ) {
1527
  if ( empty( $_POST ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || wp_is_post_revision( $id ) || isset( $_POST['_inline_edit'] ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || ! wpt_in_post_type( $id ) ) {
@@ -1531,88 +1542,86 @@ function wpt_save_post( $id ) {
1531
  $yourls = $_POST['_yourls_keyword'];
1532
  $update = update_post_meta( $id, '_yourls_keyword', $yourls );
1533
  }
1534
- if ( isset( $_POST['_jd_twitter'] ) && $_POST['_jd_twitter'] != '' ) {
1535
  $twitter = $_POST['_jd_twitter'];
1536
- $update = update_post_meta( $id, '_jd_twitter', $twitter );
1537
- } else if ( isset( $_POST['_jd_twitter'] ) && $_POST['_jd_twitter'] == '' ) {
1538
  delete_post_meta( $id, '_jd_twitter' );
1539
  }
1540
- if ( isset( $_POST['_jd_wp_twitter'] ) && $_POST['_jd_wp_twitter'] != '' ) {
1541
  $wp_twitter = $_POST['_jd_wp_twitter'];
1542
- $update = update_post_meta( $id, '_jd_wp_twitter', $wp_twitter );
1543
  }
1544
  if ( isset( $_POST['_jd_tweet_this'] ) ) {
1545
- $tweet_this = ( $_POST['_jd_tweet_this'] == 'no' ) ? 'no' : 'yes';
1546
- $update = update_post_meta( $id, '_jd_tweet_this', $tweet_this );
1547
  } else {
1548
  if ( isset( $_POST['_wpnonce'] ) ) {
1549
- $tweet_default = ( get_option( 'jd_tweet_default' ) == 1 ) ? 'no' : 'yes';
1550
- $update = update_post_meta( $id, '_jd_tweet_this', $tweet_default );
1551
  }
1552
  }
1553
- if ( isset( $_POST['wpt_clear_history'] ) && $_POST['wpt_clear_history'] == 'clear' ) {
1554
  delete_post_meta( $id, '_wpt_failed' );
1555
  delete_post_meta( $id, '_jd_wp_twitter' );
1556
  delete_post_meta( $id, '_wpt_short_url' );
1557
  delete_post_meta( $id, '_wp_jd_twitter' );
1558
  }
1559
- // WPT PRO //
1560
  $update = apply_filters( 'wpt_insert_post', $_POST, $id );
1561
- // WPT PRO //
1562
- // only send debug data if post meta is updated.
1563
- if ( $update == true || is_int( $update ) ) {
1564
- wpt_mail( "Post Meta Inserted", print_r( $_POST, 1 ) ); // DEBUG
1565
  }
1566
- if ( isset( $_POST['wpt-delete-debug'] ) && $_POST['wpt-delete-debug'] == 'true' ) {
1567
  delete_post_meta( $id, '_wpt_debug_log' );
1568
  }
1569
- if ( isset( $_POST['wpt-delete-all-debug'] ) && $_POST['wpt-delete-all-debug'] == 'true' ) {
1570
  delete_post_meta_by_key( '_wpt_debug_log' );
1571
  }
1572
  }
1573
 
1574
  /**
1575
  * Show user profile data on Edit User pages.
1576
- *
1577
- * return @string Configuration forms for WP to Twitter user-specific settings.
1578
  */
1579
  function wpt_twitter_profile() {
1580
  global $user_ID;
1581
  $current_user = wp_get_current_user();
1582
- $user_edit = ( isset( $_GET['user_id'] ) ) ? (int) $_GET['user_id'] : $user_ID;
1583
 
1584
  $is_enabled = get_user_meta( $user_edit, 'wp-to-twitter-enable-user', true );
1585
  $twitter_username = get_user_meta( $user_edit, 'wp-to-twitter-user-username', true );
1586
  $wpt_remove = get_user_meta( $user_edit, 'wpt-remove', true );
1587
- if ( current_user_can( 'wpt_twitter_oauth' ) || current_user_can( 'manage_options' ) ) {
1588
  ?>
1589
  <h3><?php _e( 'WP Tweets User Settings', 'wp-to-twitter' ); ?></h3>
1590
- <?php if ( function_exists( 'wpt_connect_oauth_message' ) ) {
 
1591
  wpt_connect_oauth_message( $user_edit );
1592
- } ?>
 
1593
  <table class="form-table">
1594
  <tr>
1595
- <th scope="row"><?php _e( "Use My Twitter Username", 'wp-to-twitter' ); ?></th>
1596
  <td>
1597
- <input type="radio" name="wp-to-twitter-enable-user" id="wp-to-twitter-enable-user-3" value="mainAtTwitter"<?php checked( $is_enabled, 'mainAtTwitter' ); ?> /> <label for="wp-to-twitter-enable-user-3"><?php _e( "Tweet my posts with an @ reference to my username.", 'wp-to-twitter' ); ?></label><br/>
1598
- <input type="radio" name="wp-to-twitter-enable-user" id="wp-to-twitter-enable-user-4" value="mainAtTwitterPlus"<?php checked( $is_enabled, 'mainAtTwitterPlus' ); ?> /> <label for="wp-to-twitter-enable-user-4"><?php _e( "Tweet my posts with an @ reference to both my username and to the main site username.", 'wp-to-twitter' ); ?></label>
1599
  </td>
1600
  </tr>
1601
  <tr>
1602
- <th scope="row"><label
1603
- for="wp-to-twitter-user-username"><?php _e( "Your Twitter Username", 'wp-to-twitter' ); ?></label>
1604
  </th>
1605
- <td><input type="text" name="wp-to-twitter-user-username" id="wp-to-twitter-user-username"
1606
- value="<?php esc_attr_e( $twitter_username ); ?>"/> <?php _e( 'Enter your own Twitter username.', 'wp-to-twitter' ); ?>
1607
  </td>
1608
  </tr>
1609
  <tr>
1610
- <th scope="row"><label
1611
- for="wpt-remove"><?php _e( "Hide account name in Tweets", 'wp-to-twitter' ); ?></label></th>
1612
- <td><input type="checkbox" name="wpt-remove" id="wpt-remove"
1613
- value="on"<?php if ( $wpt_remove == 'on' ) {
1614
- echo ' checked="checked"';
1615
- } ?> /> <?php _e( 'Do not display my account in the #account# template tag.', 'wp-to-twitter' ); ?>
1616
  </td>
1617
  </tr>
1618
  <?php echo apply_filters( 'wpt_twitter_user_fields', $user_edit ); ?>
@@ -1625,11 +1634,11 @@ function wpt_twitter_profile() {
1625
  }
1626
  } else {
1627
  // hidden fields. If function is enabled, but this user does not have privileges to edit.
1628
- ?>
1629
- <input type="hidden" name="wp-to-twitter-enable-user" value="<?php esc_attr_e( $is_enabled ); ?>" />
1630
- <input type="hidden" name="wp-to-twitter-user-username" value="<?php esc_attr_e( $twitter_username ); ?>" />
1631
- <input type="hidden" name="wpt-remove" value="<?php esc_attr_e( $wpt_remove ); ?>" />
1632
- <?php
1633
  }
1634
  }
1635
 
@@ -1637,18 +1646,25 @@ function wpt_twitter_profile() {
1637
  * This compensates for an old error where the user ID is echoed directly into the page.
1638
  */
1639
  add_filter( 'wpt_twitter_user_fields', 'wpt_basic_user_fields', 100, 1 );
 
 
 
 
 
 
 
1640
  function wpt_basic_user_fields( $user_edit ) {
1641
  if ( is_int( $user_edit ) ) {
1642
  return '';
1643
  }
1644
-
1645
  return $user_edit;
1646
  }
1647
 
1648
- /**
1649
- * Save user profile data
1650
  */
1651
- function wpt_twitter_save_profile() {
1652
  global $user_ID;
1653
  $current_user = wp_get_current_user();
1654
  if ( isset( $_POST['user_id'] ) ) {
@@ -1656,7 +1672,7 @@ function wpt_twitter_save_profile() {
1656
  } else {
1657
  $edit_id = $user_ID;
1658
  }
1659
- if ( current_user_can( 'wpt_twitter_oauth' ) || current_user_can( 'manage_options' ) ) {
1660
  $enable = ( isset( $_POST['wp-to-twitter-enable-user'] ) ) ? $_POST['wp-to-twitter-enable-user'] : '';
1661
  $username = ( isset( $_POST['wp-to-twitter-user-username'] ) ) ? $_POST['wp-to-twitter-user-username'] : '';
1662
  $wpt_remove = ( isset( $_POST['wpt-remove'] ) ) ? 'on' : '';
@@ -1664,16 +1680,16 @@ function wpt_twitter_save_profile() {
1664
  update_user_meta( $edit_id, 'wp-to-twitter-user-username', $username );
1665
  update_user_meta( $edit_id, 'wpt-remove', $wpt_remove );
1666
  }
1667
- //WPT PRO
1668
  apply_filters( 'wpt_save_user', $edit_id, $_POST );
1669
  }
1670
 
 
1671
  /**
1672
  * Send links to old admin to new admin page
1673
  */
1674
- add_action( 'init', 'wpt_old_admin_redirect' );
1675
  function wpt_old_admin_redirect() {
1676
- if ( is_admin() && isset( $_GET['page'] ) && $_GET['page'] == 'wp-to-twitter/wp-to-twitter.php' ) {
1677
  wp_safe_redirect( admin_url( 'admin.php?page=wp-tweets-pro' ) );
1678
  exit;
1679
  }
@@ -1686,39 +1702,44 @@ add_action( 'admin_menu', 'wpt_admin_page' );
1686
  function wpt_admin_page() {
1687
  if ( function_exists( 'add_menu_page' ) && ! function_exists( 'wpt_pro_functions' ) ) {
1688
  $icon_path = plugins_url( 'images/icon.png', __FILE__ );
1689
- $page = add_menu_page(__('WP to Twitter','wp-to-twitter'), __('WP to Twitter','wp-to-twitter'), 'manage_options', 'wp-tweets-pro', 'wpt_update_settings',$icon_path );
1690
  }
1691
  }
1692
 
1693
  add_action( 'admin_head', 'wpt_admin_style' );
1694
- /**
1695
  * Add stylesheets to WP to Twitter pages.
1696
  */
1697
  function wpt_admin_style() {
1698
- if ( isset( $_GET['page'] ) && ( $_GET['page'] == "wp-to-twitter" || $_GET['page'] == "wp-tweets-pro" || $_GET['page'] == "wp-to-twitter-schedule" || $_GET['page'] == "wp-to-twitter-tweets" || $_GET['page'] == "wp-to-twitter-errors" ) ) {
1699
  wp_enqueue_style( 'wpt-styles', plugins_url( 'css/styles.css', __FILE__ ) );
1700
  }
1701
  }
1702
 
1703
- /**
1704
  * Add WP to Twitter links to plug-in information.
 
 
 
 
 
1705
  */
1706
  function wpt_plugin_action( $links, $file ) {
1707
- if ( $file == plugin_basename( dirname( __FILE__ ) . '/wp-to-twitter.php' ) ) {
1708
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
1709
- $links[] = "<a href='$admin_url'>" . __( 'WP to Twitter Settings', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1710
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1711
- $links[] = "<a href='http://www.wptweetspro.com/wp-tweets-pro'>" . __( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1712
  }
1713
  }
1714
 
1715
  return $links;
1716
  }
1717
 
1718
- //Add Plugin Actions to WordPress
1719
- add_filter( 'plugin_action_links', 'wpt_plugin_action', - 10, 2 );
1720
 
1721
- if ( get_option( 'jd_individual_twitter_users' ) == '1' ) {
1722
  add_action( 'show_user_profile', 'wpt_twitter_profile' );
1723
  add_action( 'edit_user_profile', 'wpt_twitter_profile' );
1724
  add_action( 'profile_update', 'wpt_twitter_save_profile' );
@@ -1727,8 +1748,6 @@ if ( get_option( 'jd_individual_twitter_users' ) == '1' ) {
1727
  add_action( 'in_plugin_update_message-wp-to-twitter/wp-to-twitter.php', 'wpt_plugin_update_message' );
1728
  /**
1729
  * Parse plugin update info to display in update list.
1730
- *
1731
- * @return string Notice from new version's readme.txt
1732
  */
1733
  function wpt_plugin_update_message() {
1734
  global $wpt_version;
@@ -1738,44 +1757,45 @@ function wpt_plugin_update_message() {
1738
  if ( ! is_wp_error( $response ) || is_array( $response ) ) {
1739
  $data = $response['body'];
1740
  $bits = explode( '== Upgrade Notice ==', $data );
1741
- $note = '<div id="wpt-upgrade"><p><strong style="color:#c22;">Upgrade Notes:</strong> ' . nl2br( trim( $bits[1] ) ) . '</p></div>';
1742
  }
1743
-
1744
  echo $note;
1745
  }
1746
 
1747
- if ( get_option( 'jd_twit_blogroll' ) == '1' ) {
1748
  add_action( 'add_link', 'wpt_twit_link' );
1749
  }
1750
 
1751
  add_action( 'save_post', 'wpt_twit', 15 );
1752
  add_action( 'save_post', 'wpt_save_post', 10 );
1753
-
1754
  /**
1755
  * Check whether a given post is in an allowed post type and has an update template configured.
1756
- *
1757
  * @param integer $id Post ID.
1758
  *
1759
  * @return boolean True if post is allowed, false otherwise.
1760
  */
1761
  function wpt_in_post_type( $id ) {
1762
  $post_type_settings = get_option( 'wpt_post_types' );
1763
- if ( is_array( $post_type_settings ) && !empty( $post_type_settings ) ) {
1764
- $post_types = array_keys( $post_type_settings );
1765
- $type = get_post_type( $id );
1766
  if ( in_array( $type, $post_types ) ) {
1767
- if ( $post_type_settings[ $type ]['post-edited-update'] == '1' || $post_type_settings[ $type ]['post-published-update'] == '1' ) {
1768
  return true;
1769
  }
1770
  }
1771
  }
1772
-
1773
  return false;
1774
  }
1775
 
1776
  add_action( 'future_to_publish', 'wpt_future_to_publish', 16 );
1777
  /**
1778
  * Handle Tweeting posts scheduled for the future.
 
 
1779
  */
1780
  function wpt_future_to_publish( $post ) {
1781
  $id = $post->ID;
@@ -1787,18 +1807,19 @@ function wpt_future_to_publish( $post ) {
1787
 
1788
  /**
1789
  * Handle Tweeting posts published directly.
 
 
1790
  */
1791
  function wpt_twit( $id ) {
1792
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $id ) || ! wpt_in_post_type( $id ) ) {
1793
  return;
1794
  }
1795
- $post = get_post( $id );
1796
- if ( $post->post_status != 'publish' ) {
1797
  return;
1798
- }
1799
  // is there any reason to accept any other status?
1800
-
1801
- // This is an issue only until the release of WP 4.7
1802
  remove_action( 'save_post', 'wpt_twit', 15 );
1803
  wpt_twit_instant( $id );
1804
  add_action( 'save_post', 'wpt_twit', 15 );
@@ -1814,13 +1835,13 @@ add_action( 'publish_phone', 'wpt_twit_xmlrpc' );
1814
  */
1815
  function wpt_twit_future( $id ) {
1816
  set_transient( '_wpt_twit_future', $id, 10 );
1817
- // instant action has already run for this post. // prevent running actions twice (need both for older WP)
1818
  if ( get_transient( '_wpt_twit_instant' ) && get_transient( '_wpt_twit_instant' ) == $id ) {
1819
  delete_transient( '_wpt_twit_instant' );
1820
 
1821
  return;
1822
  }
1823
-
1824
  wpt_tweet( $id, 'future' );
1825
  }
1826
 
@@ -1846,8 +1867,12 @@ function wpt_twit_instant( $id ) {
1846
  wpt_tweet( $id, 'instant' );
1847
  }
1848
 
1849
- /**
1850
  * Tweet XMLRPC posts.
 
 
 
 
1851
  */
1852
  function wpt_twit_xmlrpc( $id ) {
1853
  set_transient( '_wpt_twit_xmlrpc', $id, 10 );
@@ -1863,7 +1888,7 @@ add_action( 'wpt_schedule_promotion_action', 'wpt_schedule_promotion' );
1863
  * Set an option indicating that a job has been scheduled for promoting WP Tweets PRO.
1864
  */
1865
  function wpt_schedule_promotion() {
1866
- if ( ! function_exists( 'wpt_pro_exists' ) && get_option( 'wpt_promotion_scheduled' ) == 1 ) {
1867
  update_option( 'wpt_promotion_scheduled', 2 );
1868
  }
1869
  }
@@ -1872,7 +1897,7 @@ function wpt_schedule_promotion() {
1872
  * Dismiss promotion notice.
1873
  */
1874
  function wpt_dismiss_promotion() {
1875
- if ( isset( $_GET['dismiss'] ) && $_GET['dismiss'] == 'promotion' ) {
1876
  update_option( 'wpt_promotion_scheduled', 3 );
1877
  }
1878
  }
@@ -1880,21 +1905,24 @@ function wpt_dismiss_promotion() {
1880
  add_action( 'admin_notices', 'wpt_dismiss_promotion', 5 );
1881
  add_action( 'admin_notices', 'wpt_promotion_notice', 10 );
1882
  add_action( 'admin_notices', 'wpt_debugging_enabled', 10 );
1883
-
 
 
1884
  function wpt_debugging_enabled() {
1885
  if ( current_user_can( 'manage_options' ) && WPT_DEBUG ) {
1886
- echo "<div class='notice error important'><p>" . __( "<strong>WP to Twitter</strong> debugging is enabled. Remember to disable debugging when you are finished.", 'wp-to-twitter' ) . "</p></div>";
1887
- }
1888
  }
1889
 
1890
  /**
1891
  * Display promotion notice to admin users who have not donated or purchased WP Tweets PRO.
1892
  */
1893
  function wpt_promotion_notice() {
1894
- if ( current_user_can( 'activate_plugins' ) && get_option( 'wpt_promotion_scheduled' ) == 2 && get_option( 'jd_donations' ) != 1 ) {
1895
- $upgrade = "http://www.wptweetspro.com/wp-tweets-pro/";
1896
  $dismiss = admin_url( 'admin.php?page=wp-tweets-pro&dismiss=promotion' );
1897
- echo "<div class='notice'><p>" . sprintf( __( "I hope you've enjoyed <strong>WP to Twitter</strong>! Take a look at <a href='%s'>upgrading to WP Tweets PRO</a> for advanced Tweeting with WordPress! <a href='%s'>Dismiss</a>", 'wp-to-twitter' ), $upgrade, $dismiss ) . "</p></div>";
 
1898
  }
1899
  }
1900
 
@@ -1916,43 +1944,23 @@ add_filter( 'wpt_enqueue_feed_styles', 'wpt_permit_feed_styles' );
1916
  * Check whether Twitter Feed styles are enabled.
1917
  *
1918
  * @param boolean $value true if permitted.
1919
- *
1920
  * @return boolean $value False if settings disable styles.
1921
  */
1922
  function wpt_permit_feed_styles( $value ) {
1923
- if ( get_option( 'wpt_permit_feed_styles' ) == 1 ) {
1924
  $value = false;
1925
  }
1926
 
1927
  return $value;
1928
  }
1929
 
1930
- /*
1931
- // Add notes about Tweet status to posts admin
1932
- function wpt_column($cols) {
1933
- $cols['wpt'] = __('Tweet Status','wp-to-twitter');
1934
- return $cols;
1935
- }
1936
-
1937
- // Echo the ID for the new column
1938
- function wpt_value($column_name, $id) {
1939
- if ($column_name == 'wpt') {
1940
- $marked = ucfirst( ( get_post_meta($id,'_jd_tweet_this',true) ) );
1941
- echo $marked;
1942
- }
1943
- }
1944
-
1945
- function wpt_return_value($value, $column_name, $id) {
1946
- if ( $column_name == 'wpt' ) {
1947
- $value = $id;
1948
- }
1949
- return $value;
1950
- }
1951
- */
1952
- // Output CSS for width of new column
1953
  add_action( 'admin_head', 'wpt_css' );
 
 
 
1954
  function wpt_css() {
1955
- ?>
1956
  <style type="text/css">
1957
  th#wpt {
1958
  width: 60px;
@@ -1967,24 +1975,3 @@ function wpt_css() {
1967
  </style>
1968
  <?php
1969
  }
1970
- /*
1971
- // Actions/Filters for various tables and the css output
1972
- add_action('admin_init', 'wpt_add');
1973
- function wpt_add() {
1974
- $post_type_settings = get_option('wpt_post_types');
1975
- $post_types = array_keys($post_type_settings);
1976
-
1977
- add_action('admin_head', 'wpt_css');
1978
- if ( !$post_types || in_array( 'post', $post_types ) ) {
1979
- add_filter('manage_posts_columns', 'wpt_column');
1980
- add_action('manage_posts_custom_column', 'wpt_value', 10, 2);
1981
- }
1982
- if ( !$post_types || in_array( 'page', $post_types ) ) {
1983
- add_filter('manage_pages_columns', 'wpt_column');
1984
- add_action('manage_pages_custom_column', 'wpt_value', 10, 2);
1985
- }
1986
- foreach ( $post_types as $types ) {
1987
- add_action("manage_${types}_columns", 'wpt_column');
1988
- add_filter("manage_${types}_custom_column", 'wpt_value', 10, 2);
1989
- }
1990
- } */
1
  <?php
2
+ /**
3
+ * WP to Twitter
4
+ *
5
+ * @package WP to Twitter
6
+ * @author Joe Dolson
7
+ * @copyright 2008-2018 Joe Dolson
8
+ * @license GPL-2.0+
9
+ *
10
+ * @wordpress-plugin
11
+ * Plugin Name: WP to Twitter
12
+ * Plugin URI: http://www.joedolson.com/wp-to-twitter/
13
+ * Description: Posts a Tweet when you update your WordPress blog or post a link, using your URL shortener. Rich options to customize and promote your Tweets.
14
+ * Author: Joseph C Dolson
15
+ * Author URI: http://www.joedolson.com
16
+ * Text Domain: wp-to-twitter
17
+ * License: GPL-2.0+
18
+ * License URI: http://www.gnu.org/license/gpl-2.0.txt
19
+ * Domain Path: lang
20
+ * Version: 3.3.3
21
+ */
22
+
23
  /*
24
+ Copyright 2008-2018 Joe Dolson (email : joe@joedolson.com)
 
 
 
 
 
 
 
 
25
 
26
+ This program is free software; you can redistribute it and/or modify
27
+ it under the terms of the GNU General Public License as published by
28
+ the Free Software Foundation; either version 2 of the License, or
29
+ (at your option) any later version.
30
 
31
+ This program is distributed in the hope that it will be useful,
32
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
33
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
+ GNU General Public License for more details.
35
 
36
+ You should have received a copy of the GNU General Public License
37
+ along with this program; if not, write to the Free Software
38
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
39
  */
40
  if ( ! defined( 'ABSPATH' ) ) {
41
  exit;
42
+ }
43
 
44
+ define( 'WPT_DEBUG', false ); // Debugging only works with WP Tweets PRO.
45
+ define( 'WPT_DEBUG_BY_EMAIL', false ); // Email debugging no longer default as of 3.3.0.
46
  define( 'WPT_DEBUG_ADDRESS', get_option( 'admin_email' ) );
47
+ define( 'WPT_FROM', 'From: \"' . get_option( 'blogname' ) . '\" <' . get_option( 'admin_email' ) . '>' );
48
+
49
+ require_once( plugin_dir_path( __FILE__ ) . 'wpt-functions.php' );
50
+ require_once( plugin_dir_path( __FILE__ ) . 'wp-to-twitter-oauth.php' );
51
+ require_once( plugin_dir_path( __FILE__ ) . 'wp-to-twitter-shorteners.php' );
52
+ require_once( plugin_dir_path( __FILE__ ) . 'wp-to-twitter-manager.php' );
53
+ require_once( plugin_dir_path( __FILE__ ) . 'wpt-truncate.php' );
54
+ require_once( plugin_dir_path( __FILE__ ) . 'classes/class-wpt-twitterfeed.php' );
55
+ require_once( plugin_dir_path( __FILE__ ) . 'wpt-widget.php' );
56
+ require_once( plugin_dir_path( __FILE__ ) . 'wpt-rate-limiting.php' );
 
57
 
58
  global $wpt_version;
59
+ $wpt_version = '3.3.3';
60
 
61
  add_action( 'init', 'wpt_load_textdomain' );
62
+ /**
63
+ * Set up text domain for WP to Twitter.
64
+ */
65
  function wpt_load_textdomain() {
66
  load_plugin_textdomain( 'wp-to-twitter' );
67
  }
68
 
69
+ add_action( 'widgets_init', 'wpt_register_widgets' );
70
+ /**
71
+ * Register WP to Twitter Widgets
72
+ */
73
+ function wpt_register_widgets() {
74
+ register_widget( 'WPT_Latest_Tweets_Widget' );
75
+ register_widget( 'WPT_Search_Tweets_Widget' );
76
+ }
77
+
78
+ /**
79
+ * Check for OAuth configuration
80
+ *
81
+ * @param mixed int/boolean $auth Which account to check.
82
+ *
83
+ * @return boolean Whether authorized.
84
+ */
85
  function wpt_check_oauth( $auth = false ) {
86
  if ( ! function_exists( 'wtt_oauth_test' ) ) {
87
  $oauth = false;
92
  return $oauth;
93
  }
94
 
95
+ /**
96
+ * Check whether version requires activation.
97
+ */
98
  function wpt_check_version() {
99
  global $wpt_version;
100
+ $prev_version = ( '' != get_option( 'wp_to_twitter_version' ) ) ? get_option( 'wp_to_twitter_version' ) : '1.0.0';
101
+ if ( version_compare( $prev_version, $wpt_version, '<' ) ) {
102
  wptotwitter_activate();
103
  }
104
  }
105
 
106
+ /**
107
+ * Activate WP to Twitter.
108
+ */
109
  function wptotwitter_activate() {
110
  // If this has never run before, do the initial setup.
111
+ $new_install = ( 1 == get_option( 'wpt_twitter_setup' ) || 1 == get_option( 'twitterInitialised' ) ) ? false : true;
112
  if ( $new_install ) {
113
  $initial_settings = array(
114
  'post' => array(
115
  'post-published-update' => 1,
116
  'post-published-text' => 'New post: #title# #url#',
117
  'post-edited-update' => 0,
118
+ 'post-edited-text' => 'Post Edited: #title# #url#',
119
  ),
120
  'page' => array(
121
  'post-published-update' => 0,
122
  'post-published-text' => 'New page: #title# #url#',
123
  'post-edited-update' => 0,
124
+ 'post-edited-text' => 'Page edited: #title# #url#',
125
+ ),
126
  );
127
  update_option( 'wpt_post_types', $initial_settings );
128
  update_option( 'jd_twit_blogroll', '1' );
134
  update_option( 'jd_replace_character', '' );
135
  $administrator = get_role( 'administrator' );
136
  if ( is_object( $administrator ) ) {
137
+ // wpt_twitter_oauth is the general permission for editing user accounts.
138
+ $administrator->add_cap( 'wpt_twitter_oauth' );
139
  $administrator->add_cap( 'wpt_twitter_custom' );
140
  $administrator->add_cap( 'wpt_twitter_switch' );
141
  $administrator->add_cap( 'wpt_can_tweet' );
156
 
157
  update_option( 'jd_twit_remote', '0' );
158
  update_option( 'jd_post_excerpt', 30 );
159
+ // Use Google Analytics with Twitter.
160
  update_option( 'twitter-analytics-campaign', 'twitter' );
161
  update_option( 'use-twitter-analytics', '0' );
162
  update_option( 'jd_dynamic_analytics', '0' );
163
  update_option( 'no-analytics', 1 );
164
  update_option( 'use_dynamic_analytics', 'category' );
165
+ // Use custom external URLs to point elsewhere.
166
  update_option( 'jd_twit_custom_url', 'external_link' );
167
+ // Error checking.
168
  update_option( 'wp_url_failure', '0' );
169
  // Default publishing options.
170
  update_option( 'jd_tweet_default', '0' );
172
  update_option( 'wpt_inline_edits', '0' );
173
  // Note that default options are set.
174
  update_option( 'wpt_twitter_setup', '1' );
175
+ update_option( 'jd_keyword_format', '0' );
176
  }
177
+
178
  global $wpt_version;
179
+ $prev_version = get_option( 'wp_to_twitter_version' );
 
180
  $administrator = get_role( 'administrator' );
181
+ $upgrade = version_compare( $prev_version, '2.9.0', '<' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  if ( $upgrade ) {
183
  $administrator->add_cap( 'wpt_tweet_now' );
184
  }
185
+
186
  update_option( 'wp_to_twitter_version', $wpt_version );
187
  }
188
 
189
+ /**
190
+ * Function checks for an alternate URL to be Tweeted. Contribution by Bill Berry.
191
+ *
192
+ * @param int $post_ID Post ID.
193
+ *
194
+ * @return Link to use for this URL.
195
+ */
196
  function wpt_link( $post_ID ) {
197
  $ex_link = false;
198
  $external_link = get_option( 'jd_twit_custom_url' );
199
  $permalink = get_permalink( $post_ID );
200
+ if ( '' != $external_link ) {
201
  $ex_link = get_post_meta( $post_ID, $external_link, true );
202
  }
203
 
204
  return ( $ex_link ) ? $ex_link : $permalink;
205
  }
206
 
207
+ /**
208
+ * Save error messages for Tweets.
209
+ *
210
+ * @param int $id Post ID.
211
+ * @param int $auth Current author.
212
+ * @param string $twit Tweet text.
213
+ * @param string $error Error string from Twitter.
214
+ * @param int $http_code Http code from Tiwtter.
215
+ * @param string $ts Current timestamp.
216
+ */
217
  function wpt_saves_error( $id, $auth, $twit, $error, $http_code, $ts ) {
218
  $http_code = (int) $http_code;
219
+ if ( 200 != $http_code ) {
220
  add_post_meta( $id, '_wpt_failed', array(
221
+ 'author' => $auth,
222
+ 'sentence' => $twit,
223
+ 'error' => $error,
224
+ 'code' => $http_code,
225
+ 'timestamp' => $ts,
226
+ ) );
227
  } else {
228
+ if ( 1 == get_option( 'wpt_rate_limiting' ) ) {
229
  wpt_log_success( $auth, $ts, $id );
230
  }
231
  }
232
  }
233
 
234
 
235
+ /**
236
+ * Checks whether WP to Twitter has sent a tweet on this post to this author within the last 30 seconds and blocks duplicates.
237
  *
238
+ * @param int $id Post ID.
239
+ * @param int $auth Author.
240
+ *
241
+ * @uses filter wpt_recent_tweet_threshold
242
+ * @return boolean true to send Tweet, false to block.
243
  */
244
  function wpt_check_recent_tweet( $id, $auth ) {
245
  if ( ! $id ) {
246
  return false;
247
  } else {
248
+ if ( false == $auth ) {
249
  $transient = get_transient( "_wpt_most_recent_tweet_$id" );
250
  } else {
251
+ $transient = get_transient( '_wpt_' . $auth . "_most_recent_tweet_$id" );
252
  }
253
  if ( $transient ) {
254
  return true;
255
  } else {
256
  $expire = apply_filters( 'wpt_recent_tweet_threshold', 30 );
257
  // if expiration is 0, don't set the transient. We don't want permanent transients.
258
+ if ( 0 !== $expire ) {
259
+ wpt_mail( 'Tweet transient set', "$expire / $auth / $id" );
260
+ if ( false == $auth ) {
261
  set_transient( "_wpt_most_recent_tweet_$id", true, $expire );
262
  } else {
263
+ set_transient( '_wpt_' . $auth . "_most_recent_tweet_$id", true, $expire );
264
  }
265
  }
266
  }
271
 
272
  /**
273
  * Performs the API post to Twitter
274
+ *
275
+ * @param string $twit Text of Tweet to be sent to Twitter.
276
+ * @param int $auth Author ID.
277
+ * @param int $id Post ID.
278
+ * @param boolean $media Whether to upload media attached to the post specified in $id.
279
+ *
280
+ * @return boolean Success of query.
281
  */
282
  function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false ) {
283
+ $recent = wpt_check_recent_tweet( $id, $auth );
284
+ $error = false;
285
+ if ( 1 == get_option( 'wpt_rate_limiting' ) ) {
286
  // check whether this post needs to be rate limited.
287
  $continue = wpt_test_rate_limit( $id, $auth );
288
+ if ( ! $continue ) {
289
  return false;
290
  }
291
  }
294
  if ( $recent ) {
295
  return false;
296
  }
297
+
298
  if ( ! wpt_check_oauth( $auth ) ) {
299
  $error = __( 'This account is not authorized to post to Twitter.', 'wp-to-twitter' );
300
  wpt_saves_error( $id, $auth, $twit, $error, '401', time() );
301
  wpt_set_log( 'wpt_status_message', $id, $error );
302
 
303
  return false;
304
+ } // exit silently if not authorized.
305
 
306
+ $check = ( ! $auth ) ? get_option( 'jd_last_tweet' ) : get_user_meta( $auth, 'wpt_last_tweet', true ); // get user's last tweet.
307
+ // prevent duplicate Tweets.
308
  if ( $check == $twit ) {
309
+ wpt_mail( 'Matched: tweet identical', "This Tweet: $twit; Check Tweet: $check; $auth, $id, $media" ); // DEBUG.
310
  $error = __( 'This tweet is identical to another Tweet recently sent to this account.', 'wp-to-twitter' ) . ' ' . __( 'Twitter requires all Tweets to be unique.', 'wp-to-twitter' );
311
  wpt_saves_error( $id, $auth, $twit, $error, '403-1', time() );
312
  wpt_set_log( 'wpt_status_message', $id, $error );
313
 
314
  return false;
315
+ } elseif ( '' == $twit || ! $twit ) {
316
+ wpt_mail( 'Tweet check: empty sentence', "$twit, $auth, $id, $media" ); // DEBUG.
317
  $error = __( 'This tweet was blank and could not be sent to Twitter.', 'wp-tweets-pro' );
318
  wpt_saves_error( $id, $auth, $twit, $error, '403-2', time() );
319
  wpt_set_log( 'wpt_status_message', $id, $error );
321
  return false;
322
  } else {
323
  $media_id = false;
324
+ // must be designated as media and have a valid attachment.
325
  $attachment = ( $media ) ? wpt_post_attachment( $id ) : false;
326
  if ( $attachment ) {
327
  wpt_mail( 'Post has upload', "$auth, $attachment" );
331
  $attachment = false;
332
  }
333
  }
334
+ $api = 'https://api.twitter.com/1.1/statuses/update.json';
335
+ $upload_api = 'https://upload.twitter.com/1.1/media/upload.json';
336
+ $status = array(
337
+ 'status' => $twit,
338
+ 'source' => 'wp-to-twitter',
339
+ 'include_entities' => 'true',
340
+ );
341
+
342
+ if ( wtt_oauth_test( $auth ) ) {
343
+ $connection = wpt_oauth_connection( $auth );
344
+ if ( $connection ) {
345
+ if ( $media && $attachment && ! $media_id ) {
346
+ $media_id = $connection->media( $upload_api, array(
347
+ 'auth' => $auth,
348
+ 'media' => $attachment,
349
+ ) );
350
+ wpt_mail( 'Media Uploaded', "$auth, $media_id, $attachment" );
351
+ if ( $media_id ) {
352
+ $status['media_ids'] = $media_id;
353
+ /**
354
+ * Eventually, use this to add alt text. Not supported at this time.
355
+ $metadata_api = 'https://upload.twitter.com/1.1/media/metadata/create.json';
356
+ $alt_text = get_post_meta( $args['media'], '_wp_attachment_image_alt', true );
357
+ if ( '' != $alt_text ) {
358
+ $image_alt = json_encode( array(
359
+ 'media_id' => $media_id,
360
+ 'alt_text' => array(
361
+ 'text' => $alt_text,
362
+ ),
363
+ ) );
364
+ $post_alt = $connection->post( $metadata_api, array( 'auth' => $auth, 'json' => $image_alt ), true );
365
+ }
366
+ */
367
+ }
368
  }
369
  }
370
  }
372
  $connection = array( 'connection' => 'undefined' );
373
  } else {
374
  $staging_mode = apply_filters( 'wpt_staging_mode', false, $auth, $id );
375
+ if ( ( defined( 'WPT_STAGING_MODE' ) && true == WPT_STAGING_MODE ) || $staging_mode ) {
376
  // if in staging mode, we'll behave as if the Tweet succeeded, but not send it.
377
  $connection = true;
378
+ $http_code = 200;
379
+ $notice = __( 'In Staging Mode:', 'wp-to-twitter' ) . ' ';
380
  } else {
381
  $connection->post( $api, $status );
382
  $http_code = ( $connection ) ? $connection->http_code : 'failed';
383
+ $notice = '';
384
+ }
385
  }
386
  wpt_mail( 'Twitter Connection', print_r( $connection, 1 ) . " - $twit, $auth, $id, $media" );
387
  if ( $connection ) {
388
+ if ( isset( $connection->http_header['x-access-level'] ) && 'read' == $connection->http_header['x-access-level'] ) {
389
+ // Translators: Twitter App editing URL.
390
  $supplement = sprintf( __( 'Your Twitter application does not have read and write permissions. Go to <a href="%s">your Twitter apps</a> to modify these settings.', 'wp-to-twitter' ), 'https://dev.twitter.com/apps/' );
391
  } else {
392
  $supplement = '';
394
  $return = false;
395
  switch ( $http_code ) {
396
  case '100':
397
+ $error = __( '100 Continue: Twitter received the header of your submission, but your server did not follow through by sending the body of the data.', 'wp-to-twitter' );
398
+ break;
399
  case '200':
400
  $return = true;
401
+ $error = __( '200 OK: Success!', 'wp-to-twitter' );
402
  update_option( 'wpt_authentication_missing', false );
403
  break;
404
  case '304':
405
+ $error = __( '304 Not Modified: There was no new data to return', 'wp-to-twitter' );
406
  break;
407
  case '400':
408
+ $error = __( '400 Bad Request: The request was invalid. This is the status code returned during rate limiting.', 'wp-to-twitter' );
409
  break;
410
  case '401':
411
+ $error = __( '401 Unauthorized: Authentication credentials were missing or incorrect.', 'wp-to-twitter' );
412
  update_option( 'wpt_authentication_missing', "$auth" );
413
  break;
414
  case '403':
415
+ $error = __( '403 Forbidden: The request is understood, but has been refused by Twitter.', 'wp-to-twitter' );
416
  break;
417
  case '404':
418
+ $error = __( '404 Not Found: The URI requested is invalid or the resource requested does not exist.', 'wp-to-twitter' );
419
  break;
420
  case '406':
421
+ $error = __( '406 Not Acceptable: Invalid Format Specified.', 'wp-to-twitter' );
422
  break;
423
  case '422':
424
+ $error = __( '422 Unprocessable Entity: The image uploaded could not be processed.', 'wp-to-twitter' );
425
  break;
426
  case '429':
427
+ $error = __( '429 Too Many Requests: You have exceeded your rate limits.', 'wp-to-twitter' );
428
  break;
429
  case '500':
430
+ $error = __( '500 Internal Server Error: Something is broken at Twitter.', 'wp-to-twitter' );
431
  break;
432
  case '502':
433
+ $error = __( '502 Bad Gateway: Twitter is down or being upgraded.', 'wp-to-twitter' );
434
  break;
435
  case '503':
436
+ $error = __( '503 Service Unavailable: The Twitter servers are up, but overloaded with requests - Please try again later.', 'wp-to-twitter' );
437
  break;
438
  case '504':
439
  $error = __( "504 Gateway Timeout: The Twitter servers are up, but the request couldn't be serviced due to some failure within our stack. Try again later.", 'wp-to-twitter' );
440
  break;
441
  default:
442
+ // Translators: http code.
443
+ $error = sprintf( __( '<strong>Code %s</strong>: Twitter did not return a recognized response code.', 'wp-to-twitter' ), $http_code );
444
  break;
445
  }
446
  $body = $connection->body;
447
+ $error_code = ( 200 != $http_code ) ? $body->errors[0]->code : '';
448
+ $error_message = ( 200 != $http_code ) ? $body->errors[0]->message : '';
449
+ $error_supplement = ( '' != $error_code ) ? ' (Error Code: ' . $error_code . ': ' . $error_message . ')' : '';
450
+ $error .= ( '' != $supplement ) ? " $supplement" : '';
451
  $error .= $error_supplement;
452
+ wpt_mail( "Twitter Response: $http_code", "$error" ); // DEBUG.
453
+ // only save last Tweet if successful.
454
+ if ( 200 == $http_code ) {
 
 
455
  if ( ! $auth ) {
456
  update_option( 'jd_last_tweet', $twit );
457
  } else {
459
  }
460
  }
461
  wpt_saves_error( $id, $auth, $twit, $error, $http_code, time() );
462
+ if ( 200 == $http_code ) {
463
  $jwt = get_post_meta( $id, '_jd_wp_twitter', true );
464
  if ( ! is_array( $jwt ) ) {
465
  $jwt = array();
472
  update_post_meta( $id, '_jd_wp_twitter', $jwt );
473
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
474
  // schedule a one-time promotional box for 4 weeks after first successful Tweet.
475
+ if ( false == get_option( 'wpt_promotion_scheduled' ) ) {
476
  wp_schedule_single_event( time() + ( 60 * 60 * 24 * 7 * 4 ), 'wpt_schedule_promotion_action' );
477
  update_option( 'wpt_promotion_scheduled', 1 );
478
  }
481
  if ( ! $return ) {
482
  wpt_set_log( 'wpt_status_message', $id, $error );
483
  } else {
484
+ do_action( 'wpt_tweet_posted', $connection, $id );
485
  wpt_set_log( 'wpt_status_message', $id, $notice . __( 'Tweet sent successfully.', 'wp-to-twitter' ) );
486
  }
487
 
497
 
498
  /**
499
  * For servers without PEAR normalize installed, approximates normalization. With normalizer, executes normalization on string.
500
+ *
501
+ * @param string $string Text to normalize.
502
+ *
503
  * @return string Normalized text.
504
  */
505
  function wpt_normalize( $string ) {
512
  } else {
513
  $normalizer = new WPT_Normalizer();
514
  if ( $normalizer->isNormalized( $string ) ) {
515
+ return $string;
516
  }
517
+
518
  return $normalizer->normalize( $string );
519
  }
520
  }
521
 
522
  /**
523
  * Test URL to see if is pointing to https location.
524
+ *
525
+ * @param string $url URL to check for https.
526
  *
527
  * @return boolean
528
  */
535
  }
536
 
537
  /**
538
+ * Deprecated; still used if configured.
539
+ * Uses old option 'tweet_categories' and verifies whether category of current post allows it to be Tweeted.
540
+ *
541
+ * @param array $array Array of categories for post.
542
+ *
543
+ * @return boolean.
544
  */
545
  function wpt_in_allowed_category( $array ) {
546
  $allowed_categories = get_option( 'tweet_categories' );
547
  if ( is_array( $array ) && is_array( $allowed_categories ) ) {
548
+ $common = array_intersect( $array, $allowed_categories );
549
  if ( count( $common ) >= 1 ) {
550
  return true;
551
  } else {
558
 
559
  /**
560
  * Builds array of post info for use in Tweet functions.
561
+ *
562
  * @param integer $post_ID Post ID.
563
  *
564
+ * @return array Post data used in Tweet functions.
565
  */
566
  function wpt_post_info( $post_ID ) {
567
  $encoding = get_option( 'blog_charset' );
568
+ if ( '' == $encoding ) {
569
  $encoding = 'UTF-8';
570
  }
571
  $post = get_post( $post_ID );
572
  $category_ids = false;
573
  $values = array();
574
  $values['id'] = $post_ID;
575
+ // get post author.
576
  $values['postinfo'] = $post;
577
  $values['postContent'] = $post->post_content;
578
  $values['authId'] = $post->post_author;
579
  $postdate = $post->post_date;
580
+ $dateformat = ( '' == get_option( 'jd_date_format' ) ) ? get_option( 'date_format' ) : get_option( 'jd_date_format' );
 
581
  $thisdate = mysql2date( $dateformat, $postdate );
582
+ $altdate = mysql2date( 'Y-m-d H:i:s', $postdate );
583
  $values['_postDate'] = $altdate;
584
  $values['postDate'] = $thisdate;
585
  $moddate = $post->post_modified;
586
+ $values['_postModified'] = mysql2date( 'Y-m-d H:i:s', $moddate );
587
  $values['postModified'] = mysql2date( $dateformat, $moddate );
588
+ // get first category.
589
+ $category = null;
590
+ $cat_desc = null;
591
  $categories = get_the_category( $post_ID );
592
+ $cats = array();
593
+ $cat_descs = array();
594
  if ( is_array( $categories ) ) {
595
  if ( count( $categories ) > 0 ) {
596
  $category = $categories[0]->cat_name;
597
  $cat_desc = $categories[0]->description;
598
  }
599
+ foreach ( $categories as $cat ) {
600
  $category_ids[] = $cat->term_id;
601
+ $cats[] = $cat->cat_name;
602
+ $cat_descs[] = $cat->description;
603
  }
604
  $cat_names = implode( ' ', apply_filters( 'wpt_twitter_category_names', $cats ) );
605
  $cat_descs = implode( ' ', apply_filters( 'wpt_twitter_category_descs', $cat_descs ) );
614
  $values['category'] = html_entity_decode( $category, ENT_COMPAT, $encoding );
615
  $values['cat_desc'] = html_entity_decode( $cat_desc, ENT_COMPAT, $encoding );
616
  $excerpt_length = get_option( 'jd_post_excerpt' );
617
+ $post_excerpt = ( '' == trim( $post->post_excerpt ) ) ? mb_substr( strip_tags( strip_shortcodes( $post->post_content ) ), 0, $excerpt_length ) : mb_substr( strip_tags( strip_shortcodes( $post->post_excerpt ) ), 0, $excerpt_length );
618
  $values['postExcerpt'] = html_entity_decode( $post_excerpt, ENT_COMPAT, $encoding );
619
  $thisposttitle = $post->post_title;
620
+ if ( '' == $thisposttitle && isset( $_POST['title'] ) ) {
621
  $thisposttitle = $_POST['title'];
622
  }
623
+ $thisposttitle = strip_tags( apply_filters( 'the_title', stripcslashes( $thisposttitle ) ) );
624
+ // These are common sequences that may not be fixed by html_entity_decode due to double encoding.
625
  $search = array( '&apos;', '&#039;', '&quot;', '&#034;', '&amp;', '&#038;' );
626
  $replace = array( "'", "'", '"', '"', '&', '&' );
627
+ $thisposttitle = str_replace( $search, $replace, $thisposttitle );
628
  $values['postTitle'] = html_entity_decode( $thisposttitle, ENT_QUOTES, $encoding );
629
  $values['postLink'] = wpt_link( $post_ID );
630
  $values['blogTitle'] = get_bloginfo( 'name' );
633
  $values['postType'] = $post->post_type;
634
  /**
635
  * Filters post array to insert custom data that can be used in Tweet process.
636
+ *
637
+ * @param array $values Existing values.
638
+ * @param integer $post_ID Post ID.
639
+ * @return array $values
640
  */
641
+ $values = apply_filters( 'wpt_post_info', $values, $post_ID );
642
 
643
  return $values;
644
  }
645
 
646
  /**
647
  * Retrieve stored short URL.
648
+ *
649
+ * @param int $post_id Post ID.
650
  *
651
  * @return mixed
652
  */
655
  if ( ! $post_id ) {
656
  $post_id = $post_ID;
657
  }
658
+ $use_urls = ( get_option( 'wpt_use_stored_urls' ) == 'false' ) ? false : true;
659
+ $short = ( $use_url ) ? get_post_meta( $post_id, '_wpt_short_url', true ) : false;
660
+
661
  return $short;
662
  }
663
 
664
  /**
665
  * Identify whether a post should be uploading media. Test settings and verify whether post has images that can be uploaded.
666
  *
667
+ * @param int $post_ID Post ID.
668
+ * @param array $post_info Array of post data.
669
  * @return boolean
670
+ */
671
  function wpt_post_with_media( $post_ID, $post_info = array() ) {
672
  $return = false;
673
+ if ( isset( $post_info['wpt_image'] ) && 1 == $post_info['wpt_image'] ) {
674
  return $return;
675
  }
676
 
677
+ if ( ! function_exists( 'wpt_pro_exists' ) || '1' != get_option( 'wpt_media' ) ) {
678
  $return = false;
679
  } else {
680
  if ( has_post_thumbnail( $post_ID ) || wpt_post_attachment( $post_ID ) ) {
686
  }
687
 
688
  /**
689
+ * This function is no longer in use, but the filter within it is.
690
+ *
691
+ * @param string $post_type Type of post.
692
+ * @param array $post_info Post info.
693
+ * @param int $post_ID Post ID.
694
+ *
695
  * @deprecated
696
  */
697
  function wpt_category_limit( $post_type, $post_info, $post_ID ) {
699
  $continue = true;
700
  if ( in_array( 'category', $post_type_cats ) ) {
701
  // 'category' is assigned to this post type, so apply filters.
702
+ if ( '1' == get_option( 'jd_twit_cats' ) ) {
703
  $continue = ( ! wpt_in_allowed_category( $post_info['categoryIds'] ) ) ? true : false;
704
  } else {
705
  $continue = ( wpt_in_allowed_category( $post_info['categoryIds'] ) ) ? true : false;
706
  }
707
  }
708
 
709
+ $continue = ( '0' == get_option( 'limit_categories' ) ) ? true : $continue;
710
+ $args = array(
711
+ 'type' => $post_type,
712
+ 'info' => $post_info,
713
+ 'id' => $post_ID,
714
+ );
715
 
716
  return apply_filters( 'wpt_filter_terms', $continue, $args );
717
  }
718
 
719
  /**
720
+ * Set up a Tweet to be sent.
721
+ *
722
+ * @param int $post_ID Post ID.
723
+ * @param string $type Publishing context (publishing, scheduled, xmlrpc, etc.).
724
+ *
725
+ * @return int $post_ID
726
  */
727
  function wpt_tweet( $post_ID, $type = 'instant' ) {
728
  if ( wp_is_post_autosave( $post_ID ) || wp_is_post_revision( $post_ID ) ) {
729
  return $post_ID;
730
  }
731
+
732
  wpt_check_version();
733
+ $tweet_this = get_post_meta( $post_ID, '_jd_tweet_this', true );
734
+ $newpost = false;
735
+ $oldpost = false;
736
+ $is_inline_edit = false;
737
+ $sentence = '';
738
+ $template = '';
739
+ $nptext = '';
740
+ if ( 1 != get_option( 'wpt_inline_edits' ) ) {
741
  if ( isset( $_POST['_inline_edit'] ) || isset( $_REQUEST['bulk_edit'] ) ) {
742
  return false;
743
  }
746
  $is_inline_edit = true;
747
  }
748
  }
749
+ if ( 0 == get_option( 'jd_tweet_default' ) ) {
750
+ $default = ( 'no' != $tweet_this ) ? true : false;
751
  } else {
752
+ $default = ( 'yes' == $tweet_this ) ? true : false;
753
  }
754
+ wpt_mail( '1: Tweet Template', "$tweet_this / (Original: " . get_option( 'jd_tweet_default' ) . ") / $type" ); // DEBUG.
755
  if ( $default ) { // default switch: depend on default settings.
756
  $post_info = wpt_post_info( $post_ID );
757
  $media = wpt_post_with_media( $post_ID, $post_info );
758
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
759
+ $auth = ( 'false' == get_option( 'wpt_cotweet_lock' ) || ! get_option( 'wpt_cotweet_lock' ) ) ? $post_info['authId'] : get_option( 'wpt_cotweet_lock' );
760
  } else {
761
  $auth = $post_info['authId'];
762
  }
763
+ wpt_mail( '2: POST Debug Data', 'Post_Info: ' . print_r( $post_info, 1 ) . " / $type" ); // DEBUG.
764
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() && function_exists( 'wpt_filter_post_info' ) ) {
 
765
  $filter = wpt_filter_post_info( $post_info );
766
+ if ( true == $filter ) {
767
+ wpt_mail( '3: Post caught by wpt_filter_post_info', print_r( $post_info, 1 ) . " / $type" );
768
 
769
  return false;
770
  }
771
  }
772
+ // Filter Tweet based on POST data -- allows custom filtering of unknown plug-ins, etc.
773
  $filter = apply_filters( 'wpt_filter_post_data', false, $_POST );
774
  if ( $filter ) {
775
  return false;
776
  }
777
  $post_type = $post_info['postType'];
778
+ if ( 'future' == $type || 'future' == get_post_meta( $post_ID, 'wpt_publishing' ) ) {
779
+ $new = 1; // if this is a future action, then it should be published regardless of relationship.
780
+ wpt_mail( '4a: Is a future post', print_r( $post_info, 1 ) . " / $type" );
781
  delete_post_meta( $post_ID, 'wpt_publishing' );
782
  } else {
783
  // if the post modified date and the post date are the same, this is new.
784
+ // true if first date before or equal to last date.
785
  $new = wpt_date_compare( $post_info['_postModified'], $post_info['_postDate'] );
786
  }
787
+ // post is not previously published but has been backdated.
788
+ // (post date is edited, but save option is 'publish').
789
+ if ( 0 == $new && ( isset( $_POST['edit_date'] ) && 1 == $_POST['edit_date'] && ! isset( $_POST['save'] ) ) ) {
790
  $new = 1;
791
  }
792
+ // can't catch posts that were set to a past date as a draft, then published.
793
  $post_type_settings = get_option( 'wpt_post_types' );
794
  $post_types = array_keys( $post_type_settings );
795
  if ( in_array( $post_type, $post_types ) ) {
796
+ // identify whether limited by category/taxonomy.
797
  $continue = wpt_category_limit( $post_type, $post_info, $post_ID );
798
+ if ( false == $continue ) {
799
  return false;
800
  }
801
+ // create Tweet and ID whether current action is edit or new.
802
+ $ct = get_post_meta( $post_ID, '_jd_twitter', true );
803
+ if ( isset( $_POST['_jd_twitter'] ) && '' != $_POST['_jd_twitter'] ) {
804
+ $ct = $_POST['_jd_twitter'];
805
  }
806
+ $custom_tweet = ( '' != $ct ) ? stripcslashes( trim( $ct ) ) : '';
807
  // if ops is set and equals 'publish', this is being edited. Otherwise, it's a new post.
808
+ if ( 0 == $new || true == $is_inline_edit ) {
809
+ // if this is an old post and editing updates are enabled.
810
+ if ( 1 == get_option( 'jd_tweet_default_edit' ) ) {
811
  $tweet_this = apply_filters( 'wpt_tweet_this_edit', $tweet_this, $_POST );
812
+ if ( 'yes' != $tweet_this ) {
813
  return false;
814
  }
815
  }
816
+ wpt_mail( '4b: Is edited post', 'Tweet this: ' . print_r( $post_info, 1 ) . " / $type" ); // DEBUG.
817
+ if ( '1' == $post_type_settings[ $post_type ]['post-edited-update'] ) {
818
  $nptext = stripcslashes( $post_type_settings[ $post_type ]['post-edited-text'] );
819
  $oldpost = true;
820
  }
821
  } else {
822
+ wpt_mail( '4c: Is new post', 'Tweet this: ' . print_r( $post_info, 1 ) . " / $type" ); // DEBUG.
823
+ if ( '1' == $post_type_settings[ $post_type ]['post-published-update'] ) {
824
  $nptext = stripcslashes( $post_type_settings[ $post_type ]['post-published-text'] );
825
  $newpost = true;
826
  }
827
  }
828
  if ( $newpost || $oldpost ) {
829
+ $template = ( '' != $custom_tweet ) ? $custom_tweet : $nptext;
830
  $sentence = jd_truncate_tweet( $template, $post_info, $post_ID );
831
+ wpt_mail( '5: Tweet Truncated', "Truncated Tweet: $sentence / $template / $type" ); // DEBUG.
832
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
833
  $sentence2 = jd_truncate_tweet( $template, $post_info, $post_ID, false, $auth );
834
  }
835
  }
836
+ if ( '' != $sentence ) {
837
+ // WPT PRO.
838
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
839
  $wpt_selected_users = $post_info['wpt_authorized_users'];
840
+ // set up basic author/main account values.
841
  $auth_verified = wtt_oauth_test( $auth, 'verify' );
842
+ if ( empty( $wpt_selected_users ) && 1 == get_option( 'jd_individual_twitter_users' ) ) {
843
  $wpt_selected_users = ( $auth_verified ) ? array( $auth ) : array( false );
844
  }
845
+ if ( 1 == $post_info['wpt_cotweet'] || 1 != get_option( 'jd_individual_twitter_users' ) || in_array( 'main', $wpt_selected_users ) ) {
846
  $wpt_selected_users['main'] = false;
847
  }
848
+ // filter selected users before using.
849
  $wpt_selected_users = apply_filters( 'wpt_filter_users', $wpt_selected_users, $post_info );
850
+ if ( 0 == $post_info['wpt_delay_tweet'] || '' == $post_info['wpt_delay_tweet'] || 'on' == $post_info['wpt_no_delay'] ) {
851
  foreach ( $wpt_selected_users as $acct ) {
852
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
853
  wpt_post_to_twitter( $sentence2, $acct, $post_ID, $media );
855
  }
856
  } else {
857
  foreach ( $wpt_selected_users as $acct ) {
858
+ $acct = ( 'main' == $acct ) ? false : $acct;
859
  $offset = ( $auth != $acct ) ? apply_filters( 'wpt_random_delay', rand( 60, 480 ) ) : 0;
860
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
861
+ $time = apply_filters( 'wpt_schedule_delay', ( (int) $post_info['wpt_delay_tweet'] ) * 60, $acct );
862
  wp_schedule_single_event( time() + $time + $offset, 'wpt_schedule_tweet_action', array(
863
+ 'id' => $acct,
864
+ 'sentence' => $sentence,
865
+ 'rt' => 0,
866
+ 'post_id' => $post_ID,
867
+ ) );
868
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
869
  $author_id = ( $acct ) ? "#$acct" : 'Main';
870
  wpt_mail( "7a: Tweet Scheduled for author $author_id", print_r( array(
871
+ 'id' => $acct,
872
+ 'sentence' => $sentence,
873
+ 'rt' => 0,
874
+ 'post_id' => $post_ID,
875
+ 'timestamp' => time() + $time + $offset,
876
+ 'current_time' => time(),
877
+ 'timezone' => get_option( 'gmt_offset' ),
878
+ 'timestamp_string' => date( 'Y-m-d H:i:s', time() + $time + $offset ),
879
+ 'current_ts' => date( 'Y-m-d H:i:s', time() ),
880
+ ), 1 ) ); // DEBUG.
881
  }
882
  }
883
  }
884
  }
885
+ // This cycle handles scheduling the automatic retweets.
886
+ if ( 0 != $post_info['wpt_retweet_after'] && 'on' != $post_info['wpt_no_repost'] ) {
887
  $repeat = $post_info['wpt_retweet_repeat'];
888
  $first = true;
889
  foreach ( $wpt_selected_users as $acct ) {
893
  if ( $continue ) {
894
  $retweet = apply_filters( 'wpt_set_retweet_text', $template, $i );
895
  $retweet = jd_truncate_tweet( $retweet, $post_info, $post_ID, true, $acct );
896
+ // add original delay to schedule.
897
  $delay = ( isset( $post_info['wpt_delay_tweet'] ) ) ? ( (int) $post_info['wpt_delay_tweet'] ) * 60 : 0;
898
+ // Don't delay the first Tweet of the group.
899
+ $offset = ( true == $first ) ? 0 : rand( 60, 240 ); // delay each co-tweet by 1-4 minutes.
900
+ $time = apply_filters( 'wpt_schedule_retweet', ( $post_info['wpt_retweet_after'] ) * ( 60 * 60 ) * $i, $acct, $i, $post_info );
901
  wp_schedule_single_event( time() + $time + $offset + $delay, 'wpt_schedule_tweet_action', array(
902
+ 'id' => $acct,
903
+ 'sentence' => $retweet,
904
+ 'rt' => $i,
905
+ 'post_id' => $post_ID,
906
+ ) );
907
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
908
  if ( $acct ) {
909
  $author_id = "#$acct";
911
  $author_id = 'Main';
912
  }
913
  wpt_mail( "7b: Retweet Scheduled for author $author_id", print_r( array(
914
+ 'id' => $acct,
915
+ 'sentence' => array( $retweet, $i, $post_ID ),
916
+ 'timestamp' => time() + $time + $offset + $delay,
917
+ 'time' => array( $time, $offset, $delay, get_option( 'gmt_offset' ), time() ),
918
+ 'timestring' => date( 'Y-m-d H:i:s', time() + $time + $offset + $delay ),
919
+ 'current_ts' => date( 'Y-m-d H:i:s', time() ),
920
+ ), 1 ), true ); // DEBUG.
 
 
 
 
 
 
921
  }
922
  $tweet_limit = apply_filters( 'wpt_tweet_repeat_limit', 4, $post_ID );
923
  if ( $i == $tweet_limit ) {
932
  } else {
933
  wpt_post_to_twitter( $sentence, false, $post_ID, $media );
934
  }
935
+ // END WPT PRO.
936
  }
937
  } else {
938
  if ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) {
939
+ wpt_mail( '3c: Not a Tweeted post type', 'Post_Info: ' . print_r( $post_info, 1 ) . " / $type" );
940
  }
941
 
942
  return $post_ID;
948
 
949
  /**
950
  * Send Tweets on links in link manager. Only active if Link plug-in is installed.
951
+ *
952
+ * @param integer $link_id Database ID for link.
953
+ *
954
  * @return mixed boolean/integer link ID if successful, false if failure.
955
  */
956
+ function wpt_twit_link( $link_id ) {
957
  wpt_check_version();
958
  $thislinkprivate = $_POST['link_visible'];
959
+ if ( 'N' != $thislinkprivate ) {
960
+ $thislinkname = stripslashes( $_POST['link_name'] );
961
  $thispostlink = $_POST['link_url'];
962
  $thislinkdescription = stripcslashes( $_POST['link_description'] );
963
  $sentence = stripcslashes( get_option( 'newlink-published-text' ) );
964
+ $sentence = str_ireplace( '#title#', $thislinkname, $sentence );
965
+ $sentence = str_ireplace( '#description#', $thislinkdescription, $sentence );
966
 
967
  if ( mb_strlen( $sentence ) > 118 ) {
968
  $sentence = mb_substr( $sentence, 0, 114 ) . '...';
969
  }
970
  $shrink = apply_filters( 'wptt_shorten_link', $thispostlink, $thislinkname, false, 'link' );
971
+ if ( false === stripos( $sentence, '#url#' ) ) {
972
+ $sentence = $sentence . ' ' . $shrink;
973
  } else {
974
+ $sentence = str_ireplace( '#url#', $shrink, $sentence );
975
  }
976
+
977
+ if ( false === stripos( $sentence, '#longurl#' ) ) {
978
+ $sentence = $sentence . ' ' . $thispostlink;
979
  } else {
980
+ $sentence = str_ireplace( '#longurl#', $thispostlink, $sentence );
981
  }
982
+
983
+ if ( '' != $sentence ) {
984
+ wpt_post_to_twitter( $sentence, false, $link_id );
985
  }
986
 
987
+ return $link_id;
988
  } else {
989
  return false;
990
  }
991
  }
992
 
993
+ /**
994
  * Generate hash tags from tags set on post.
 
 
995
  *
996
+ * @param int $post_ID Post ID.
997
+ *
998
+ * @return string $hashtags Hashtags in format needed for Tweet.
999
  */
1000
  function wpt_generate_hash_tags( $post_ID ) {
1001
  $hashtags = '';
1002
+ $term_meta = false;
1003
+ $t_id = false;
1004
  $max_tags = get_option( 'jd_max_tags' );
1005
  $max_characters = get_option( 'jd_max_characters' );
1006
+ $max_characters = ( 0 == $max_characters || '' == $max_characters ) ? 100 : $max_characters + 1;
1007
+ if ( 0 == $max_tags || '' == $max_tags ) {
1008
  $max_tags = 100;
1009
  }
1010
+ $use_cats = ( '1' == get_option( 'wpt_use_cats' ) ) ? true : false;
1011
+ $tags = ( true == $use_cats ) ? wp_get_post_categories( $post_ID, array( 'fields' => 'all' ) ) : get_the_tags( $post_ID );
1012
  $tags = apply_filters( 'wpt_hash_source', $tags, $post_ID );
1013
  if ( $tags && count( $tags ) > 0 ) {
1014
  $i = 1;
1017
  $t_id = $value->term_id;
1018
  $term_meta = get_option( "wpt_taxonomy_$t_id" );
1019
  }
1020
+ if ( 'slug' == get_option( 'wpt_tag_source' ) ) {
1021
  $tag = $value->slug;
1022
  } else {
1023
  $tag = $value->name;
1024
  }
1025
  $strip = get_option( 'jd_strip_nonan' );
1026
+ $search = '/[^\p{L}\p{N}\s]/u';
1027
  $replace = get_option( 'jd_replace_character' );
1028
+ $replace = ( '[ ]' == $replace || '' == $replace ) ? '' : $replace;
1029
+ $tag = str_ireplace( ' ', $replace, trim( $tag ) );
1030
  $tag = preg_replace( '/[\/]/', $replace, $tag ); // remove forward slashes.
1031
+ $tag = ( '1' == $strip ) ? preg_replace( $search, $replace, $tag ) : $tag;
1032
+
1033
  switch ( $term_meta ) {
1034
+ case 1:
1035
+ $newtag = "#$tag";
1036
+ break;
1037
+ case 2:
1038
+ $newtag = "$$tag";
1039
+ break;
1040
+ case 3:
1041
+ $newtag = '';
1042
+ break;
1043
+ case 4:
1044
+ $newtag = $tag;
1045
+ break;
1046
+ default:
1047
+ $newtag = apply_filters( 'wpt_tag_default', '#', $t_id ) . $tag;
1048
  }
1049
  if ( mb_strlen( $newtag ) > 2 && ( mb_strlen( $newtag ) <= $max_characters ) && ( $i <= $max_tags ) ) {
1050
  $hashtags .= "$newtag ";
1054
  }
1055
  $hashtags = trim( $hashtags );
1056
  if ( mb_strlen( $hashtags ) <= 1 ) {
1057
+ $hashtags = '';
1058
  }
1059
 
1060
  return $hashtags;
1061
  }
1062
 
1063
  add_action( 'admin_menu', 'wpt_add_twitter_outer_box' );
1064
+ /**
1065
  * Set up post meta box.
1066
  */
1067
  function wpt_add_twitter_outer_box() {
1071
  if ( function_exists( 'add_meta_box' ) ) {
1072
  if ( is_array( $wpt_post_types ) ) {
1073
  foreach ( $wpt_post_types as $key => $value ) {
1074
+ if ( 1 == $value['post-published-update'] || 1 == $value['post-edited-update'] ) {
1075
  add_meta_box( 'wp2t', 'WP to Twitter', 'wpt_add_twitter_inner_box', $key, 'side' );
1076
  }
1077
  }
1081
 
1082
 
1083
  add_action( 'admin_menu', 'wpt_add_twitter_debug_box' );
1084
+ /**
1085
  * Set up post meta box.
1086
  */
1087
  function wpt_add_twitter_debug_box() {
1092
  if ( function_exists( 'add_meta_box' ) ) {
1093
  if ( is_array( $wpt_post_types ) ) {
1094
  foreach ( $wpt_post_types as $key => $value ) {
1095
+ if ( 1 == $value['post-published-update'] || 1 == $value['post-edited-update'] ) {
1096
  add_meta_box( 'wp2t-debug', 'WP to Twitter Debugging', 'wpt_show_debug', $key, 'advanced' );
1097
  }
1098
  }
1099
  }
1100
  }
1101
  }
1102
+ }
1103
+
1104
+
1105
  /**
1106
  * Print post meta box
1107
+ *
1108
+ * @param object $post Post object.
1109
  */
1110
  function wpt_add_twitter_inner_box( $post ) {
1111
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1114
  <?php
1115
  $tweet_status = '';
1116
  $options = get_option( 'wpt_post_types' );
1117
+ $type = $post->post_type;
1118
+ $status = $post->post_status;
1119
+ $post_id = $post->ID;
1120
+ $tweet_this = get_post_meta( $post_id, '_jd_tweet_this', true );
 
1121
  if ( ! $tweet_this ) {
1122
+ $tweet_this = ( '1' == get_option( 'jd_tweet_default' ) ) ? 'no' : 'yes';
1123
  }
1124
+ if ( isset( $_GET['action'] ) && 'edit' == $_GET['action'] && '1' == get_option( 'jd_tweet_default_edit' ) && 'publish' == $status ) {
1125
  $tweet_this = 'no';
1126
  }
1127
+ if ( isset( $_REQUEST['message'] ) && 10 != $_REQUEST['message'] ) {
1128
+ // don't display when draft is updated or if no message.
1129
+ if ( ! ( ( 1 == $_REQUEST['message'] ) && ( 'publish' == $status && 1 != $options[ $type ]['post-edited-update'] ) ) && 'no' != $tweet_this ) {
1130
  $log = wpt_log( 'wpt_status_message', $post_id );
1131
+ $class = ( __( 'Tweet sent successfully.', 'wp-to-twitter' ) != $log ) ? 'error' : 'updated';
1132
+ if ( '' != $log ) {
1133
  echo "<div class='$class'><p>$log</p></div>";
1134
  }
1135
  }
1136
  }
1137
+ $tweet = esc_attr( stripcslashes( get_post_meta( $post_id, '_jd_twitter', true ) ) );
1138
+ $tweet = apply_filters( 'wpt_user_text', $tweet, $status );
1139
+ $template = ( 'publish' == $status ) ? $options[ $type ]['post-edited-text'] : $options[ $type ]['post-published-text'];
 
 
1140
 
1141
+ if ( 'publish' == $status && 1 != $options[ $type ]['post-edited-update'] ) {
1142
+ // Translators: post type.
1143
  $tweet_status = sprintf( __( '%s will not be Tweeted on update.', 'wp-to-twitter' ), ucfirst( $type ) );
1144
  }
1145
 
1146
+ if ( 'publish' == $status && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1147
  ?>
1148
  <div class='tweet-buttons'>
1149
  <button type='button' class='tweet button-primary' data-action='tweet'><span class='dashicons dashicons-twitter' aria-hidden='true'></span><?php _e( 'Tweet Now', 'wp-to-twitter' ); ?></button>
1150
+ <?php
1151
+ if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) {
1152
+ ?>
1153
+ <button type='button' class='tweet schedule button-secondary' data-action='schedule' disabled><?php _e( 'Schedule', 'wp-to-twitter' ); ?></button>
1154
+ <button type='button' class='time button-secondary'>
1155
+ <span class="dashicons dashicons-clock" aria-hidden="true"></span><span class="screen-reader-text"><?php _e( 'Set Date/Time', 'wp-to-twitter' ); ?></span>
1156
+ </button>
1157
+ <div id="jts">
1158
+ <label for='wpt_date'><?php _e( 'Date', 'wp-to-twitter' ); ?></label>
1159
+ <input type='date' value='' class='wpt_date date' name='wpt_datetime' id='wpt_date' data-value='<?php echo date( 'Y-m-d', current_time( 'timestamp' ) ); ?>' /><br/>
1160
+ <label for='wpt_time'><?php _e( 'Time', 'wp-to-twitter' ); ?></label>
1161
+ <input type='text' value='<?php echo date_i18n( 'h:s a', current_time( 'timestamp' ) + 3600 ); ?>' class='wpt_time time' name='wpt_datetime' id='wpt_time'/>
1162
+ </div>
1163
+ <?php
1164
+ }
1165
+ ?>
1166
  <div class='wpt_log' aria-live='assertive'></div>
1167
  </div>
1168
  <?php
1170
  if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1171
  ?>
1172
  <p class='jtw'>
1173
+ <label for="jtw"><?php _e( 'Custom Twitter Post', 'wp-to-twitter' ); ?></label><br/>
1174
  <textarea class="wpt_tweet_box" name="_jd_twitter" id="jtw" rows="2" cols="60"><?php echo esc_attr( $tweet ); ?></textarea>
1175
+ <?php echo apply_filters( 'wpt_custom_box', '', $tweet, $post_id ); ?>
1176
  </p>
1177
  <?php
1178
  $expanded = $template;
1179
+ if ( '' != get_option( 'jd_twit_prepend' ) ) {
1180
+ $expanded = "<span title='" . __( 'Your prepended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_prepend' ) ) . '</span> ' . $expanded;
1181
  }
1182
+ if ( '' != get_option( 'jd_twit_append' ) ) {
1183
+ $expanded = $expanded . " <span title='" . __( 'Your appended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_append' ) ) . '</span>';
1184
  }
1185
  ?>
1186
  <p class='template'>
1195
  echo "<label for='yourls_keyword'>" . __( 'YOURLS Custom Keyword', 'wp-to-twitter' ) . "</label> <input type='text' name='_yourls_keyword' id='yourls_keyword' value='$custom_keyword' />";
1196
  }
1197
  } else {
1198
+ ?>
1199
+ <input type="hidden" name='_jd_twitter' value='<?php echo esc_attr( $tweet ); ?>'/>
1200
  <?php
1201
  }
1202
  ?>
1203
  <div class='wpt-options'>
1204
+ <?php
1205
+ if ( 'pro' == $is_pro ) {
1206
+ $pro_active = " class='active'";
1207
+ $free_active = '';
1208
+ } else {
1209
+ $free_active = " class='active'";
1210
+ $pro_active = '';
1211
+ }
1212
+ ?>
1213
+ <ul class='tabs' role="tablist">
1214
+ <?php if ( get_option( 'jd_individual_twitter_users' ) == 1 ) { ?>
1215
+ <li><a href='#authors'<?php echo $pro_active; ?> aria-controls="authors" role="tab" id="tab_authors"><?php _e( 'Tweet to', 'wp-to-twitter' ); ?></a></li>
1216
+ <?php } ?>
1217
+ <li><a href='#custom' aria-controls="custom" role="tab" id="tab_custom"><?php _e( 'Options', 'wp-to-twitter' ); ?></a></li>
1218
+ <li><a href='#notes'<?php echo $free_active; ?> aria-controls="notes" role="tab" id="tab_notes"><?php _e( 'Notes', 'wp-to-twitter' ); ?></a></li>
1219
+ </ul>
1220
+ <?php
1221
+ // WPT PRO OPTIONS.
1222
+ if ( current_user_can( 'edit_others_posts' ) ) {
1223
+ if ( 1 == get_option( 'jd_individual_twitter_users' ) ) {
1224
+ echo "<div class='wptab' id='authors' aria-labelledby='tab_authors' role='tabpanel'>";
1225
+ $selected = ( get_post_meta( $post_id, '_wpt_authorized_users', true ) ) ? get_post_meta( $post_id, '_wpt_authorized_users', true ) : array();
1226
+ if ( function_exists( 'wpt_authorized_users' ) ) {
1227
+ echo wpt_authorized_users( $selected );
1228
+ do_action( 'wpt_authors_tab', $post_id, $selected );
1229
+ } else {
1230
+ echo '<p>';
1231
+ if ( function_exists( 'wpt_pro_exists' ) ) {
1232
+ // Translators: URL to account.
1233
+ printf( __( 'WP Tweets PRO allows you to select Twitter accounts. <a href="%s">Log in and download now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/account/' );
1234
  } else {
1235
+ // Translators: URL to buy WP Tweets Pro.
1236
+ printf( __( 'Upgrade to WP Tweets PRO to select Twitter accounts! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' );
 
 
 
 
 
1237
  }
1238
+ echo '</p>';
1239
+ }
1240
+ echo '</div>';
1241
  }
1242
+ }
1243
+ ?>
1244
+ <div class='wptab' id='custom' aria-labelledby='tab_custom' role='tabpanel'>
1245
+ <?php
1246
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() && ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) ) {
1247
+ wpt_schedule_values( $post_id );
1248
+ do_action( 'wpt_custom_tab', $post_id, 'visible' );
1249
+ } else {
1250
+ if ( ! function_exists( 'wpt_pro_exists' ) ) {
1251
+ // Translators: premium sales link.
1252
+ echo '<p>' . sprintf( __( 'Upgrade to WP Tweets PRO to configure options! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' ) . '</p>';
1253
+ }
1254
+ }
1255
+ ?>
1256
+ </div>
1257
+ <?php
1258
+ // WPT PRO.
1259
+ if ( ! current_user_can( 'wpt_twitter_custom' ) && ! current_user_can( 'manage_options' ) ) {
1260
  ?>
1261
+ <div class='wptab' id='custom' aria-labelledby='tab_custom' role='tabpanel'>
1262
+ <p><?php _e( 'Access to customizing WP to Twitter values is not allowed for your user role.', 'wp-to-twitter' ); ?></p>
1263
+ <?php
1264
+ if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
1265
+ wpt_schedule_values( $post_id, 'hidden' );
1266
+ do_action( 'wpt_custom_tab', $post_id, 'hidden' );
 
 
1267
  }
1268
  ?>
1269
+ </div>
1270
+ <?php
1271
+ }
1272
+ if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1273
+ ?>
1274
+ <div class='wptab' id='notes' aria-labelledby='tab_notes' role='tabpanel'>
1275
+ <p>
1276
+ <?php
1277
+ _e( 'Template Tags: <code>#url#</code>, <code>#title#</code>, <code>#post#</code>, <code>#category#</code>, <code>#date#</code>, <code>#modified#</code>, <code>#author#</code>, <code>#account#</code>, <code>#tags#</code>, <code>#blog#</code>, <code>#longurl#</code>.', 'wp-to-twitter' );
1278
+ do_action( 'wpt_notes_tab', $post_id );
 
 
 
 
 
 
1279
  ?>
1280
+ </p>
1281
+ </div>
1282
+ <?php
1283
+ }
1284
+ ?>
 
 
 
 
1285
  </div>
1286
  <?php
1287
  if ( current_user_can( 'wpt_twitter_switch' ) || current_user_can( 'manage_options' ) ) {
1288
  // "no" means 'Don't Tweet' (is checked)
1289
+ $nochecked = ( 'no' == $tweet_this ) ? ' checked="checked"' : '';
1290
+ $yeschecked = ( 'yes' == $tweet_this ) ? ' checked="checked"' : '';
1291
+ ?>
1292
+ <p class='toggle-btn-group'>
1293
+ <input type="radio" name="_jd_tweet_this" value="no" id="jtn"<?php echo $nochecked; ?> /><label for="jtn"><?php _e( "Don't Tweet", 'wp-to-twitter' ); ?></label>
1294
+ <input type="radio" name="_jd_tweet_this" value="yes" id="jty"<?php echo $yeschecked; ?> /><label for="jty"><?php _e( 'Tweet', 'wp-to-twitter' ); ?></label>
1295
+ </p>
1296
  <?php
1297
  } else {
1298
+ ?>
1299
+ <input type='hidden' name='_jd_tweet_this' value='<?php echo $tweet_this; ?>'/>
1300
  <?php
1301
  }
1302
+ wpt_show_tweets( $post_id );
1303
  ?>
1304
  <p class="wpt-support">
1305
+ <?php
1306
+ if ( ! function_exists( 'wpt_pro_exists' ) ) {
1307
  ?>
1308
+ <strong><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Go Premium', 'wp-to-twitter' ); ?></a></strong> &raquo;
1309
+ <?php
1310
+ } else {
1311
+ ?>
1312
+ <a href="<?php echo esc_url( add_query_arg( 'tab', 'support', admin_url( 'admin.php?page=wp-tweets-pro' ) ) ); ?>#get-support"><?php _e( 'Get Support', 'wp-to-twitter' ); ?></a> &raquo;
1313
+ <?php
1314
+ }
1315
+ ?>
1316
+ </p>
1317
+ <?php
1318
+ if ( '' != $tweet_status ) {
1319
  echo "<p class='disabled'>$tweet_status</p>";
1320
  }
1321
  ?>
1322
  </div>
1323
  <?php
1324
+ } else {
1325
+ // permissions: this user isn't allowed to Tweet.
1326
+ _e( 'Your role does not have the ability to Post Tweets from this site.', 'wp-to-twitter' );
1327
+ ?>
1328
+ <input type='hidden' name='_jd_tweet_this' value='no'/>
1329
+ <?php
1330
  }
1331
  }
1332
 
1333
  /**
1334
  * Format history of Tweets attempted on current post.
1335
+ *
1336
+ * @param array $post_id Post ID to fetch Tweets on.
 
 
 
1337
  */
1338
+ function wpt_show_tweets( $post_id ) {
1339
+ $previous_tweets = get_post_meta( $post_id, '_jd_wp_twitter', true );
1340
+ $failed_tweets = get_post_meta( $post_id, '_wpt_failed' );
1341
+
1342
+ if ( ! is_array( $previous_tweets ) && '' != $previous_tweets ) {
1343
  $previous_tweets = array( 0 => $previous_tweets );
1344
  }
1345
  if ( ! empty( $previous_tweets ) || ! empty( $failed_tweets ) ) {
1346
+ ?>
1347
+ <hr>
1348
+ <p class='panel-toggle'>
1349
+ <a href='#wpt_tweet_history' class='history-toggle'><span class='dashicons dashicons-plus' aria-hidden="true"></span><?php _e( 'View Tweet History', 'wp-to-twitter' ); ?></a>
1350
+ </p>
1351
+ <div class='history'>
1352
+ <p class='error'><em><?php _e( 'Previous Tweets', 'wp-to-twitter' ); ?>:</em></p>
1353
+ <ul>
1354
+ <?php
1355
+ $has_history = false;
1356
+ $hidden_fields = '';
1357
+ if ( is_array( $previous_tweets ) ) {
1358
+ foreach ( $previous_tweets as $previous_tweet ) {
1359
+ if ( '' != $previous_tweet ) {
1360
+ $has_history = true;
1361
+ $hidden_fields .= "<input type='hidden' name='_jd_wp_twitter[]' value='" . esc_attr( $previous_tweet ) . "' />";
1362
+ echo "<li>$previous_tweet <a href='http://twitter.com/intent/tweet?text=" . urlencode( $previous_tweet ) . "'>Retweet this</a></li>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1363
  }
1364
+ }
1365
+ }
1366
+ ?>
1367
+ </ul>
1368
+ <?php
1369
+ $list = false;
1370
+ $error_list = '';
1371
+ if ( is_array( $failed_tweets ) ) {
1372
+ foreach ( $failed_tweets as $failed_tweet ) {
1373
+ if ( ! empty( $failed_tweet ) ) {
1374
+ $ft = $failed_tweet['sentence'];
1375
+ $reason = $failed_tweet['code'];
1376
+ $error = $failed_tweet['error'];
1377
+ $list = true;
1378
+ $error_list .= "<li> <code>Error: $reason</code> $ft <a href='http://twitter.com/intent/tweet?text=" . urlencode( $ft ) . "'>Tweet this</a><br /><em>$error</em></li>";
1379
  }
1380
  }
1381
+ if ( true == $list ) {
1382
+ echo "<p class='error'><em>" . __( 'Failed Tweets', 'wp-to-twitter' ) . ":</em></p>
1383
+ <ul>$error_list</ul>";
1384
  }
1385
+ }
1386
+ echo '<div>' . $hidden_fields . '</div>';
1387
+ if ( $has_history || $list ) {
1388
+ echo "<p><input type='checkbox' name='wpt_clear_history' id='wptch' value='clear' /> <label for='wptch'>" . __( 'Delete Tweet History', 'wp-to-twitter' ) . '</label></p>';
1389
+ }
1390
+ ?>
1391
+ </div>
1392
+ <?php
1393
  }
1394
  }
1395
 
1399
  */
1400
  function wpt_admin_scripts() {
1401
  global $current_screen, $wpt_version;
1402
+ if ( 'post' == $current_screen->base || 'wp-tweets-pro_page_wp-to-twitter-schedule' == $current_screen->id ) {
1403
  wp_enqueue_script( 'charCount', plugins_url( 'wp-to-twitter/js/jquery.charcount.js' ), array( 'jquery' ), $wpt_version );
1404
  }
1405
+ if ( 'post' == $current_screen->base && isset( $_GET['post'] ) && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1406
  wp_enqueue_script( 'wpt.ajax', plugins_url( 'js/ajax.js', __FILE__ ), array( 'jquery' ), $wpt_version );
1407
  wp_localize_script( 'wpt.ajax', 'wpt_data', array(
1408
  'post_ID' => (int) $_GET['post'],
1409
  'action' => 'wpt_tweet',
1410
+ 'security' => wp_create_nonce( 'wpt-tweet-nonce' ),
1411
  ) );
1412
  }
1413
+ if ( 'settings_page_wp-to-twitter/wp-to-twitter' == $current_screen->id || 'toplevel_page_wp-tweets-pro' == $current_screen->id ) {
1414
  wp_enqueue_script( 'wpt.tabs', plugins_url( 'js/tabs.js', __FILE__ ), array( 'jquery' ), $wpt_version );
1415
  wp_localize_script( 'wpt.tabs', 'firstItem', 'wpt_post' );
1416
  wp_localize_script( 'wpt.tabs', 'firstPerm', 'wpt_editor' );
1421
  add_action( 'wp_ajax_wpt_tweet', 'wpt_ajax_tweet' );
1422
  /**
1423
  * Handle Tweets sent via Ajax Tweet Now/Schedule Tweet buttons.
 
 
1424
  */
1425
  function wpt_ajax_tweet() {
1426
  if ( ! check_ajax_referer( 'wpt-tweet-nonce', 'security', false ) ) {
1427
+ echo 'Invalid Security Check';
1428
  die;
1429
  }
1430
+ $action = ( 'tweet' == $_REQUEST['tweet_action'] ) ? 'tweet' : 'schedule';
1431
+ $authors = ( isset( $_REQUEST['tweet_auth'] ) && null != $_REQUEST['tweet_auth'] ) ? $_REQUEST['tweet_auth'] : false;
1432
+ $upload = ( isset( $_REQUEST['tweet_upload'] ) && null != $_REQUEST['tweet_upload'] ) ? $_REQUEST['tweet_upload'] : 1;
1433
  $current_user = wp_get_current_user();
1434
  if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) {
1435
  if ( wtt_oauth_test( $current_user->ID, 'verify' ) ) {
1436
+ $auth = $current_user->ID;
1437
+ $user_ID = $current_user->ID;
1438
  } else {
1439
  $auth = false;
1440
  $user_ID = $current_user->ID;
1444
  $user_ID = $current_user->ID;
1445
  }
1446
 
1447
+ $authors = ( is_array( $authors ) && ! empty( $authors ) ) ? $authors : array( $auth );
1448
+
1449
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1450
  $options = get_option( 'wpt_post_types' );
1451
  $post_ID = intval( $_REQUEST['tweet_post_id'] );
1452
  $type = get_post_type( $post_ID );
1453
  $default = ( isset( $options[ $type ]['post-edited-text'] ) ) ? $options[ $type ]['post-edited-text'] : '';
1454
+ $sentence = ( isset( $_REQUEST['tweet_text'] ) && '' != trim( $_REQUEST['tweet_text'] ) ) ? $_REQUEST['tweet_text'] : $default;
1455
  $sentence = stripcslashes( trim( $sentence ) );
1456
+ $post_info = wpt_post_info( $post_ID );
1457
  $sentence = jd_truncate_tweet( $sentence, $post_info, $post_ID, false, $user_ID );
1458
  $schedule = ( isset( $_REQUEST['tweet_schedule'] ) ) ? strtotime( $_REQUEST['tweet_schedule'] ) : rand( 60, 240 );
1459
  $print_schedule = date_i18n( get_option( 'date_format' ) . ' @ ' . get_option( 'time_format' ), $schedule );
1460
  $offset = ( 60 * 60 * get_option( 'gmt_offset' ) );
1461
  $schedule = $schedule - $offset;
1462
+ $media = ( 1 == $upload ) ? false : true; // this is correct; the boolean logic is reversed. Blah.
1463
+
1464
+ foreach ( $authors as $auth ) {
1465
+
1466
+ $auth = ( 'main' == $auth ) ? false : $auth;
1467
+
1468
  switch ( $action ) {
1469
+ case 'tweet':
1470
  wpt_post_to_twitter( $sentence, $auth, $post_ID, $media );
1471
  break;
1472
+ case 'schedule':
1473
  wp_schedule_single_event( $schedule, 'wpt_schedule_tweet_action', array(
1474
+ 'id' => $auth,
1475
+ 'sentence' => $sentence,
1476
+ 'rt' => 0,
1477
+ 'post_id' => $post_ID,
1478
+ ) );
1479
  break;
1480
  }
1481
+ // Translators: Full text of Tweet, time scheduled for.
1482
+ $return = ( 'tweet' == $action ) ? wpt_log( 'wpt_status_message', $post_ID ) : sprintf( __( 'Tweet scheduled: %1$s for %2$s', 'wp-tweets-pro' ), '"' . $sentence . '"', $print_schedule );
1483
  echo $return;
1484
  if ( count( $authors ) > 1 ) {
1485
+ echo '<br />';
1486
  }
1487
  }
1488
  } else {
1493
 
1494
  add_action( 'admin_head', 'wpt_admin_script' );
1495
  /**
1496
+ * Print scripts to WP Tweets PRO pages.
1497
  */
1498
  function wpt_admin_script() {
1499
  global $current_screen;
1500
+ if ( 'post' == $current_screen->base || 'wp-tweets-pro_page_wp-to-twitter-schedule' == $current_screen->id ) {
1501
  wp_register_style( 'wpt-post-styles', plugins_url( 'css/post-styles.css', __FILE__ ) );
1502
  wp_enqueue_style( 'wpt-post-styles' );
1503
  $config = wpt_max_length();
1504
  // add one; character count starts from 1.
1505
+ if ( 'post' == $current_screen->base ) {
1506
  $allowed = $config['base_length'] - mb_strlen( stripslashes( get_option( 'jd_twit_prepend' ) . get_option( 'jd_twit_append' ) ) ) + 1;
1507
  } else {
1508
  $allowed = $config['base_length'] + 1;
1509
  }
1510
+ if ( function_exists( 'wpt_pro_exists' ) && 1 == get_option( 'jd_individual_twitter_users' ) ) {
1511
  $first = '#authors';
1512
+ } elseif ( function_exists( 'wpt_pro_exists' ) ) {
1513
  $first = '#custom';
1514
  } else {
1515
  $first = '#notes';
1517
  wp_register_script( 'wpt-base-js', plugins_url( 'js/base.js', __FILE__ ), array( 'jquery' ) );
1518
  wp_enqueue_script( 'wpt-base-js' );
1519
  wp_localize_script( 'wpt-base-js', 'wptSettings', array(
1520
+ 'allowed' => $allowed,
1521
+ 'first' => $first,
1522
+ 'is_ssl' => ( wpt_is_ssl( home_url() ) ) ? 'true' : 'false',
1523
+ 'text' => __( 'Characters left: ', 'wp-to-twitter' ),
1524
+ ) );
1525
  echo "
1526
  <style type='text/css'>
1527
+ #wp2t h3 span, #wp2t h2 span { padding-left: 30px; background: url(" . plugins_url( 'wp-to-twitter/images/twitter-bird-light-bgs.png' ) . ') left 50% no-repeat; }
1528
+ </style>';
1529
  }
1530
  }
1531
 
1533
  * Post the Custom Tweet & custom Tweet data into the post meta table
1534
  *
1535
  * @param integer $id Post ID.
 
1536
  */
1537
  function wpt_save_post( $id ) {
1538
  if ( empty( $_POST ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || wp_is_post_revision( $id ) || isset( $_POST['_inline_edit'] ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || ! wpt_in_post_type( $id ) ) {
1542
  $yourls = $_POST['_yourls_keyword'];
1543
  $update = update_post_meta( $id, '_yourls_keyword', $yourls );
1544
  }
1545
+ if ( isset( $_POST['_jd_twitter'] ) && '' != $_POST['_jd_twitter'] ) {
1546
  $twitter = $_POST['_jd_twitter'];
1547
+ $update = update_post_meta( $id, '_jd_twitter', $twitter );
1548
+ } elseif ( isset( $_POST['_jd_twitter'] ) && '' == $_POST['_jd_twitter'] ) {
1549
  delete_post_meta( $id, '_jd_twitter' );
1550
  }
1551
+ if ( isset( $_POST['_jd_wp_twitter'] ) && '' != $_POST['_jd_wp_twitter'] ) {
1552
  $wp_twitter = $_POST['_jd_wp_twitter'];
1553
+ $update = update_post_meta( $id, '_jd_wp_twitter', $wp_twitter );
1554
  }
1555
  if ( isset( $_POST['_jd_tweet_this'] ) ) {
1556
+ $tweet_this = ( 'no' == $_POST['_jd_tweet_this'] ) ? 'no' : 'yes';
1557
+ $update = update_post_meta( $id, '_jd_tweet_this', $tweet_this );
1558
  } else {
1559
  if ( isset( $_POST['_wpnonce'] ) ) {
1560
+ $tweet_default = ( 1 == get_option( 'jd_tweet_default' ) ) ? 'no' : 'yes';
1561
+ $update = update_post_meta( $id, '_jd_tweet_this', $tweet_default );
1562
  }
1563
  }
1564
+ if ( isset( $_POST['wpt_clear_history'] ) && 'clear' == $_POST['wpt_clear_history'] ) {
1565
  delete_post_meta( $id, '_wpt_failed' );
1566
  delete_post_meta( $id, '_jd_wp_twitter' );
1567
  delete_post_meta( $id, '_wpt_short_url' );
1568
  delete_post_meta( $id, '_wp_jd_twitter' );
1569
  }
1570
+ // WPT PRO.
1571
  $update = apply_filters( 'wpt_insert_post', $_POST, $id );
1572
+ // WPT PRO.
1573
+ // only send debug data if post meta is updated.
1574
+ if ( true == $update || is_int( $update ) ) {
1575
+ wpt_mail( 'Post Meta Inserted', print_r( $_POST, 1 ) ); // DEBUG.
1576
  }
1577
+ if ( isset( $_POST['wpt-delete-debug'] ) && 'true' == $_POST['wpt-delete-debug'] ) {
1578
  delete_post_meta( $id, '_wpt_debug_log' );
1579
  }
1580
+ if ( isset( $_POST['wpt-delete-all-debug'] ) && 'true' == $_POST['wpt-delete-all-debug'] ) {
1581
  delete_post_meta_by_key( '_wpt_debug_log' );
1582
  }
1583
  }
1584
 
1585
  /**
1586
  * Show user profile data on Edit User pages.
 
 
1587
  */
1588
  function wpt_twitter_profile() {
1589
  global $user_ID;
1590
  $current_user = wp_get_current_user();
1591
+ $user_edit = ( isset( $_GET['user_id'] ) ) ? (int) $_GET['user_id'] : $user_ID;
1592
 
1593
  $is_enabled = get_user_meta( $user_edit, 'wp-to-twitter-enable-user', true );
1594
  $twitter_username = get_user_meta( $user_edit, 'wp-to-twitter-user-username', true );
1595
  $wpt_remove = get_user_meta( $user_edit, 'wpt-remove', true );
1596
+ if ( current_user_can( 'wpt_twitter_oauth' ) || current_user_can( 'manage_options' ) ) {
1597
  ?>
1598
  <h3><?php _e( 'WP Tweets User Settings', 'wp-to-twitter' ); ?></h3>
1599
+ <?php
1600
+ if ( function_exists( 'wpt_connect_oauth_message' ) ) {
1601
  wpt_connect_oauth_message( $user_edit );
1602
+ }
1603
+ ?>
1604
  <table class="form-table">
1605
  <tr>
1606
+ <th scope="row"><?php _e( 'Use My Twitter Username', 'wp-to-twitter' ); ?></th>
1607
  <td>
1608
+ <input type="radio" name="wp-to-twitter-enable-user" id="wp-to-twitter-enable-user-3" value="mainAtTwitter"<?php checked( $is_enabled, 'mainAtTwitter' ); ?> /> <label for="wp-to-twitter-enable-user-3"><?php _e( 'Tweet my posts with an @ reference to my username.', 'wp-to-twitter' ); ?></label><br/>
1609
+ <input type="radio" name="wp-to-twitter-enable-user" id="wp-to-twitter-enable-user-4" value="mainAtTwitterPlus"<?php checked( $is_enabled, 'mainAtTwitterPlus' ); ?> /> <label for="wp-to-twitter-enable-user-4"><?php _e( 'Tweet my posts with an @ reference to both my username and to the main site username.', 'wp-to-twitter' ); ?></label>
1610
  </td>
1611
  </tr>
1612
  <tr>
1613
+ <th scope="row">
1614
+ <label for="wp-to-twitter-user-username"><?php _e( 'Your Twitter Username', 'wp-to-twitter' ); ?></label>
1615
  </th>
1616
+ <td>
1617
+ <input type="text" name="wp-to-twitter-user-username" id="wp-to-twitter-user-username" value="<?php echo esc_attr( $twitter_username ); ?>"/> <?php _e( 'Enter your own Twitter username.', 'wp-to-twitter' ); ?>
1618
  </td>
1619
  </tr>
1620
  <tr>
1621
+ <th scope="row">
1622
+ <label for="wpt-remove"><?php _e( 'Hide account name in Tweets', 'wp-to-twitter' ); ?></label></th>
1623
+ <td>
1624
+ <input type="checkbox" name="wpt-remove" id="wpt-remove" value="on"<?php checked( 'on', $wpt_remove ); ?>/> <?php _e( 'Do not display my account in the #account# template tag.', 'wp-to-twitter' ); ?>
 
 
1625
  </td>
1626
  </tr>
1627
  <?php echo apply_filters( 'wpt_twitter_user_fields', $user_edit ); ?>
1634
  }
1635
  } else {
1636
  // hidden fields. If function is enabled, but this user does not have privileges to edit.
1637
+ ?>
1638
+ <input type="hidden" name="wp-to-twitter-enable-user" value="<?php echo esc_attr( $is_enabled ); ?>" />
1639
+ <input type="hidden" name="wp-to-twitter-user-username" value="<?php echo esc_attr( $twitter_username ); ?>" />
1640
+ <input type="hidden" name="wpt-remove" value="<?php echo esc_attr( $wpt_remove ); ?>" />
1641
+ <?php
1642
  }
1643
  }
1644
 
1646
  * This compensates for an old error where the user ID is echoed directly into the page.
1647
  */
1648
  add_filter( 'wpt_twitter_user_fields', 'wpt_basic_user_fields', 100, 1 );
1649
+ /**
1650
+ * Return empty string if value is an integer.
1651
+ *
1652
+ * @param int $user_edit User ID.
1653
+ *
1654
+ * @return empty string.
1655
+ */
1656
  function wpt_basic_user_fields( $user_edit ) {
1657
  if ( is_int( $user_edit ) ) {
1658
  return '';
1659
  }
1660
+
1661
  return $user_edit;
1662
  }
1663
 
1664
+ /**
1665
+ * Save user profile data
1666
  */
1667
+ function wpt_twitter_save_profile() {
1668
  global $user_ID;
1669
  $current_user = wp_get_current_user();
1670
  if ( isset( $_POST['user_id'] ) ) {
1672
  } else {
1673
  $edit_id = $user_ID;
1674
  }
1675
+ if ( current_user_can( 'wpt_twitter_oauth' ) || current_user_can( 'manage_options' ) ) {
1676
  $enable = ( isset( $_POST['wp-to-twitter-enable-user'] ) ) ? $_POST['wp-to-twitter-enable-user'] : '';
1677
  $username = ( isset( $_POST['wp-to-twitter-user-username'] ) ) ? $_POST['wp-to-twitter-user-username'] : '';
1678
  $wpt_remove = ( isset( $_POST['wpt-remove'] ) ) ? 'on' : '';
1680
  update_user_meta( $edit_id, 'wp-to-twitter-user-username', $username );
1681
  update_user_meta( $edit_id, 'wpt-remove', $wpt_remove );
1682
  }
1683
+ // WPT PRO.
1684
  apply_filters( 'wpt_save_user', $edit_id, $_POST );
1685
  }
1686
 
1687
+ add_action( 'init', 'wpt_old_admin_redirect' );
1688
  /**
1689
  * Send links to old admin to new admin page
1690
  */
 
1691
  function wpt_old_admin_redirect() {
1692
+ if ( is_admin() && isset( $_GET['page'] ) && 'wp-to-twitter/wp-to-twitter.php' == $_GET['page'] ) {
1693
  wp_safe_redirect( admin_url( 'admin.php?page=wp-tweets-pro' ) );
1694
  exit;
1695
  }
1702
  function wpt_admin_page() {
1703
  if ( function_exists( 'add_menu_page' ) && ! function_exists( 'wpt_pro_functions' ) ) {
1704
  $icon_path = plugins_url( 'images/icon.png', __FILE__ );
1705
+ $page = add_menu_page( __( 'WP to Twitter', 'wp-to-twitter' ), __( 'WP to Twitter', 'wp-to-twitter' ), 'manage_options', 'wp-tweets-pro', 'wpt_update_settings', $icon_path );
1706
  }
1707
  }
1708
 
1709
  add_action( 'admin_head', 'wpt_admin_style' );
1710
+ /**
1711
  * Add stylesheets to WP to Twitter pages.
1712
  */
1713
  function wpt_admin_style() {
1714
+ if ( isset( $_GET['page'] ) && ( 'wp-to-twitter' == $_GET['page'] || 'wp-tweets-pro' == $_GET['page'] || 'wp-to-twitter-schedule' == $_GET['page'] || 'wp-to-twitter-tweets' == $_GET['page'] || 'wp-to-twitter-errors' == $_GET['page'] ) ) {
1715
  wp_enqueue_style( 'wpt-styles', plugins_url( 'css/styles.css', __FILE__ ) );
1716
  }
1717
  }
1718
 
1719
+ /**
1720
  * Add WP to Twitter links to plug-in information.
1721
+ *
1722
+ * @param array $links Array of links.
1723
+ * @param string $file Current file name.
1724
+ *
1725
+ * @return link new array.
1726
  */
1727
  function wpt_plugin_action( $links, $file ) {
1728
+ if ( plugin_basename( dirname( __FILE__ ) . '/wp-to-twitter.php' ) == $file ) {
1729
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
1730
+ $links[] = "<a href='$admin_url'>" . __( 'WP to Twitter Settings', 'wp-to-twitter' ) . '</a>';
1731
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1732
+ $links[] = "<a href='http://www.wptweetspro.com/wp-tweets-pro'>" . __( 'Go Premium', 'wp-to-twitter' ) . '</a>';
1733
  }
1734
  }
1735
 
1736
  return $links;
1737
  }
1738
 
1739
+ // Add Plugin Actions to WordPress.
1740
+ add_filter( 'plugin_action_links', 'wpt_plugin_action', 10, 2 );
1741
 
1742
+ if ( '1' == get_option( 'jd_individual_twitter_users' ) ) {
1743
  add_action( 'show_user_profile', 'wpt_twitter_profile' );
1744
  add_action( 'edit_user_profile', 'wpt_twitter_profile' );
1745
  add_action( 'profile_update', 'wpt_twitter_save_profile' );
1748
  add_action( 'in_plugin_update_message-wp-to-twitter/wp-to-twitter.php', 'wpt_plugin_update_message' );
1749
  /**
1750
  * Parse plugin update info to display in update list.
 
 
1751
  */
1752
  function wpt_plugin_update_message() {
1753
  global $wpt_version;
1757
  if ( ! is_wp_error( $response ) || is_array( $response ) ) {
1758
  $data = $response['body'];
1759
  $bits = explode( '== Upgrade Notice ==', $data );
1760
+ $note = '</div><div id="wpt-upgrade" class="notice inline notice-warning"><ul><li><strong style="color:#c22;">Upgrade Notes:</strong> ' . str_replace( '* ', '', nl2br( trim( $bits[1] ) ) ) . '</li></ul>';
1761
  }
1762
+
1763
  echo $note;
1764
  }
1765
 
1766
+ if ( '1' == get_option( 'jd_twit_blogroll' ) ) {
1767
  add_action( 'add_link', 'wpt_twit_link' );
1768
  }
1769
 
1770
  add_action( 'save_post', 'wpt_twit', 15 );
1771
  add_action( 'save_post', 'wpt_save_post', 10 );
 
1772
  /**
1773
  * Check whether a given post is in an allowed post type and has an update template configured.
1774
+ *
1775
  * @param integer $id Post ID.
1776
  *
1777
  * @return boolean True if post is allowed, false otherwise.
1778
  */
1779
  function wpt_in_post_type( $id ) {
1780
  $post_type_settings = get_option( 'wpt_post_types' );
1781
+ if ( is_array( $post_type_settings ) && ! empty( $post_type_settings ) ) {
1782
+ $post_types = array_keys( $post_type_settings );
1783
+ $type = get_post_type( $id );
1784
  if ( in_array( $type, $post_types ) ) {
1785
+ if ( '1' == $post_type_settings[ $type ]['post-edited-update'] || '1' == $post_type_settings[ $type ]['post-published-update'] ) {
1786
  return true;
1787
  }
1788
  }
1789
  }
1790
+
1791
  return false;
1792
  }
1793
 
1794
  add_action( 'future_to_publish', 'wpt_future_to_publish', 16 );
1795
  /**
1796
  * Handle Tweeting posts scheduled for the future.
1797
+ *
1798
+ * @param object $post Post object.
1799
  */
1800
  function wpt_future_to_publish( $post ) {
1801
  $id = $post->ID;
1807
 
1808
  /**
1809
  * Handle Tweeting posts published directly.
1810
+ *
1811
+ * @param object $id Post ID.
1812
  */
1813
  function wpt_twit( $id ) {
1814
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $id ) || ! wpt_in_post_type( $id ) ) {
1815
  return;
1816
  }
1817
+ $post = get_post( $id );
1818
+ if ( 'publish' != $post->post_status ) {
1819
  return;
1820
+ }
1821
  // is there any reason to accept any other status?
1822
+ // This is an issue only until the release of WP 4.7.
 
1823
  remove_action( 'save_post', 'wpt_twit', 15 );
1824
  wpt_twit_instant( $id );
1825
  add_action( 'save_post', 'wpt_twit', 15 );
1835
  */
1836
  function wpt_twit_future( $id ) {
1837
  set_transient( '_wpt_twit_future', $id, 10 );
1838
+ // instant action has already run for this post. // prevent running actions twice (need both for older WP).
1839
  if ( get_transient( '_wpt_twit_instant' ) && get_transient( '_wpt_twit_instant' ) == $id ) {
1840
  delete_transient( '_wpt_twit_instant' );
1841
 
1842
  return;
1843
  }
1844
+
1845
  wpt_tweet( $id, 'future' );
1846
  }
1847
 
1867
  wpt_tweet( $id, 'instant' );
1868
  }
1869
 
1870
+ /**
1871
  * Tweet XMLRPC posts.
1872
+ *
1873
+ * @param integer $id Post ID.
1874
+ *
1875
+ * @return post ID.
1876
  */
1877
  function wpt_twit_xmlrpc( $id ) {
1878
  set_transient( '_wpt_twit_xmlrpc', $id, 10 );
1888
  * Set an option indicating that a job has been scheduled for promoting WP Tweets PRO.
1889
  */
1890
  function wpt_schedule_promotion() {
1891
+ if ( ! function_exists( 'wpt_pro_exists' ) && 1 == get_option( 'wpt_promotion_scheduled' ) ) {
1892
  update_option( 'wpt_promotion_scheduled', 2 );
1893
  }
1894
  }
1897
  * Dismiss promotion notice.
1898
  */
1899
  function wpt_dismiss_promotion() {
1900
+ if ( isset( $_GET['dismiss'] ) && 'promotion' == $_GET['dismiss'] ) {
1901
  update_option( 'wpt_promotion_scheduled', 3 );
1902
  }
1903
  }
1905
  add_action( 'admin_notices', 'wpt_dismiss_promotion', 5 );
1906
  add_action( 'admin_notices', 'wpt_promotion_notice', 10 );
1907
  add_action( 'admin_notices', 'wpt_debugging_enabled', 10 );
1908
+ /**
1909
+ * Show notice is Twitter debugging is enabled.
1910
+ */
1911
  function wpt_debugging_enabled() {
1912
  if ( current_user_can( 'manage_options' ) && WPT_DEBUG ) {
1913
+ echo "<div class='notice error important'><p>" . __( '<strong>WP to Twitter</strong> debugging is enabled. Remember to disable debugging when you are finished.', 'wp-to-twitter' ) . '</p></div>';
1914
+ }
1915
  }
1916
 
1917
  /**
1918
  * Display promotion notice to admin users who have not donated or purchased WP Tweets PRO.
1919
  */
1920
  function wpt_promotion_notice() {
1921
+ if ( current_user_can( 'activate_plugins' ) && 2 == get_option( 'wpt_promotion_scheduled' ) && 1 != get_option( 'jd_donations' ) ) {
1922
+ $upgrade = 'http://www.wptweetspro.com/wp-tweets-pro/';
1923
  $dismiss = admin_url( 'admin.php?page=wp-tweets-pro&dismiss=promotion' );
1924
+ // Translators: URL to upgrade.
1925
+ echo "<div class='notice'><p>" . sprintf( __( 'I hope you\'ve enjoyed <strong>WP to Twitter</strong>! Take a look at <a href=\'%1$s\'>upgrading to WP Tweets PRO</a> for advanced Tweeting with WordPress! <a href=\'%2$s\'>Dismiss</a>', 'wp-to-twitter' ), $upgrade, $dismiss ) . '</p></div>';
1926
  }
1927
  }
1928
 
1944
  * Check whether Twitter Feed styles are enabled.
1945
  *
1946
  * @param boolean $value true if permitted.
1947
+ *
1948
  * @return boolean $value False if settings disable styles.
1949
  */
1950
  function wpt_permit_feed_styles( $value ) {
1951
+ if ( 1 == get_option( 'wpt_permit_feed_styles' ) ) {
1952
  $value = false;
1953
  }
1954
 
1955
  return $value;
1956
  }
1957
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1958
  add_action( 'admin_head', 'wpt_css' );
1959
+ /**
1960
+ * Output CSS governing styles for authorized users column.
1961
+ */
1962
  function wpt_css() {
1963
+ ?>
1964
  <style type="text/css">
1965
  th#wpt {
1966
  width: 60px;
1975
  </style>
1976
  <?php
1977
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
wpt-functions.php CHANGED
@@ -1,38 +1,102 @@
1
  <?php
2
- // This file contains secondary functions supporting WP to Twitter
 
 
 
 
 
 
 
 
3
 
4
  if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
- } // Exit if accessed directly
7
 
8
- // FUNCTION to see if checkboxes should be checked
9
- function jd_checkCheckbox( $field, $sub1 = false, $sub2 = '' ) {
 
 
 
 
 
 
 
 
 
 
10
  if ( $sub1 ) {
11
  $setting = get_option( $field );
12
  if ( isset( $setting[ $sub1 ] ) ) {
13
- $value = ( $sub2 != '' ) ? $setting[ $sub1 ][ $sub2 ] : $setting[ $sub1 ];
14
  } else {
15
  $value = 0;
16
  }
17
- if ( $value == 1 ) {
18
  return 'checked="checked"';
19
  }
20
  }
21
- if ( get_option( $field ) == '1' ) {
22
  return 'checked="checked"';
23
  }
24
  return '';
25
  }
26
 
27
- function jd_checkSelect( $field, $value, $type = 'select' ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  if ( get_option( $field ) == $value ) {
29
- return ( $type == 'select' ) ? 'selected="selected"' : 'checked="checked"';
30
  }
31
  return '';
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  function wpt_set_log( $data, $id, $message ) {
35
- if ( $id == 'test' ) {
36
  update_option( $data, $message );
37
  } else {
38
  update_post_meta( $id, '_' . $data, $message );
@@ -40,10 +104,18 @@ function wpt_set_log( $data, $id, $message ) {
40
  update_option( $data . '_last', array( $id, $message ) );
41
  }
42
 
 
 
 
 
 
 
 
 
43
  function wpt_log( $data, $id ) {
44
- if ( $id == 'test' ) {
45
  $log = get_option( $data );
46
- } else if ( $id == 'last' ) {
47
  $log = get_option( $data . '_last' );
48
  } else {
49
  $log = get_post_meta( $id, '_' . $data, true );
@@ -52,77 +124,81 @@ function wpt_log( $data, $id ) {
52
  return $log;
53
  }
54
 
 
 
 
55
  function wpt_check_functions() {
56
  $message = "<div class='update'><ul>";
57
- // grab or set necessary variables
58
- $testurl = get_bloginfo( 'url' );
59
- $testpost = false;
60
- $title = urlencode( 'Your blog home' );
61
- $shrink = apply_filters( 'wptt_shorten_link', $testurl, $title, false, true );
62
- if ( $shrink == false ) {
63
- $error = htmlentities( get_option( 'wpt_shortener_status' ) );
64
- $message .= __( "<li class=\"error\"><strong>WP to Twitter was unable to contact your selected URL shortening service.</strong></li>", 'wp-to-twitter' );
65
- if ( $error != '' ) {
66
  $message .= "<li><code>$error</code></li>";
67
  } else {
68
- $message .= "<li><code>" . __( 'No error message was returned.', 'wp-to-twitter' ) . "</code></li>";
69
  }
70
  } else {
71
  $message .= __( "<li><strong>WP to Twitter successfully contacted your URL shortening service.</strong> This link should point to your site's homepage:", 'wp-to-twitter' );
72
  $message .= " <a href='$shrink'>$shrink</a></li>";
73
  }
74
- //check twitter credentials
75
  if ( wtt_oauth_test() ) {
76
  $rand = rand( 1000000, 9999999 );
77
  $testpost = wpt_post_to_twitter( "This is a test of WP to Twitter. $shrink ($rand)" );
78
  if ( $testpost ) {
79
- $message .= __( "<li><strong>WP to Twitter successfully submitted a status update to Twitter.</strong></li>", 'wp-to-twitter' );
80
  } else {
81
- $error = wpt_log( 'wpt_status_message', 'test' );
82
- $message .= __( "<li class=\"error\"><strong>WP to Twitter failed to submit an update to Twitter.</strong></li>", 'wp-to-twitter' );
83
- $message .= "<li class=\"error\">$error</li>";
84
  }
85
  } else {
86
- $message .= "<strong>" . _e( 'You have not connected WordPress to Twitter.', 'wp-to-twitter' ) . "</strong> ";
87
  }
88
- // If everything's OK, there's no reason to do this again.
89
- if ( $testpost == false && $shrink == false ) {
90
  $message .= __( "<li class=\"error\"><strong>Your server does not appear to support the required methods for WP to Twitter to function.</strong> You can try it anyway - these tests aren't perfect.</li>", 'wp-to-twitter' );
91
- } else {
92
  }
93
  if ( $testpost && $shrink ) {
94
- $message .= __( "<li><strong>Your server should run WP to Twitter successfully.</strong></li>", 'wp-to-twitter' );
95
  }
96
- $message .= "</ul>
97
- </div>";
98
 
99
  return $message;
100
  }
101
 
 
 
 
102
  function wpt_settings_tabs() {
103
- $output = '';
104
- $default = ( get_option( 'wtt_twitter_username' ) == '' ) ? 'connection' : 'basic';
105
- $current = ( isset( $_GET['tab'] ) ) ? $_GET['tab'] : $default;
106
  $pro_text = ( function_exists( 'wpt_pro_exists' ) ) ? __( 'Pro Settings', 'wp-to-twitter' ) : __( 'Get WP Tweets PRO', 'wp-to-twitter' );
107
- $pages = array(
108
- 'connection'=> __( 'Twitter Connection', 'wp-to-twitter' ),
109
- 'basic'=> __( 'Basic Settings', 'wp-to-twitter' ),
110
- 'shortener'=> __( 'URL Shortener', 'wp-to-twitter' ),
111
- 'advanced' => __( 'Advanced Settings', 'wp-to-twitter' ),
112
- 'support' => __( 'Get Help', 'wp-to-twitter' ),
113
- 'pro' => $pro_text
114
  );
115
- if ( get_option( 'jd_donations' ) == '1' && !function_exists( 'wpt_pro_exists' ) ) {
116
  unset( $pages['pro'] );
117
  }
118
-
119
- $pages = apply_filters( 'wpt_settings_tabs_pages', $pages, $current );
120
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
121
 
122
  foreach ( $pages as $key => $value ) {
123
- $selected = ( $key == $current ) ? " nav-tab-active" : '';
124
- $url = esc_url( add_query_arg( 'tab', $key, $admin_url ) );
125
- if ( $key == 'pro' ) {
126
  $output .= "<a class='wpt-pro-tab nav-tab$selected' href='$url'>$value</a>";
127
  } else {
128
  $output .= "<a class='nav-tab$selected' href='$url'>$value</a>";
@@ -131,6 +207,9 @@ function wpt_settings_tabs() {
131
  echo $output;
132
  }
133
 
 
 
 
134
  function wpt_show_last_tweet() {
135
  if ( apply_filters( 'wpt_show_last_tweet', true ) ) {
136
  $log = wpt_log( 'wpt_status_message', 'last' );
@@ -140,7 +219,7 @@ function wpt_show_last_tweet() {
140
  if ( is_object( $post ) ) {
141
  $title = "<a href='" . get_edit_post_link( $post_ID ) . "'>$post->post_title</a>";
142
  } else {
143
- $title = __( 'No post associated with this Tweet', 'wp-to-twitter' );
144
  }
145
  $notice = $log[1];
146
  echo "<div class='updated'><p><strong>" . __( 'Last Tweet', 'wp-to-twitter' ) . "</strong>: $title &raquo; $notice</p></div>";
@@ -148,20 +227,21 @@ function wpt_show_last_tweet() {
148
  }
149
  }
150
 
151
-
 
 
152
  function wpt_handle_errors() {
153
- if ( isset( $_POST['submit-type'] ) && $_POST['submit-type'] == 'clear-error' ) {
154
  delete_option( 'wp_url_failure' );
155
  }
156
- if ( get_option( 'wp_url_failure' ) == '1' ) {
157
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
158
- $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
159
- $error = '<div class="error">' .
160
- __( "<p>The query to the URL shortener API failed, and your URL was not shrunk. The full post URL was attached to your Tweet. Check with your URL shortening provider to see if there are any known issues.</p>", 'wp-to-twitter' ) .
161
  '<form method="post" action="' . $admin_url . '">
162
  <div>
163
  <input type="hidden" name="submit-type" value="clear-error"/>
164
- '. $nonce . '
165
  </div>
166
  <p>
167
  <input type="submit" name="submit" value="' . __( "Clear 'WP to Twitter' Error Messages", 'wp-to-twitter' ) . '" class="button-primary" />
@@ -171,7 +251,15 @@ function wpt_handle_errors() {
171
  echo $error;
172
  }
173
  }
174
- // verify user capabilities
 
 
 
 
 
 
 
 
175
  function wpt_check_caps( $role, $cap ) {
176
  $role = get_role( $role );
177
  if ( $role->has_cap( $cap ) ) {
@@ -180,13 +268,28 @@ function wpt_check_caps( $role, $cap ) {
180
  return '';
181
  }
182
 
183
- // output checkbox for user capabilities
 
 
 
 
 
 
 
 
184
  function wpt_cap_checkbox( $role, $cap, $name ) {
185
  return "<li><input type='checkbox' id='wpt_caps_{$role}_$cap' name='wpt_caps[$role][$cap]' value='on'" . wpt_check_caps( $role, $cap ) . " /> <label for='wpt_caps_{$role}_$cap'>$name</label></li>";
186
  }
187
 
188
- function wpt_mail( $subject, $body, $override=false ) {
189
- if ( ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) || $override == true ) {
 
 
 
 
 
 
 
190
  if ( WPT_DEBUG_BY_EMAIL ) {
191
  wp_mail( WPT_DEBUG_ADDRESS, $subject, $body, WPT_FROM );
192
  } else {
@@ -195,6 +298,12 @@ function wpt_mail( $subject, $body, $override=false ) {
195
  }
196
  }
197
 
 
 
 
 
 
 
198
  function wpt_debug_log( $subject, $body ) {
199
  global $post_ID;
200
  if ( $post_ID ) {
@@ -203,17 +312,20 @@ function wpt_debug_log( $subject, $body ) {
203
  }
204
  }
205
 
 
 
 
206
  function wpt_show_debug() {
207
  global $post_ID;
208
  if ( WPT_DEBUG ) {
209
- $records = '';
210
  $debug_log = get_post_meta( $post_ID, '_wpt_debug_log' );
211
  if ( is_array( $debug_log ) ) {
212
- foreach( $debug_log as $entry ) {
213
- $date = date_i18n( 'Y-m-d H:i', $entry[0] );
214
- $subject = $entry[1];
215
- $body = $entry[2];
216
- $records .= "<li><button type='button' class='toggle-debug button-secondary' aria-expanded='false'><strong>$date</strong>:<br />$subject</button><pre class='wpt-debug-details'>" . esc_html( $body ) . "</pre></li>";
217
  }
218
  }
219
  $script = "
@@ -227,7 +339,7 @@ function wpt_show_debug() {
227
  $( this ).attr( 'aria-expanded', 'false' );
228
  } else {
229
  $( this ).next( 'pre' ).show();
230
- $( this ).attr( 'aria-expanded', 'true' );
231
  }
232
  });
233
  })
@@ -235,38 +347,48 @@ function wpt_show_debug() {
235
  </script>";
236
  $delete = "<ul>
237
  <li><input type='checkbox' name='wpt-delete-debug' value='true' id='wpt-delete-debug'> <label for='wpt-delete-debug'>" . __( 'Delete debugging logs on this post', 'wp-to-twitter' ) . "</label></li>
238
- <li><input type='checkbox' name='wpt-delete-all-debug' value='true' id='wpt-delete-all-debug'> <label for='wpt-delete-all-debug'>" . __( 'Delete debugging logs for all posts', 'wp-to-twitter' ) . "</label></li>
239
- </ul>";
240
-
241
- echo ( $records != '' ) ? "$script<div class='wpt-debug-log'><h3>Debugging Log:</h3><ul>$records</ul></div>$delete" : '';
242
  }
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
245
  function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
246
  $input = wpt_fetch_url( $url, $method );
247
  wpt_mail( 'Remote JSON input', print_r( $input, 1 ) . "\n\n" . $url );
248
- $obj = json_decode( $input, $array );
249
  wpt_mail( 'Remote JSON return value', print_r( $obj, 1 ) . "\n\n" . "$url" );
250
- if ( function_exists( 'json_last_error' ) ) { // > PHP 5.3
251
  try {
252
  if ( is_null( $obj ) ) {
253
  switch ( json_last_error() ) {
254
- case JSON_ERROR_DEPTH :
255
  $msg = ' - Maximum stack depth exceeded';
256
  break;
257
- case JSON_ERROR_STATE_MISMATCH :
258
  $msg = ' - Underflow or the modes mismatch';
259
  break;
260
- case JSON_ERROR_CTRL_CHAR :
261
  $msg = ' - Unexpected control character found';
262
  break;
263
- case JSON_ERROR_SYNTAX :
264
  $msg = ' - Syntax error, malformed JSON';
265
  break;
266
- case JSON_ERROR_UTF8 :
267
  $msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded';
268
  break;
269
- default :
270
  $msg = ' - Unknown error';
271
  break;
272
  }
@@ -280,6 +402,13 @@ function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
280
  return $obj;
281
  }
282
 
 
 
 
 
 
 
 
283
  function wpt_is_valid_url( $url ) {
284
  if ( is_string( $url ) ) {
285
  $url = urldecode( $url );
@@ -290,19 +419,30 @@ function wpt_is_valid_url( $url ) {
290
  }
291
  }
292
 
293
- // Fetch a remote page. Input url, return content
 
 
 
 
 
 
 
 
 
 
294
  function wpt_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $return = 'body' ) {
295
  $request = new WP_Http;
296
- $result = $request->request( $url, array( 'method' => $method,
297
- 'body' => $body,
298
- 'headers' => $headers,
299
- 'sslverify' => false,
300
- 'user-agent' => 'WP to Twitter/http://www.joedolson.com/wp-to-twitter/'
301
- ) );
302
- // Success?
 
303
  if ( ! is_wp_error( $result ) && isset( $result['body'] ) ) {
304
- if ( $result['response']['code'] == 200 ) {
305
- if ( $return == 'body' ) {
306
  return $result['body'];
307
  } else {
308
  return $result;
@@ -310,63 +450,63 @@ function wpt_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $retur
310
  } else {
311
  return $result['response']['code'];
312
  }
313
- // Failure (server problem...)
314
  } else {
315
  return false;
316
  }
317
  }
318
 
319
  if ( ! function_exists( 'mb_substr_split_unicode' ) ) {
320
- function mb_substr_split_unicode( $str, $splitPos ) {
321
- if ( $splitPos == 0 ) {
 
 
 
 
 
 
 
 
322
  return 0;
323
- }
324
- $byteLen = strlen( $str );
325
-
326
- if ( $splitPos > 0 ) {
327
- if ( $splitPos > 256 ) {
328
- // Optimize large string offsets by skipping ahead N bytes.
329
- // This will cut out most of our slow time on Latin-based text,
330
- // and 1/2 to 1/3 on East European and Asian scripts.
331
- $bytePos = $splitPos;
332
- while ( $bytePos < $byteLen && $str[$bytePos] >= "\x80" && $str[$bytePos] < "\xc0" ) {
333
- ++$bytePos;
334
- }
335
- $charPos = mb_strlen( substr( $str, 0, $bytePos ) );
336
- } else {
337
- $charPos = 0;
338
- $bytePos = 0;
339
- }
340
-
341
- while ( $charPos++ < $splitPos ) {
342
- ++$bytePos;
343
- // Move past any tail bytes
344
- while ( $bytePos < $byteLen && $str[$bytePos] >= "\x80" && $str[$bytePos] < "\xc0" ) {
345
- ++$bytePos;
346
- }
347
- }
348
- } else {
349
- $splitPosX = $splitPos + 1;
350
- $charPos = 0; // relative to end of string; we don't care about the actual char position here
351
- $bytePos = $byteLen;
352
- while ( $bytePos > 0 && $charPos-- >= $splitPosX ) {
353
- --$bytePos;
354
- // Move past any tail bytes
355
- while ( $bytePos > 0 && $str[$bytePos] >= "\x80" && $str[$bytePos] < "\xc0" ) {
356
- --$bytePos;
357
- }
358
- }
359
- }
360
-
361
- return $bytePos;
362
- }
363
- }
364
 
365
- // filter_var substitution for PHP <5.2
366
- if ( ! function_exists( 'filter_var' ) ) {
367
- function filter_var( $url ) {
368
- // this does not emulate filter_var; merely the usage of filter_var in WP to Twitter.
369
- return ( stripos( $url, 'https:' ) !== false || stripos( $url, 'http:' ) !== false ) ? true : false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  }
371
  }
372
 
@@ -374,9 +514,9 @@ if ( ! function_exists( 'mb_strrpos' ) ) {
374
  /**
375
  * Fallback implementation of mb_strrpos, hardcoded to UTF-8.
376
  *
377
- * @param $haystack String
378
- * @param $needle String
379
- * @param $offset integer: optional start position
380
  *
381
  * @return int
382
  */
@@ -386,9 +526,7 @@ if ( ! function_exists( 'mb_strrpos' ) ) {
386
  $ar = array();
387
  preg_match_all( '/' . $needle . '/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
388
 
389
- if ( isset( $ar[0] ) && count( $ar[0] ) > 0 &&
390
- isset( $ar[0][ count( $ar[0] ) - 1 ][1] )
391
- ) {
392
  return $ar[0][ count( $ar[0] ) - 1 ][1];
393
  } else {
394
  return false;
@@ -396,60 +534,14 @@ if ( ! function_exists( 'mb_strrpos' ) ) {
396
  }
397
  }
398
 
399
- // str_ireplace substitution for PHP4
400
- if ( ! function_exists( 'str_ireplace' ) ) {
401
- function str_ireplace( $needle, $str, $haystack ) {
402
- $needle = preg_quote( $needle, '/' );
403
-
404
- return preg_replace( "/$needle/i", $str, $haystack );
405
- }
406
- }
407
- // str_split substitution for PHP4
408
- if ( ! function_exists( 'str_split' ) ) {
409
- function str_split( $string, $string_length = 1 ) {
410
- if ( strlen( $string ) > $string_length || ! $string_length ) {
411
- do {
412
- $parts[] = substr( $string, 0, $string_length );
413
- $string = substr( $string, $string_length );
414
- } while ( $string !== false );
415
- } else {
416
- $parts = array( $string );
417
- }
418
-
419
- return $parts;
420
- }
421
- }
422
- // mb_substr_replace substition for PHP4
423
- if ( ! function_exists( 'mb_substr_replace' ) ) {
424
- function mb_substr_replace( $string, $replacement, $start, $length = null, $encoding = null ) {
425
- if ( extension_loaded( 'mbstring' ) === true ) {
426
- $string_length = ( is_null( $encoding ) === true ) ? mb_strlen( $string ) : mb_strlen( $string, $encoding );
427
- if ( $start < 0 ) {
428
- $start = max( 0, $string_length + $start );
429
- } else if ( $start > $string_length ) {
430
- $start = $string_length;
431
- }
432
- if ( $length < 0 ) {
433
- $length = max( 0, $string_length - $start + $length );
434
- } else if ( ( is_null( $length ) === true ) || ( $length > $string_length ) ) {
435
- $length = $string_length;
436
- }
437
- if ( ( $start + $length ) > $string_length ) {
438
- $length = $string_length - $start;
439
- }
440
- if ( is_null( $encoding ) === true ) {
441
- return mb_substr( $string, 0, $start ) . $replacement . mb_substr( $string, $start + $length, $string_length - $start - $length );
442
- }
443
-
444
- return mb_substr( $string, 0, $start, $encoding ) . $replacement . mb_substr( $string, $start + $length, $string_length - $start - $length, $encoding );
445
- }
446
-
447
- return ( is_null( $length ) === true ) ? substr_replace( $string, $replacement, $start ) : substr_replace( $string, $replacement, $start, $length );
448
- }
449
- }
450
-
451
  /**
452
  * This function is obsolete; only exists for people using out of date versions of WP Tweets PRO.
 
 
 
 
 
 
453
  */
454
  function wtt_option_selected( $field, $value, $type = 'checkbox' ) {
455
  switch ( $type ) {
@@ -460,7 +552,8 @@ function wtt_option_selected( $field, $value, $type = 'checkbox' ) {
460
  case 'option':
461
  $result = ' selected="selected"';
462
  break;
463
- default: $result = ' selected="selected"';
 
464
  }
465
  if ( $field == $value ) {
466
  $output = $result;
@@ -473,17 +566,17 @@ function wtt_option_selected( $field, $value, $type = 'checkbox' ) {
473
 
474
  /**
475
  * Compares two dates to identify which is earlier. Used to differentiate between post edits and original publication.
476
- *
477
- * @param string $modified
478
- * @param string $late
479
- *
480
  * @return integer 1|0
481
- */
482
  function wpt_date_compare( $modified, $postdate ) {
483
  $modifier = apply_filters( 'wpt_edit_sensitivity', 0 ); // alter time in seconds to modified date.
484
- $mod_date = strtotime( $modified );
485
- $post_date = strtotime( $postdate ) + $modifier;
486
- if ( $mod_date <= $post_date ) { // if post_modified is before or equal to post_date
487
  return 1;
488
  } else {
489
  return 0;
@@ -493,12 +586,12 @@ function wpt_date_compare( $modified, $postdate ) {
493
  /**
494
  * Gets the first attachment for the supplied post.
495
  *
496
- * @param integer $post_ID The post ID
497
  *
498
  * @return mixed boolean|integer Attachment ID.
499
  */
500
  function wpt_post_attachment( $post_ID ) {
501
- $return = false;
502
  $use_featured_image = apply_filters( 'wpt_use_featured_image', true, $post_ID );
503
  if ( has_post_thumbnail( $post_ID ) && $use_featured_image ) {
504
  $attachment = get_post_thumbnail_id( $post_ID );
@@ -511,66 +604,69 @@ function wpt_post_attachment( $post_ID ) {
511
  'post_status' => 'published',
512
  'post_parent' => $post_ID,
513
  'post_mime_type' => 'image',
514
- 'order' => 'ASC'
515
  );
516
  $attachments = get_posts( $args );
517
  if ( $attachments ) {
518
- $return = $attachments[0]->ID; //Return the first attachment.
519
  } else {
520
  $return = false;
521
  }
522
  }
523
-
524
  return apply_filters( 'wpt_post_attachment', $return, $post_ID );
525
  }
526
 
 
 
 
527
  function wpt_get_support_form() {
528
  global $current_user, $wpt_version;
529
- $current_user = wp_get_current_user();
530
- $request = '';
531
  $response_email = '';
532
- // send fields for WP to Twitter
533
- $license = ( get_option( 'wpt_license_key' ) != '' ) ? get_option( 'wpt_license_key' ) : 'none';
534
- if ( $license != 'none' ) {
535
- $valid = ( ( get_option( 'wpt_license_valid' ) == 'true' ) || ( get_option( 'wpt_license_valid' ) == 'active' ) || ( get_option( 'wpt_license_valid' ) == 'valid' ) ) ? ' (active)' : ' (inactive)';
536
  } else {
537
  $valid = '';
538
  }
539
- $license = "License Key: " . $license . $valid;
540
 
541
  $version = $wpt_version;
542
  $wtt_twitter_username = get_option( 'wtt_twitter_username' );
543
- // send fields for all plugins
544
  $wp_version = get_bloginfo( 'version' );
545
  $home_url = home_url();
546
  $wp_url = site_url();
547
  $language = get_bloginfo( 'language' );
548
  $charset = get_bloginfo( 'charset' );
549
- // server
550
  $php_version = phpversion();
551
 
552
- // theme data
553
  $theme = wp_get_theme();
554
- $theme_name = $theme->Name;
555
- $theme_uri = $theme->ThemeURI;
556
- $theme_parent = $theme->Template;
557
- $theme_version = $theme->Version;
558
 
559
  $admin_email = get_option( 'admin_email' );
560
- // plugin data
561
  $plugins = get_plugins();
562
  $plugins_string = '';
563
  foreach ( array_keys( $plugins ) as $key ) {
564
  if ( is_plugin_active( $key ) ) {
565
- $plugin =& $plugins[ $key ];
566
- $plugin_name = $plugin['Name'];
567
- $plugin_uri = $plugin['PluginURI'];
568
- $plugin_version = $plugin['Version'];
569
  $plugins_string .= "$plugin_name: $plugin_version; $plugin_uri\n";
570
  }
571
  }
572
 
573
- $data = "
574
  ================ Installation Data ====================
575
  ==WP to Twitter==
576
  Version: $version
@@ -603,92 +699,102 @@ $plugins_string
603
  if ( isset( $_POST['wpt_support'] ) ) {
604
  $nonce = $_REQUEST['_wpnonce'];
605
  if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
606
- die( "Security check failed" );
607
  }
608
  $request = ( ! empty( $_POST['support_request'] ) ) ? stripslashes( $_POST['support_request'] ) : false;
609
- $has_donated = ( isset( $_POST['has_donated'] ) ) ? "Donor" : "No donation";
610
- $has_read_faq = ( isset( $_POST['has_read_faq'] ) ) ? "Read FAQ" : false;
611
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
612
- $pro = " PRO";
613
  } else {
614
  $pro = '';
615
  }
616
  $subject = "WP to Twitter$pro support request. $has_donated";
617
  $message = $request . "\n\n" . $data;
618
- // Get the site domain and get rid of www. from pluggable.php
619
  $sitename = strtolower( $_SERVER['SERVER_NAME'] );
620
- if ( substr( $sitename, 0, 4 ) == 'www.' ) {
621
  $sitename = substr( $sitename, 4 );
622
  }
623
  $response_email = ( isset( $_POST['response_email'] ) ) ? $_POST['response_email'] : false;
624
- $from_email = 'wordpress@' . $sitename;
625
- $from = "From: \"$current_user->display_name\" <$response_email>\r\nReply-to: \"$current_user->display_name\" <$response_email>\r\n";
626
 
627
  if ( ! $has_read_faq ) {
628
- echo "<div class='notice error'><p>" . __( 'Please read the FAQ and other Help documents before making a support request.', 'wp-to-twitter' ) . "</p></div>";
629
- } else if ( ! $response_email ) {
630
- echo "<div class='notice error'><p>" . __( 'Please supply a valid email where you can receive support responses.', 'wp-to-twitter' ) . "</p></div>";
631
- } else if ( ! $request ) {
632
- echo "<div class='notice error'><p>" . __( 'Please describe your problem. I\'m not psychic.', 'wp-to-twitter' ) . "</p></div>";
633
  } else {
634
- $sent = wp_mail( "plugins@joedolson.com", $subject, $message, $from );
635
  if ( $sent ) {
636
- if ( $has_donated == 'Donor' ) {
637
- echo "<div class='notice updated'><p>" . sprintf( __( 'Thank you for supporting WP to Twitter! I\'ll get back to you as soon as I can. Please make sure you can receive email at <code>%s</code>.', 'wp-to-twitter' ), $response_email ) . "</p></div>";
 
638
  } else {
639
- echo "<div class='notice updated'><p>" . sprintf( __( "Thanks for using WP to Twitter. Please ensure that you can receive email at <code>%s</code>.", 'wp-to-twitter' ), $response_email ) . "</p></div>";
 
640
  }
641
  } else {
642
- echo "<div class='notice error'><p>" . __( "Sorry! I couldn't send that message. Here's the text of your request:", 'my-calendar' ) . "</p><p>" . sprintf( __( '<a href="%s">Contact me here</a>, instead.', 'wp-to-twitter' ), 'https://www.joedolson.com/contact/' ) . "</p><pre>$request</pre></div>";
 
643
  }
644
  }
645
  }
646
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
647
- $checked = "checked='checked'";
648
  } else {
649
  $checked = '';
650
  }
651
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
652
  $admin_url = add_query_arg( 'tab', 'support', $admin_url );
653
-
654
  echo "
655
  <form method='post' action='$admin_url'>
656
  <div><input type='hidden' name='_wpnonce' value='" . wp_create_nonce( 'wp-to-twitter-nonce' ) . "' /></div>
657
  <div>
658
- <p>" .
659
- __( "If you're having trouble with WP to Twitter, please try to answer these questions in your message:", 'wp-to-twitter' )
660
- . "</p>
661
  <ul>
662
- <li>" . __( 'What were you doing when the problem occurred?', 'wp-to-twitter' ) . "</li>
663
- <li>" . __( 'What did you expect to happen?', 'wp-to-twitter' ) . "</li>
664
- <li>" . __( 'What happened instead?', 'wp-to-twitter' ) . "</li>
665
  </ul>
666
  <p>
667
  <label for='response_email'>" . __( 'Your Email', 'wp-to-twitter' ) . "</label><br />
668
  <input type='email' name='response_email' id='response_email' value='$response_email' class='widefat' required='required' aria-required='true' />
669
  </p>
670
  <p>
671
- <input type='checkbox' name='has_read_faq' id='has_read_faq' value='on' required='required' aria-required='true' /> <label for='has_read_faq'>" . sprintf( __( 'I have read <a href="%1$s">the FAQ for this plug-in</a> <span>(required)</span>', 'wp-to-twitter' ), 'http://www.joedolson.com/wp-to-twitter/support-2/' ) . "
672
- </p>
673
- <p>
674
- <input type='checkbox' name='has_donated' id='has_donated' value='on' $checked /> <label for='has_donated'>" . __( 'I made a donation or purchase to help support this plug-in', 'wp-to-twitter' ) . "</label>
675
- </p>
676
- <p>
677
- <label for='support_request'>" . __( 'Support Request:', 'wp-to-twitter' ) . "</label><br /><textarea class='support-request' name='support_request' id='support_request' cols='80' rows='10' class='widefat'>" . stripslashes( esc_attr( $request ) ) . "</textarea>
 
 
678
  </p>
679
  <p>
680
  <input type='submit' value='" . __( 'Send Support Request', 'wp-to-twitter' ) . "' name='wpt_support' class='button-primary' />
681
  </p>
682
  <p>" .
683
- __( 'The following additional information will be sent with your support request:', 'wp-to-twitter' )
684
- . "</p>
685
  <div class='mc_support'>
686
- " . wpautop( $data ) . "
687
  </div>
688
  </div>
689
- </form>";
690
  }
691
 
 
 
 
 
 
 
 
692
  function wpt_is_writable( $file ) {
693
  if ( function_exists( 'wp_is_writable' ) ) {
694
  $is_writable = wp_is_writable( $file );
@@ -699,346 +805,78 @@ function wpt_is_writable( $file ) {
699
  return $is_writable;
700
  }
701
 
702
- /**
703
- * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.
704
- *
705
- * It has been validated with Unicode 6.1 Normalization Conformance Test.
706
- * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.
707
- */
708
- class WPT_Normalizer
709
- {
710
- const
711
-
712
- NONE = 1,
713
- FORM_D = 2, NFD = 2,
714
- FORM_KD = 3, NFKD = 3,
715
- FORM_C = 4, NFC = 4,
716
- FORM_KC = 5, NFKC = 5;
717
-
718
-
719
- protected static
720
-
721
- $C, $D, $KD, $cC,
722
- $ulen_mask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4),
723
- $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
724
-
725
-
726
- static function isNormalized($s, $form = self::NFC)
727
- {
728
- if (strspn($s, self::$ASCII) === strlen($s)) return true;
729
- if (self::NFC === $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) return true;
730
- return false; // Pretend false as quick checks implementented in PHP won't be so quick
731
- }
732
-
733
- static function normalize($s, $form = self::NFC)
734
- {
735
- if (!preg_match('//u', $s)) return false;
736
-
737
- switch ($form)
738
- {
739
- case self::NONE: return $s;
740
- case self::NFC: $C = true; $K = false; break;
741
- case self::NFD: $C = false; $K = false; break;
742
- case self::NFKC: $C = true; $K = true; break;
743
- case self::NFKD: $C = false; $K = true; break;
744
- default: return false;
745
- }
746
-
747
- if (!strlen($s)) return '';
748
-
749
- if ($K && empty(self::$KD)) self::$KD = self::getData('compatibilityDecomposition');
750
-
751
- if (empty(self::$D))
752
- {
753
- self::$D = self::getData('canonicalDecomposition');
754
- self::$cC = self::getData('combiningClass');
755
- }
756
-
757
- if ($C)
758
- {
759
- if (empty(self::$C)) self::$C = self::getData('canonicalComposition');
760
- return self::recompose(self::decompose($s, $K));
761
- }
762
- else return self::decompose($s, $K);
763
- }
764
-
765
- protected static function recompose($s)
766
- {
767
- $ASCII = self::$ASCII;
768
- $compMap = self::$C;
769
- $combClass = self::$cC;
770
- $ulen_mask = self::$ulen_mask;
771
-
772
- $result = $tail = '';
773
-
774
- $i = $s[0] < "\x80" ? 1 : $ulen_mask[$s[0] & "\xF0"];
775
- $len = strlen($s);
776
-
777
- $last_uchr = substr($s, 0, $i);
778
- $last_ucls = isset($combClass[$last_uchr]) ? 256 : 0;
779
-
780
- while ($i < $len)
781
- {
782
- if ($s[$i] < "\x80")
783
- {
784
- // ASCII chars
785
-
786
- if ($tail)
787
- {
788
- $last_uchr .= $tail;
789
- $tail = '';
790
- }
791
-
792
- if ($j = strspn($s, $ASCII, $i+1))
793
- {
794
- $last_uchr .= substr($s, $i, $j);
795
- $i += $j;
796
- }
797
-
798
- $result .= $last_uchr;
799
- $last_uchr = $s[$i];
800
- ++$i;
801
- }
802
- else
803
- {
804
- $ulen = $ulen_mask[$s[$i] & "\xF0"];
805
- $uchr = substr($s, $i, $ulen);
806
-
807
- if ($last_uchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $last_uchr
808
- || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
809
- || $last_ucls)
810
- {
811
- // Table lookup and combining chars composition
812
-
813
- $ucls = isset($combClass[$uchr]) ? $combClass[$uchr] : 0;
814
-
815
- if (isset($compMap[$last_uchr . $uchr]) && (!$last_ucls || $last_ucls < $ucls))
816
- {
817
- $last_uchr = $compMap[$last_uchr . $uchr];
818
- }
819
- else if ($last_ucls = $ucls) $tail .= $uchr;
820
- else
821
- {
822
- if ($tail)
823
- {
824
- $last_uchr .= $tail;
825
- $tail = '';
826
- }
827
-
828
- $result .= $last_uchr;
829
- $last_uchr = $uchr;
830
- }
831
- }
832
- else
833
- {
834
- // Hangul chars
835
-
836
- $L = ord($last_uchr[2]) - 0x80;
837
- $V = ord($uchr[2]) - 0xA1;
838
- $T = 0;
839
-
840
- $uchr = substr($s, $i + $ulen, 3);
841
-
842
- if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82")
843
- {
844
- $T = ord($uchr[2]) - 0xA7;
845
- 0 > $T && $T += 0x40;
846
- $ulen += 3;
847
- }
848
-
849
- $L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
850
- $last_uchr = chr(0xE0 | $L>>12) . chr(0x80 | $L>>6 & 0x3F) . chr(0x80 | $L & 0x3F);
851
- }
852
-
853
- $i += $ulen;
854
- }
855
- }
856
-
857
- return $result . $last_uchr . $tail;
858
- }
859
-
860
- protected static function decompose($s, $c)
861
- {
862
- $result = '';
863
-
864
- $ASCII = self::$ASCII;
865
- $decompMap = self::$D;
866
- $combClass = self::$cC;
867
- $ulen_mask = self::$ulen_mask;
868
- if ($c) $compatMap = self::$KD;
869
-
870
- $c = array();
871
- $i = 0;
872
- $len = strlen($s);
873
-
874
- while ($i < $len) {
875
- if ($s[$i] < "\x80") {
876
- // ASCII chars
877
-
878
- if ($c) {
879
- ksort($c);
880
- $result .= implode('', $c);
881
- $c = array();
882
- }
883
-
884
- $j = 1 + strspn($s, $ASCII, $i+1);
885
- $result .= substr($s, $i, $j);
886
- $i += $j;
887
- } else {
888
- $ulen = $ulen_mask[$s[$i] & "\xF0"];
889
- $uchr = substr($s, $i, $ulen);
890
- $i += $ulen;
891
-
892
- if (isset($combClass[$uchr])) {
893
- // Combining chars, for sorting
894
-
895
- isset($c[$combClass[$uchr]]) || $c[$combClass[$uchr]] = '';
896
- $c[$combClass[$uchr]] .= isset($compatMap[$uchr]) ? $compatMap[$uchr] : (isset($decompMap[$uchr]) ? $decompMap[$uchr] : $uchr);
897
- } else {
898
- if ($c) {
899
- ksort($c);
900
- $result .= implode('', $c);
901
- $c = array();
902
- }
903
-
904
- if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {
905
- // Table lookup
906
-
907
- $j = isset($compatMap[$uchr]) ? $compatMap[$uchr] : (isset($decompMap[$uchr]) ? $decompMap[$uchr] : $uchr);
908
-
909
- if ($uchr != $j) {
910
- $uchr = $j;
911
-
912
- $j = strlen($uchr);
913
- $ulen = $uchr[0] < "\x80" ? 1 : $ulen_mask[$uchr[0] & "\xF0"];
914
-
915
- if ($ulen != $j)
916
- {
917
- // Put trailing chars in $s
918
-
919
- $j -= $ulen;
920
- $i -= $j;
921
-
922
- if (0 > $i)
923
- {
924
- $s = str_repeat(' ', -$i) . $s;
925
- $len -= $i;
926
- $i = 0;
927
- }
928
-
929
- while ($j--) $s[$i+$j] = $uchr[$ulen+$j];
930
-
931
- $uchr = substr($uchr, 0, $ulen);
932
- }
933
- }
934
- } else {
935
- // Hangul chars
936
-
937
- $uchr = unpack('C*', $uchr);
938
- $j = (($uchr[1]-224) << 12) + (($uchr[2]-128) << 6) + $uchr[3] - 0xAC80;
939
-
940
- $uchr = "\xE1\x84" . chr(0x80 + (int) ($j / 588))
941
- . "\xE1\x85" . chr(0xA1 + (int) (($j % 588) / 28));
942
-
943
- if ($j %= 28)
944
- {
945
- $uchr .= $j < 25
946
- ? ("\xE1\x86" . chr(0xA7 + $j))
947
- : ("\xE1\x87" . chr(0x67 + $j));
948
- }
949
- }
950
-
951
- $result .= $uchr;
952
- }
953
- }
954
- }
955
-
956
- if ( $c ) {
957
- ksort($c);
958
- $result .= implode('', $c);
959
- }
960
-
961
- return $result;
962
- }
963
-
964
- protected static function getData($file) {
965
- $file = __DIR__ . '/unidata/' . $file . '.ser';
966
- if ( file_exists( $file ) ) {
967
- return unserialize( file_get_contents( $file ) );
968
- } else {
969
- return false;
970
- }
971
- }
972
- }
973
-
974
-
975
  /**
976
  * Migrates post meta to new format when post is called in editor.
977
  */
978
- add_action( 'load-post.php', 'wpt_migrate_url_meta' );
979
  function wpt_migrate_url_meta() {
980
  $post_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : false;
981
- if ( !$post_id ) {
982
- // if this is a new post screen, no migration
983
  return;
984
  }
985
-
986
  $post = get_post( $post_id );
987
  if ( strtotime( $post->post_date ) > 1449764285 ) {
988
  // if this post was added after the migration function was added, it will not need to be migrated. Guaranteed.
989
  return;
990
  }
991
-
992
- $short = get_post_meta( $post_id, '_wpt_short_url', true );
993
- if ( $short != '' ) {
994
- return;
995
  }
996
- if ( $short == "" ) {
997
  $short = get_post_meta( $post_id, '_wp_jd_goo', true );
998
  delete_post_meta( $post_id, '_wp_jd_goo' );
999
  }
1000
- if ( $short == "" ) {
1001
  $short = get_post_meta( $post_id, '_wp_jd_supr', true );
1002
  delete_post_meta( $post_id, '_wp_jd_supr' );
1003
  }
1004
- if ( $short == "" ) {
1005
  $short = get_post_meta( $post_id, '_wp_jd_wp', true );
1006
  delete_post_meta( $post_id, '_wp_jd_wp' );
1007
  }
1008
- if ( $short == "" ) {
1009
  $short = get_post_meta( $post_id, '_wp_jd_ind', true );
1010
  delete_post_meta( $post_id, '_wp_jd_ind' );
1011
  }
1012
- if ( $short == "" ) {
1013
  $short = get_post_meta( $post_id, '_wp_jd_yourls', true );
1014
  delete_post_meta( $post_id, '_wp_jd_yourls' );
1015
  }
1016
- if ( $short == "" ) {
1017
  $short = get_post_meta( $post_id, '_wp_jd_url', true );
1018
  delete_post_meta( $post_id, '_wp_jd_url' );
1019
  }
1020
- if ( $short == "" ) {
1021
  $short = get_post_meta( $post_id, '_wp_jd_joturl', true );
1022
  delete_post_meta( $post_id, '_wp_jd_joturl' );
1023
  }
1024
- if ( $short == "" ) {
1025
- // don't delete target link
1026
  $short = get_post_meta( $post_id, '_wp_jd_target', true );
1027
  }
1028
- if ( $short == "" ) {
1029
  $short = get_post_meta( $post_id, '_wp_jd_clig', true );
1030
  delete_post_meta( $post_id, '_wp_jd_clig' );
1031
  }
1032
-
1033
- if ( $short == '' ) {
1034
- $short = get_permalink( $post_id );
1035
  }
1036
-
1037
- update_post_meta( $post_id, '_wpt_short_url', $short );
1038
  }
1039
 
 
 
 
 
 
 
 
1040
  function wp_get_curl( $url ) {
1041
-
1042
  $curl = curl_init( $url );
1043
 
1044
  curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
@@ -1049,9 +887,9 @@ function wp_get_curl( $url ) {
1049
  curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
1050
 
1051
  $response = curl_exec( $curl );
1052
- if( 0 !== curl_errno( $curl ) || 200 !== curl_getinfo( $curl, CURLINFO_HTTP_CODE ) ) {
1053
  $response = false;
1054
- } // end if
1055
  curl_close( $curl );
1056
 
1057
  return $response;
@@ -1061,6 +899,9 @@ add_action( 'dp_duplicate_post', 'wpt_delete_copied_meta', 10, 2 );
1061
  add_action( 'dp_duplicate_page', 'wpt_delete_copied_meta', 10, 2 );
1062
  /**
1063
  * Prevent 'Duplicate Posts' plug-in from copying WP to Twitter meta data
 
 
 
1064
  */
1065
  function wpt_delete_copied_meta( $new_id, $post ) {
1066
  $disable = apply_filters( 'wpt_allow_copy_meta', false );
@@ -1077,32 +918,97 @@ function wpt_delete_copied_meta( $new_id, $post ) {
1077
  }
1078
 
1079
  /**
1080
- * Functions to provide fallbacks for changed function names in case any plug-ins or themes are calling WP to Twitter functions in custom code.
 
 
 
 
 
 
 
 
1081
  */
1082
  function jd_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $return = 'body' ) {
1083
  return wpt_fetch_url( $url, $method, $body, $headers, $return );
1084
  }
1085
 
 
 
 
 
 
 
 
 
1086
  function jd_remote_json( $url, $array = true ) {
1087
  return wpt_remote_json( $url, $array );
1088
  }
1089
 
1090
- function jd_twit_link( $link_ID ) {
1091
- return wpt_twit_link( $link_ID );
 
 
 
 
 
 
 
1092
  }
1093
 
 
 
 
 
 
 
 
1094
  function jd_post_info( $post_ID ) {
1095
  return wpt_post_info( $post_ID );
1096
  }
1097
 
 
 
 
 
 
 
 
 
1098
  function jd_twit( $post_ID, $type = 'instant' ) {
1099
  return wpt_tweet( $post_ID, $type );
1100
  }
1101
 
 
 
 
1102
  function jd_addTwitterAdminStyles() {
1103
  return wpt_admin_style();
1104
  }
1105
 
 
 
 
 
 
 
 
 
 
 
 
 
1106
  function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false ) {
1107
  return wpt_post_to_twitter( $twit, $auth, $id, $media );
1108
- }
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+ /**
3
+ * Core support functions WP to Twitter
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
 
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
+ include( dirname( __FILE__ ) . '/classes/class-wpt-normalizer.php' );
17
+
18
+ /**
19
+ * See if checkboxes should be checked
20
+ *
21
+ * @param string $field Option name to check.
22
+ * @param string $sub1 Array key if applicable.
23
+ * @param string $sub2 Array key if applicable.
24
+ *
25
+ * @return Checked or unchecked.
26
+ */
27
+ function wpt_checkbox( $field, $sub1 = false, $sub2 = '' ) {
28
  if ( $sub1 ) {
29
  $setting = get_option( $field );
30
  if ( isset( $setting[ $sub1 ] ) ) {
31
+ $value = ( '' != $sub2 ) ? $setting[ $sub1 ][ $sub2 ] : $setting[ $sub1 ];
32
  } else {
33
  $value = 0;
34
  }
35
+ if ( 1 == $value ) {
36
  return 'checked="checked"';
37
  }
38
  }
39
+ if ( '1' == get_option( $field ) ) {
40
  return 'checked="checked"';
41
  }
42
  return '';
43
  }
44
 
45
+ /**
46
+ * See if checkboxes should be checked - fallback to old function.
47
+ *
48
+ * @param string $field Option name to check.
49
+ * @param string $sub1 Array key if applicable.
50
+ * @param string $sub2 Array key if applicable.
51
+ *
52
+ * @deprecated 3/26/2018
53
+ *
54
+ * @return Checked or unchecked.
55
+ */
56
+ function jd_checkCheckbox( $field, $sub1 = false, $sub2 = '' ) {
57
+ return wpt_checkbox( $field, $sub1, $sub2 );
58
+ }
59
+
60
+ /**
61
+ * See if options should be selected
62
+ *
63
+ * @param string $field Option name to check.
64
+ * @param string $value Value to verify against.
65
+ * @param string $type Select or checkbox.
66
+ *
67
+ * @return Selected or unselected/ checked or unchecked..
68
+ */
69
+ function wpt_selected( $field, $value, $type = 'select' ) {
70
  if ( get_option( $field ) == $value ) {
71
+ return ( 'select' == $type ) ? 'selected="selected"' : 'checked="checked"';
72
  }
73
  return '';
74
  }
75
 
76
+ /**
77
+ * See if options should be selected - fallback function
78
+ *
79
+ * @param string $field Option name to check.
80
+ * @param string $value Value to verify against.
81
+ * @param string $type Select or checkbox.
82
+ *
83
+ * @deprecated 3/26/2018
84
+ *
85
+ * @return Selected or unselected/ checked or unchecked..
86
+ */
87
+ function jd_checkSelect( $field, $value, $type = 'select' ) {
88
+ return wpt_selected( $field, $value, $type );
89
+ }
90
+
91
+ /**
92
+ * Insert a Tweet record into logs.
93
+ *
94
+ * @param string $data Option key.
95
+ * @param int $id Post ID.
96
+ * @param string $message Log message.
97
+ */
98
  function wpt_set_log( $data, $id, $message ) {
99
+ if ( 'test' == $id ) {
100
  update_option( $data, $message );
101
  } else {
102
  update_post_meta( $id, '_' . $data, $message );
104
  update_option( $data . '_last', array( $id, $message ) );
105
  }
106
 
107
+ /**
108
+ * Get information from Tweet logs.
109
+ *
110
+ * @param string $data Option key.
111
+ * @param int $id Post ID.
112
+ *
113
+ * @return stored message.
114
+ */
115
  function wpt_log( $data, $id ) {
116
+ if ( 'test' == $id ) {
117
  $log = get_option( $data );
118
+ } elseif ( 'last' == $id ) {
119
  $log = get_option( $data . '_last' );
120
  } else {
121
  $log = get_post_meta( $id, '_' . $data, true );
124
  return $log;
125
  }
126
 
127
+ /**
128
+ * Test function to see whether options are functioning.
129
+ */
130
  function wpt_check_functions() {
131
  $message = "<div class='update'><ul>";
132
+ // grab or set necessary variables.
133
+ $testurl = get_bloginfo( 'url' );
134
+ $testpost = false;
135
+ $title = urlencode( 'Your blog home' );
136
+ $shrink = apply_filters( 'wptt_shorten_link', $testurl, $title, false, true );
137
+ if ( false == $shrink ) {
138
+ $error = htmlentities( get_option( 'wpt_shortener_status' ) );
139
+ $message .= __( '<li class="error"><strong>WP to Twitter was unable to contact your selected URL shortening service.</strong></li>', 'wp-to-twitter' );
140
+ if ( '' != $error ) {
141
  $message .= "<li><code>$error</code></li>";
142
  } else {
143
+ $message .= '<li><code>' . __( 'No error message was returned.', 'wp-to-twitter' ) . '</code></li>';
144
  }
145
  } else {
146
  $message .= __( "<li><strong>WP to Twitter successfully contacted your URL shortening service.</strong> This link should point to your site's homepage:", 'wp-to-twitter' );
147
  $message .= " <a href='$shrink'>$shrink</a></li>";
148
  }
149
+ // check twitter credentials.
150
  if ( wtt_oauth_test() ) {
151
  $rand = rand( 1000000, 9999999 );
152
  $testpost = wpt_post_to_twitter( "This is a test of WP to Twitter. $shrink ($rand)" );
153
  if ( $testpost ) {
154
+ $message .= __( '<li><strong>WP to Twitter successfully submitted a status update to Twitter.</strong></li>', 'wp-to-twitter' );
155
  } else {
156
+ $error = wpt_log( 'wpt_status_message', 'test' );
157
+ $message .= __( '<li class="error"><strong>WP to Twitter failed to submit an update to Twitter.</strong></li>', 'wp-to-twitter' );
158
+ $message .= "<li class='error'>$error</li>";
159
  }
160
  } else {
161
+ $message .= '<strong>' . __( 'You have not connected WordPress to Twitter.', 'wp-to-twitter' ) . '</strong> ';
162
  }
163
+ if ( false == $testpost && false == $shrink ) {
 
164
  $message .= __( "<li class=\"error\"><strong>Your server does not appear to support the required methods for WP to Twitter to function.</strong> You can try it anyway - these tests aren't perfect.</li>", 'wp-to-twitter' );
 
165
  }
166
  if ( $testpost && $shrink ) {
167
+ $message .= __( '<li><strong>Your server should run WP to Twitter successfully.</strong></li>', 'wp-to-twitter' );
168
  }
169
+ $message .= '</ul>
170
+ </div>';
171
 
172
  return $message;
173
  }
174
 
175
+ /**
176
+ * Generate Settings links.
177
+ */
178
  function wpt_settings_tabs() {
179
+ $output = '';
180
+ $default = ( '' == get_option( 'wtt_twitter_username' ) ) ? 'connection' : 'basic';
181
+ $current = ( isset( $_GET['tab'] ) ) ? $_GET['tab'] : $default;
182
  $pro_text = ( function_exists( 'wpt_pro_exists' ) ) ? __( 'Pro Settings', 'wp-to-twitter' ) : __( 'Get WP Tweets PRO', 'wp-to-twitter' );
183
+ $pages = array(
184
+ 'connection' => __( 'Twitter Connection', 'wp-to-twitter' ),
185
+ 'basic' => __( 'Basic Settings', 'wp-to-twitter' ),
186
+ 'shortener' => __( 'URL Shortener', 'wp-to-twitter' ),
187
+ 'advanced' => __( 'Advanced Settings', 'wp-to-twitter' ),
188
+ 'support' => __( 'Get Help', 'wp-to-twitter' ),
189
+ 'pro' => $pro_text,
190
  );
191
+ if ( '1' == get_option( 'jd_donations' ) && ! function_exists( 'wpt_pro_exists' ) ) {
192
  unset( $pages['pro'] );
193
  }
194
+
195
+ $pages = apply_filters( 'wpt_settings_tabs_pages', $pages, $current );
196
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
197
 
198
  foreach ( $pages as $key => $value ) {
199
+ $selected = ( $key == $current ) ? ' nav-tab-active' : '';
200
+ $url = esc_url( add_query_arg( 'tab', $key, $admin_url ) );
201
+ if ( 'pro' == $key ) {
202
  $output .= "<a class='wpt-pro-tab nav-tab$selected' href='$url'>$value</a>";
203
  } else {
204
  $output .= "<a class='nav-tab$selected' href='$url'>$value</a>";
207
  echo $output;
208
  }
209
 
210
+ /**
211
+ * Show the last Tweet attempt as admin notice.
212
+ */
213
  function wpt_show_last_tweet() {
214
  if ( apply_filters( 'wpt_show_last_tweet', true ) ) {
215
  $log = wpt_log( 'wpt_status_message', 'last' );
219
  if ( is_object( $post ) ) {
220
  $title = "<a href='" . get_edit_post_link( $post_ID ) . "'>$post->post_title</a>";
221
  } else {
222
+ $title = '(' . __( 'No post', 'wp-to-twitter' ) . ')';
223
  }
224
  $notice = $log[1];
225
  echo "<div class='updated'><p><strong>" . __( 'Last Tweet', 'wp-to-twitter' ) . "</strong>: $title &raquo; $notice</p></div>";
227
  }
228
  }
229
 
230
+ /**
231
+ * Handle Tweet & URL shortener errors.
232
+ */
233
  function wpt_handle_errors() {
234
+ if ( isset( $_POST['submit-type'] ) && 'clear-error' == $_POST['submit-type'] ) {
235
  delete_option( 'wp_url_failure' );
236
  }
237
+ if ( '1' == get_option( 'wp_url_failure' ) ) {
238
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
239
+ $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
240
+ $error = '<div class="error">' . __( '<p>The query to the URL shortener API failed, and your URL was not shrunk. The full post URL was attached to your Tweet. Check with your URL shortening provider to see if there are any known issues.</p>', 'wp-to-twitter' ) .
 
241
  '<form method="post" action="' . $admin_url . '">
242
  <div>
243
  <input type="hidden" name="submit-type" value="clear-error"/>
244
+ ' . $nonce . '
245
  </div>
246
  <p>
247
  <input type="submit" name="submit" value="' . __( "Clear 'WP to Twitter' Error Messages", 'wp-to-twitter' ) . '" class="button-primary" />
251
  echo $error;
252
  }
253
  }
254
+
255
+ /**
256
+ * Verify user capabilities
257
+ *
258
+ * @param string $role Role name.
259
+ * @param string $cap Capability name.
260
+ *
261
+ * @return Check if has capability.
262
+ */
263
  function wpt_check_caps( $role, $cap ) {
264
  $role = get_role( $role );
265
  if ( $role->has_cap( $cap ) ) {
268
  return '';
269
  }
270
 
271
+ /**
272
+ * Output checkbox for user capabilities
273
+ *
274
+ * @param string $role Role name.
275
+ * @param string $cap Capability name.
276
+ * @param string $name Display name for capability.
277
+ *
278
+ * @return Checkbox HTML.
279
+ */
280
  function wpt_cap_checkbox( $role, $cap, $name ) {
281
  return "<li><input type='checkbox' id='wpt_caps_{$role}_$cap' name='wpt_caps[$role][$cap]' value='on'" . wpt_check_caps( $role, $cap ) . " /> <label for='wpt_caps_{$role}_$cap'>$name</label></li>";
282
  }
283
 
284
+ /**
285
+ * Send a debug message. (Used email by default until 3.3.)
286
+ *
287
+ * @param string $subject Subject of error.
288
+ * @param string $body Body of error.
289
+ * @param boolean $override Send message if debug disabled.
290
+ */
291
+ function wpt_mail( $subject, $body, $override = false ) {
292
+ if ( ( WPT_DEBUG && function_exists( 'wpt_pro_exists' ) ) || true == $override ) {
293
  if ( WPT_DEBUG_BY_EMAIL ) {
294
  wp_mail( WPT_DEBUG_ADDRESS, $subject, $body, WPT_FROM );
295
  } else {
298
  }
299
  }
300
 
301
+ /**
302
+ * Insert record into debug log.
303
+ *
304
+ * @param string $subject Subject of error.
305
+ * @param string $body Body of error.
306
+ */
307
  function wpt_debug_log( $subject, $body ) {
308
  global $post_ID;
309
  if ( $post_ID ) {
312
  }
313
  }
314
 
315
+ /**
316
+ * Display debug log.
317
+ */
318
  function wpt_show_debug() {
319
  global $post_ID;
320
  if ( WPT_DEBUG ) {
321
+ $records = '';
322
  $debug_log = get_post_meta( $post_ID, '_wpt_debug_log' );
323
  if ( is_array( $debug_log ) ) {
324
+ foreach ( $debug_log as $entry ) {
325
+ $date = date_i18n( 'Y-m-d H:i', $entry[0] );
326
+ $subject = $entry[1];
327
+ $body = $entry[2];
328
+ $records .= "<li><button type='button' class='toggle-debug button-secondary' aria-expanded='false'><strong>$date</strong>:<br />$subject</button><pre class='wpt-debug-details'>" . esc_html( $body ) . '</pre></li>';
329
  }
330
  }
331
  $script = "
339
  $( this ).attr( 'aria-expanded', 'false' );
340
  } else {
341
  $( this ).next( 'pre' ).show();
342
+ $( this ).attr( 'aria-expanded', 'true' );
343
  }
344
  });
345
  })
347
  </script>";
348
  $delete = "<ul>
349
  <li><input type='checkbox' name='wpt-delete-debug' value='true' id='wpt-delete-debug'> <label for='wpt-delete-debug'>" . __( 'Delete debugging logs on this post', 'wp-to-twitter' ) . "</label></li>
350
+ <li><input type='checkbox' name='wpt-delete-all-debug' value='true' id='wpt-delete-all-debug'> <label for='wpt-delete-all-debug'>" . __( 'Delete debugging logs for all posts', 'wp-to-twitter' ) . '</label></li>
351
+ </ul>';
352
+
353
+ echo ( '' != $records ) ? "$script<div class='wpt-debug-log'><h3>Debugging Log:</h3><ul>$records</ul></div>$delete" : '';
354
  }
355
  }
356
 
357
+ /**
358
+ * Send a remote query expecting JSON.
359
+ *
360
+ * @param string $url Target URL.
361
+ * @param array $array Arguments if not default.
362
+ * @param string $method Query method.
363
+ * @throws Exception JSON error string.
364
+ *
365
+ * @return JSON object.
366
+ */
367
  function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
368
  $input = wpt_fetch_url( $url, $method );
369
  wpt_mail( 'Remote JSON input', print_r( $input, 1 ) . "\n\n" . $url );
370
+ $obj = json_decode( $input, $array );
371
  wpt_mail( 'Remote JSON return value', print_r( $obj, 1 ) . "\n\n" . "$url" );
372
+ if ( function_exists( 'json_last_error' ) ) { // > PHP 5.3.
373
  try {
374
  if ( is_null( $obj ) ) {
375
  switch ( json_last_error() ) {
376
+ case JSON_ERROR_DEPTH:
377
  $msg = ' - Maximum stack depth exceeded';
378
  break;
379
+ case JSON_ERROR_STATE_MISMATCH:
380
  $msg = ' - Underflow or the modes mismatch';
381
  break;
382
+ case JSON_ERROR_CTRL_CHAR:
383
  $msg = ' - Unexpected control character found';
384
  break;
385
+ case JSON_ERROR_SYNTAX:
386
  $msg = ' - Syntax error, malformed JSON';
387
  break;
388
+ case JSON_ERROR_UTF8:
389
  $msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded';
390
  break;
391
+ default:
392
  $msg = ' - Unknown error';
393
  break;
394
  }
402
  return $obj;
403
  }
404
 
405
+ /**
406
+ * Test whether a URL is valid.
407
+ *
408
+ * @param string $url URL.
409
+ *
410
+ * @return URL if passes, false otherwise.
411
+ */
412
  function wpt_is_valid_url( $url ) {
413
  if ( is_string( $url ) ) {
414
  $url = urldecode( $url );
419
  }
420
  }
421
 
422
+ /**
423
+ * Fetch a remote page. Input url, return content
424
+ *
425
+ * @param string $url URL.
426
+ * @param string $method Method.
427
+ * @param string $body Body of query.
428
+ * @param string $headers Headers to add.
429
+ * @param string $return Array key from fetched object to return.
430
+ *
431
+ * @return value from query.
432
+ */
433
  function wpt_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $return = 'body' ) {
434
  $request = new WP_Http;
435
+ $result = $request->request( $url, array(
436
+ 'method' => $method,
437
+ 'body' => $body,
438
+ 'headers' => $headers,
439
+ 'sslverify' => false,
440
+ 'user-agent' => 'WP to Twitter/http://www.joedolson.com/wp-to-twitter/',
441
+ ) );
442
+
443
  if ( ! is_wp_error( $result ) && isset( $result['body'] ) ) {
444
+ if ( 200 == $result['response']['code'] ) {
445
+ if ( 'body' == $return ) {
446
  return $result['body'];
447
  } else {
448
  return $result;
450
  } else {
451
  return $result['response']['code'];
452
  }
453
+ // Failure (server problem...).
454
  } else {
455
  return false;
456
  }
457
  }
458
 
459
  if ( ! function_exists( 'mb_substr_split_unicode' ) ) {
460
+ /**
461
+ * Fall back function for mb_substr_split_unicode if doesn't exist.
462
+ *
463
+ * @param string $str String.
464
+ * @param int $split_pos Position to split on.
465
+ *
466
+ * @return split output.
467
+ */
468
+ function mb_substr_split_unicode( $str, $split_pos ) {
469
+ if ( 0 == $split_pos ) {
470
  return 0;
471
+ }
472
+ $byte_len = strlen( $str );
473
+
474
+ if ( $split_pos > 0 ) {
475
+ if ( $split_pos > 256 ) {
476
+ // Optimize large string offsets by skipping ahead N bytes.
477
+ // This will cut out most of our slow time on Latin-based text,
478
+ // and 1/2 to 1/3 on East European and Asian scripts.
479
+ $byte_pos = $split_pos;
480
+ while ( $byte_pos < $byte_len && $str[ $byte_pos ] >= "\x80" && $str[ $byte_pos ] < "\xc0" ) {
481
+ ++$byte_pos;
482
+ }
483
+ $char_pos = mb_strlen( substr( $str, 0, $byte_pos ) );
484
+ } else {
485
+ $char_pos = 0;
486
+ $byte_pos = 0;
487
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
+ while ( $char_pos++ < $split_pos ) {
490
+ ++$byte_pos;
491
+ // Move past any tail bytes.
492
+ while ( $byte_pos < $byte_len && $str[ $byte_pos ] >= "\x80" && $str[ $byte_pos ] < "\xc0" ) {
493
+ ++$byte_pos;
494
+ }
495
+ }
496
+ } else {
497
+ $split_posx = $split_pos + 1;
498
+ $char_pos = 0; // relative to end of string; we don't care about the actual char position here.
499
+ $byte_pos = $byte_len;
500
+ while ( $byte_pos > 0 && $char_pos-- >= $split_posx ) {
501
+ --$byte_pos;
502
+ // Move past any tail bytes.
503
+ while ( $byte_pos > 0 && $str[ $byte_pos ] >= "\x80" && $str[ $byte_pos ] < "\xc0" ) {
504
+ --$byte_pos;
505
+ }
506
+ }
507
+ }
508
+
509
+ return $byte_pos;
510
  }
511
  }
512
 
514
  /**
515
  * Fallback implementation of mb_strrpos, hardcoded to UTF-8.
516
  *
517
+ * @param string $haystack String.
518
+ * @param string $needle String.
519
+ * @param int $offset integer: optional start position.
520
  *
521
  * @return int
522
  */
526
  $ar = array();
527
  preg_match_all( '/' . $needle . '/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
528
 
529
+ if ( isset( $ar[0] ) && count( $ar[0] ) > 0 && isset( $ar[0][ count( $ar[0] ) - 1 ][1] ) ) {
 
 
530
  return $ar[0][ count( $ar[0] ) - 1 ][1];
531
  } else {
532
  return false;
534
  }
535
  }
536
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  /**
538
  * This function is obsolete; only exists for people using out of date versions of WP Tweets PRO.
539
+ *
540
+ * @param string $field Field to check.
541
+ * @param string $value Value to check.
542
+ * @param string $type Type of field.
543
+ *
544
+ * @return checked string.
545
  */
546
  function wtt_option_selected( $field, $value, $type = 'checkbox' ) {
547
  switch ( $type ) {
552
  case 'option':
553
  $result = ' selected="selected"';
554
  break;
555
+ default:
556
+ $result = ' selected="selected"';
557
  }
558
  if ( $field == $value ) {
559
  $output = $result;
566
 
567
  /**
568
  * Compares two dates to identify which is earlier. Used to differentiate between post edits and original publication.
569
+ *
570
+ * @param string $modified Date this post was modified.
571
+ * @param string $postdate Date this post was published.
572
+ *
573
  * @return integer 1|0
574
+ */
575
  function wpt_date_compare( $modified, $postdate ) {
576
  $modifier = apply_filters( 'wpt_edit_sensitivity', 0 ); // alter time in seconds to modified date.
577
+ $mod_date = strtotime( $modified );
578
+ $post_date = strtotime( $postdate ) + $modifier;
579
+ if ( $mod_date <= $post_date ) { // if post_modified is before or equal to post_date.
580
  return 1;
581
  } else {
582
  return 0;
586
  /**
587
  * Gets the first attachment for the supplied post.
588
  *
589
+ * @param integer $post_ID The post ID.
590
  *
591
  * @return mixed boolean|integer Attachment ID.
592
  */
593
  function wpt_post_attachment( $post_ID ) {
594
+ $return = false;
595
  $use_featured_image = apply_filters( 'wpt_use_featured_image', true, $post_ID );
596
  if ( has_post_thumbnail( $post_ID ) && $use_featured_image ) {
597
  $attachment = get_post_thumbnail_id( $post_ID );
604
  'post_status' => 'published',
605
  'post_parent' => $post_ID,
606
  'post_mime_type' => 'image',
607
+ 'order' => 'ASC',
608
  );
609
  $attachments = get_posts( $args );
610
  if ( $attachments ) {
611
+ $return = $attachments[0]->ID; // Return the first attachment.
612
  } else {
613
  $return = false;
614
  }
615
  }
616
+
617
  return apply_filters( 'wpt_post_attachment', $return, $post_ID );
618
  }
619
 
620
+ /**
621
+ * Show support form. Note: text in the message body should not be translatable.
622
+ */
623
  function wpt_get_support_form() {
624
  global $current_user, $wpt_version;
625
+ $current_user = wp_get_current_user();
626
+ $request = '';
627
  $response_email = '';
628
+ // send fields for WP to Twitter.
629
+ $license = ( '' != get_option( 'wpt_license_key' ) ) ? get_option( 'wpt_license_key' ) : 'none';
630
+ if ( 'none' != $license ) {
631
+ $valid = ( ( 'true' == get_option( 'wpt_license_valid' ) ) || ( 'active' == get_option( 'wpt_license_valid' ) ) || ( 'valid' == get_option( 'wpt_license_valid' ) ) ) ? ' (active)' : ' (inactive)';
632
  } else {
633
  $valid = '';
634
  }
635
+ $license = 'License Key: ' . $license . $valid;
636
 
637
  $version = $wpt_version;
638
  $wtt_twitter_username = get_option( 'wtt_twitter_username' );
639
+ // send fields for all plugins.
640
  $wp_version = get_bloginfo( 'version' );
641
  $home_url = home_url();
642
  $wp_url = site_url();
643
  $language = get_bloginfo( 'language' );
644
  $charset = get_bloginfo( 'charset' );
645
+ // server.
646
  $php_version = phpversion();
647
 
648
+ // theme data.
649
  $theme = wp_get_theme();
650
+ $theme_name = $theme->get( 'Name' );
651
+ $theme_uri = $theme->get( 'ThemeURI' );
652
+ $theme_parent = $theme->get( 'Template' );
653
+ $theme_version = $theme->get( 'Version' );
654
 
655
  $admin_email = get_option( 'admin_email' );
656
+ // plugin data.
657
  $plugins = get_plugins();
658
  $plugins_string = '';
659
  foreach ( array_keys( $plugins ) as $key ) {
660
  if ( is_plugin_active( $key ) ) {
661
+ $plugin =& $plugins[ $key ];
662
+ $plugin_name = $plugin['Name'];
663
+ $plugin_uri = $plugin['PluginURI'];
664
+ $plugin_version = $plugin['Version'];
665
  $plugins_string .= "$plugin_name: $plugin_version; $plugin_uri\n";
666
  }
667
  }
668
 
669
+ $data = "
670
  ================ Installation Data ====================
671
  ==WP to Twitter==
672
  Version: $version
699
  if ( isset( $_POST['wpt_support'] ) ) {
700
  $nonce = $_REQUEST['_wpnonce'];
701
  if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
702
+ die( 'Security check failed' );
703
  }
704
  $request = ( ! empty( $_POST['support_request'] ) ) ? stripslashes( $_POST['support_request'] ) : false;
705
+ $has_donated = ( isset( $_POST['has_donated'] ) ) ? 'Donor' : 'No donation';
706
+ $has_read_faq = ( isset( $_POST['has_read_faq'] ) ) ? 'Read FAQ' : false;
707
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
708
+ $pro = ' PRO';
709
  } else {
710
  $pro = '';
711
  }
712
  $subject = "WP to Twitter$pro support request. $has_donated";
713
  $message = $request . "\n\n" . $data;
714
+ // Get the site domain and get rid of www. from pluggable.php.
715
  $sitename = strtolower( $_SERVER['SERVER_NAME'] );
716
+ if ( 'www.' == substr( $sitename, 0, 4 ) ) {
717
  $sitename = substr( $sitename, 4 );
718
  }
719
  $response_email = ( isset( $_POST['response_email'] ) ) ? $_POST['response_email'] : false;
720
+ $from_email = 'wordpress@' . $sitename;
721
+ $from = "From: \"$current_user->display_name\" <$response_email>\r\nReply-to: \"$current_user->display_name\" <$response_email>\r\n";
722
 
723
  if ( ! $has_read_faq ) {
724
+ echo "<div class='notice error'><p>" . __( 'Please read the FAQ and other Help documents before making a support request.', 'wp-to-twitter' ) . '</p></div>';
725
+ } elseif ( ! $response_email ) {
726
+ echo "<div class='notice error'><p>" . __( 'Please supply a valid email where you can receive support responses.', 'wp-to-twitter' ) . '</p></div>';
727
+ } elseif ( ! $request ) {
728
+ echo "<div class='notice error'><p>" . __( 'Please describe your problem. I\'m not psychic.', 'wp-to-twitter' ) . '</p></div>';
729
  } else {
730
+ $sent = wp_mail( 'plugins@joedolson.com', $subject, $message, $from );
731
  if ( $sent ) {
732
+ if ( 'Donor' == $has_donated ) {
733
+ // Translators: Email address.
734
+ echo "<div class='notice updated'><p>" . sprintf( __( 'Thank you for supporting WP to Twitter! I\'ll get back to you as soon as I can. Please make sure you can receive email at <code>%s</code>.', 'wp-to-twitter' ), $response_email ) . '</p></div>';
735
  } else {
736
+ // Translators: Email address.
737
+ echo "<div class='notice updated'><p>" . sprintf( __( 'Thanks for using WP to Twitter. Please ensure that you can receive email at <code>%s</code>.', 'wp-to-twitter' ), $response_email ) . '</p></div>';
738
  }
739
  } else {
740
+ // Translators: URL to plugin support form.
741
+ echo "<div class='notice error'><p>" . __( "Sorry! I couldn't send that message. Here's the text of your request:", 'wp-to-twitter' ) . '</p><p>' . sprintf( __( '<a href="%s">Contact me here</a>, instead.', 'wp-to-twitter' ), 'https://www.joedolson.com/contact/get-support/' ) . "</p><pre>$request</pre></div>";
742
  }
743
  }
744
  }
745
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
746
+ $checked = 'checked="checked"';
747
  } else {
748
  $checked = '';
749
  }
750
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
751
  $admin_url = add_query_arg( 'tab', 'support', $admin_url );
752
+
753
  echo "
754
  <form method='post' action='$admin_url'>
755
  <div><input type='hidden' name='_wpnonce' value='" . wp_create_nonce( 'wp-to-twitter-nonce' ) . "' /></div>
756
  <div>
757
+ <p>" . __( "If you're having trouble with WP to Twitter, please try to answer these questions in your message:", 'wp-to-twitter' ) . '</p>
 
 
758
  <ul>
759
+ <li>' . __( 'What were you doing when the problem occurred?', 'wp-to-twitter' ) . '</li>
760
+ <li>' . __( 'What did you expect to happen?', 'wp-to-twitter' ) . '</li>
761
+ <li>' . __( 'What happened instead?', 'wp-to-twitter' ) . "</li>
762
  </ul>
763
  <p>
764
  <label for='response_email'>" . __( 'Your Email', 'wp-to-twitter' ) . "</label><br />
765
  <input type='email' name='response_email' id='response_email' value='$response_email' class='widefat' required='required' aria-required='true' />
766
  </p>
767
  <p>
768
+ <input type='checkbox' name='has_read_faq' id='has_read_faq' value='on' required='required' aria-required='true' /> <label for='has_read_faq'>";
769
+ // Translators: Link to plugin FAQ.
770
+ echo sprintf( __( 'I have read <a href="%1$s">the FAQ for this plug-in</a> <span>(required)</span>', 'wp-to-twitter' ), 'http://www.joedolson.com/wp-to-twitter/support-2/' );
771
+ echo "</p>
772
+ <p>
773
+ <input type='checkbox' name='has_donated' id='has_donated' value='on' $checked /> <label for='has_donated'>" . __( 'I made a donation or purchase to help support this plug-in', 'wp-to-twitter' ) . "</label>
774
+ </p>
775
+ <p>
776
+ <label for='support_request'>" . __( 'Support Request:', 'wp-to-twitter' ) . "</label><br /><textarea class='support-request' name='support_request' id='support_request' cols='80' rows='10' class='widefat'>" . stripslashes( esc_attr( $request ) ) . "</textarea>
777
  </p>
778
  <p>
779
  <input type='submit' value='" . __( 'Send Support Request', 'wp-to-twitter' ) . "' name='wpt_support' class='button-primary' />
780
  </p>
781
  <p>" .
782
+ __( 'The following additional information will be sent with your support request:', 'wp-to-twitter' )
783
+ . "</p>
784
  <div class='mc_support'>
785
+ " . wpautop( $data ) . '
786
  </div>
787
  </div>
788
+ </form>';
789
  }
790
 
791
+ /**
792
+ * Check whether a file is writable.
793
+ *
794
+ * @param string $file Filename/path.
795
+ *
796
+ * @return boolean.
797
+ */
798
  function wpt_is_writable( $file ) {
799
  if ( function_exists( 'wp_is_writable' ) ) {
800
  $is_writable = wp_is_writable( $file );
805
  return $is_writable;
806
  }
807
 
808
+ add_action( 'load-post.php', 'wpt_migrate_url_meta' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809
  /**
810
  * Migrates post meta to new format when post is called in editor.
811
  */
 
812
  function wpt_migrate_url_meta() {
813
  $post_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : false;
814
+ if ( ! $post_id ) {
815
+ // if this is a new post screen, no migration.
816
  return;
817
  }
818
+
819
  $post = get_post( $post_id );
820
  if ( strtotime( $post->post_date ) > 1449764285 ) {
821
  // if this post was added after the migration function was added, it will not need to be migrated. Guaranteed.
822
  return;
823
  }
824
+
825
+ $short = wpt_short_url( $post_id );
826
+ if ( '' != $short ) {
827
+ return;
828
  }
829
+ if ( '' == $short ) {
830
  $short = get_post_meta( $post_id, '_wp_jd_goo', true );
831
  delete_post_meta( $post_id, '_wp_jd_goo' );
832
  }
833
+ if ( '' == $short ) {
834
  $short = get_post_meta( $post_id, '_wp_jd_supr', true );
835
  delete_post_meta( $post_id, '_wp_jd_supr' );
836
  }
837
+ if ( '' == $short ) {
838
  $short = get_post_meta( $post_id, '_wp_jd_wp', true );
839
  delete_post_meta( $post_id, '_wp_jd_wp' );
840
  }
841
+ if ( '' == $short ) {
842
  $short = get_post_meta( $post_id, '_wp_jd_ind', true );
843
  delete_post_meta( $post_id, '_wp_jd_ind' );
844
  }
845
+ if ( '' == $short ) {
846
  $short = get_post_meta( $post_id, '_wp_jd_yourls', true );
847
  delete_post_meta( $post_id, '_wp_jd_yourls' );
848
  }
849
+ if ( '' == $short ) {
850
  $short = get_post_meta( $post_id, '_wp_jd_url', true );
851
  delete_post_meta( $post_id, '_wp_jd_url' );
852
  }
853
+ if ( '' == $short ) {
854
  $short = get_post_meta( $post_id, '_wp_jd_joturl', true );
855
  delete_post_meta( $post_id, '_wp_jd_joturl' );
856
  }
857
+ if ( '' == $short ) {
858
+ // don't delete target link.
859
  $short = get_post_meta( $post_id, '_wp_jd_target', true );
860
  }
861
+ if ( '' == $short ) {
862
  $short = get_post_meta( $post_id, '_wp_jd_clig', true );
863
  delete_post_meta( $post_id, '_wp_jd_clig' );
864
  }
865
+
866
+ if ( '' != $short ) {
867
+ update_post_meta( $post_id, '_wpt_short_url', $short );
868
  }
 
 
869
  }
870
 
871
+ /**
872
+ * Make a curl query.
873
+ *
874
+ * @param string $url URL to query.
875
+ *
876
+ * @return Curl response.
877
+ */
878
  function wp_get_curl( $url ) {
879
+
880
  $curl = curl_init( $url );
881
 
882
  curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
887
  curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
888
 
889
  $response = curl_exec( $curl );
890
+ if ( 0 !== curl_errno( $curl ) || 200 !== curl_getinfo( $curl, CURLINFO_HTTP_CODE ) ) {
891
  $response = false;
892
+ } // end if.
893
  curl_close( $curl );
894
 
895
  return $response;
899
  add_action( 'dp_duplicate_page', 'wpt_delete_copied_meta', 10, 2 );
900
  /**
901
  * Prevent 'Duplicate Posts' plug-in from copying WP to Twitter meta data
902
+ *
903
+ * @param int $new_id New post ID.
904
+ * @param object $post Old Post.
905
  */
906
  function wpt_delete_copied_meta( $new_id, $post ) {
907
  $disable = apply_filters( 'wpt_allow_copy_meta', false );
918
  }
919
 
920
  /**
921
+ * Provide aliases for changed function names if plug-ins or themes are calling WP to Twitter functions in custom code.
922
+ *
923
+ * @param string $url Query url.
924
+ * @param string $method Method.
925
+ * @param string $body Body.
926
+ * @param string $headers Headers.
927
+ * @param string $return Return data.
928
+ *
929
+ * @return data.
930
  */
931
  function jd_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $return = 'body' ) {
932
  return wpt_fetch_url( $url, $method, $body, $headers, $return );
933
  }
934
 
935
+ /**
936
+ * Alias for remote_json.
937
+ *
938
+ * @param string $url Query url.
939
+ * @param array $array Arguments.
940
+ *
941
+ * @return remote JSON.
942
+ */
943
  function jd_remote_json( $url, $array = true ) {
944
  return wpt_remote_json( $url, $array );
945
  }
946
 
947
+ /**
948
+ * Send a Tweet for a new link.
949
+ *
950
+ * @param int $link_id Link ID.
951
+ *
952
+ * @return twit link.
953
+ */
954
+ function jd_twit_link( $link_id ) {
955
+ return wpt_twit_link( $link_id );
956
  }
957
 
958
+ /**
959
+ * Get post data.
960
+ *
961
+ * @param int $post_ID Post ID.
962
+ *
963
+ * @return Array post data.
964
+ */
965
  function jd_post_info( $post_ID ) {
966
  return wpt_post_info( $post_ID );
967
  }
968
 
969
+ /**
970
+ * Sent post tweet.
971
+ *
972
+ * @param int $post_ID Post ID.
973
+ * @param string $type Type of post.
974
+ *
975
+ * @return tweet
976
+ */
977
  function jd_twit( $post_ID, $type = 'instant' ) {
978
  return wpt_tweet( $post_ID, $type );
979
  }
980
 
981
+ /**
982
+ * Set up admin styles.
983
+ */
984
  function jd_addTwitterAdminStyles() {
985
  return wpt_admin_style();
986
  }
987
 
988
+ /**
989
+ * Send to Twitter API. Fallback; deprecated.
990
+ *
991
+ * @param string $twit Tweet.
992
+ * @param mixed boolean/int $auth Author ID.
993
+ * @param int $id Post ID.
994
+ * @param boolean $media Include media.
995
+ *
996
+ * @deprecated 1/19/2017
997
+ *
998
+ * @return boolean.
999
+ */
1000
  function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false ) {
1001
  return wpt_post_to_twitter( $twit, $auth, $id, $media );
1002
+ }
1003
+
1004
+ /**
1005
+ * Update oauth settings.
1006
+ *
1007
+ * @param mixed boolean/int $auth Author ID.
1008
+ * @param mixed boolean/array $post POST data.
1009
+ *
1010
+ * @return update.
1011
+ */
1012
+ function jd_update_oauth_settings( $auth = false, $post = false ) {
1013
+ return wpt_update_oauth_settings( $auth, $post );
1014
+ }
wpt-rate-limiting.php CHANGED
@@ -1,13 +1,22 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
5
-
6
 
 
7
  /**
8
  * Hourly cron job to reset rate limits
9
  */
10
- add_action( 'wptratelimits', 'wpt_clear_rate_limits' );
11
  function wpt_clear_rate_limits() {
12
  delete_option( 'wpt_rate_limits' );
13
  }
@@ -15,105 +24,112 @@ function wpt_clear_rate_limits() {
15
  /**
16
  * Logs successful Tweets for rate limiting.
17
  *
18
- * @param $id Post ID
 
 
19
  */
20
  function wpt_log_success( $auth, $ts, $post_ID ) {
21
- if ( !$post_ID ) { return; }
22
-
23
- // get record of recent Tweets
 
 
24
  $rate_limit = get_option( 'wpt_rate_limits' );
25
  if ( ! is_array( $rate_limit ) ) {
26
  $rate_limit = array();
27
  }
28
- $post = get_post( $post_ID );
29
- $post_type = $post->post_type;
30
  $object_taxonomies = get_object_taxonomies( $post_type );
31
- $terms = wp_get_object_terms( $post_ID, $object_taxonomies, array( 'fields' => 'all' ) );
32
-
33
- foreach( $terms as $term ) {
34
  $term_id = $term->term_id;
35
- $tax = $term->taxonomy;
36
-
37
- $rate_limit[$auth][$term_id.'+'.$tax][] = $post_ID;
38
  }
39
-
40
  update_option( 'wpt_rate_limits', $rate_limit );
41
  }
42
 
43
  /**
44
  * Test Tweets against rate limiting rules.
45
  *
46
- * @param $post_ID Post ID
 
47
  *
48
  * @return boolean True if OK to Tweet.
49
  */
50
  function wpt_test_rate_limit( $post_ID, $auth ) {
51
- // record of recent Tweets
52
  $rate_limit = get_option( 'wpt_rate_limits' );
53
- $return = true;
54
- if ( !$rate_limit ) {
55
  return true;
56
  } else {
57
  $post = get_post( $post_ID );
58
  if ( is_object( $post ) ) {
59
- $post_type = $post->post_type;
60
  $object_taxonomies = get_object_taxonomies( $post_type );
61
- $terms = wp_get_object_terms( $post_ID, $object_taxonomies, array( 'fields' => 'all' ) );
62
-
63
- foreach( $terms as $term ) {
64
  $term_id = $term->term_id;
65
- $limit = wpt_get_rate_limit( $term_id );
66
- $tax = $term->taxonomy;
67
- $count = ( isset( $rate_limit[$auth][$term_id.'+'.$tax] ) ) ? count( $rate_limit[$auth][$term_id.'+'.$tax] ) : false;
68
  if ( $count && $count >= $limit ) {
69
  $return = false;
70
  }
71
  }
72
  } else {
73
- // don't rate limit if no post
74
  $return = true;
75
  }
76
  }
77
-
78
  return $return;
79
  }
80
 
81
  /**
82
  * Default rate limiting value. Limit can't be 0.
83
  *
84
- * @param $term Term ID
85
  *
86
  * @return integer Default rate limit
87
  */
88
  function wpt_default_rate_limit( $term = false ) {
89
- $limit = ( get_option( 'wpt_default_rate_limit' ) != '' ) ? get_option( 'wpt_default_rate_limit' ) : 10;
90
- $limit = ( $limit == 0 ) ? 1 : $limit;
91
-
92
- return apply_filters( 'wpt_default_rate_limit', $limit, $term );
93
  }
94
 
95
  /**
96
- * Get the current rate limit for a given term ID.
97
  *
98
- * @param $term Term ID
99
- *
100
  * @uses filter wpt_default_rate_limit
101
  *
102
  * @return integer Number of Tweets allowed per hour in this category.
103
  */
104
  function wpt_get_rate_limit( $term ) {
105
  $limits = get_option( 'wpt_rate_limit' );
106
- $limit = isset( $limits[$term] ) ? $limits[$term] : wpt_default_rate_limit( $term );
107
- if ( !is_int( $limit ) ) {
108
  $limit = wpt_default_rate_limit( $term );
109
  }
110
-
111
  return $limit;
112
  }
113
 
114
  add_action( 'init', 'wpt_term_rate_limits' );
 
 
 
115
  function wpt_term_rate_limits() {
116
- $args = apply_filters( 'wpt_rate_limit_taxonomies', array() );
117
  $taxonomies = get_taxonomies( $args );
118
  if ( ! is_array( $taxonomies ) ) {
119
  $taxonomies = array();
@@ -121,76 +137,96 @@ function wpt_term_rate_limits() {
121
  foreach ( $taxonomies as $value ) {
122
  add_action( $value . '_add_form_fields', 'wpt_add_term_rate_limit', 10, 1 );
123
  add_action( $value . '_edit_form_fields', 'wpt_edit_term_rate_limit', 10, 2 );
124
- add_action( 'edit_'.$value, 'wpt_save_term_rate_limit', 10, 2 );
125
- add_action( 'created_'.$value, 'wpt_save_term_rate_limit', 10, 2 );
126
  }
127
  }
128
 
 
 
 
 
 
 
129
  function wpt_save_term_rate_limit( $term_id, $tax_id ) {
130
- $limits = get_option( 'wpt_rate_limit' );
131
  $option_set = isset( $_POST['wpt_rate_limit'] ) ? $_POST['wpt_rate_limit'] : wpt_default_rate_limit( $term_id );
132
  if ( isset( $_POST['taxonomy'] ) ) {
133
- if ( isset( $_POST['wpt_rate_limit'] ) ) {
134
- $limits[$term_id] = $option_set;
135
  update_option( 'wpt_rate_limit', $limits );
136
- }
137
  }
138
  }
139
 
 
 
 
 
 
 
140
  function wpt_edit_term_rate_limit( $term, $taxonomy ) {
141
- $t_id = $term->term_id;
142
- $limits = get_option( 'wpt_rate_limit' );
143
- $option_set = isset( $limits[$t_id] ) ? $limits[$t_id] : wpt_default_rate_limit( $t_id );
144
- ?>
145
- <tr class="form-field">
146
- <th valign="top" scope="row">
147
- <label for="wpt_rate_limit"><?php _e( 'Max Tweets per hour on this term','wp-tweets-pro' ); ?></label>
148
- </th>
149
- <td>
150
- <input type='number' size='4' value='<?php echo esc_attr( $option_set ); ?>' name='wpt_rate_limit' id='wpt_rate_limit' />
151
- </td>
152
- </tr>
153
- <?php
154
  }
155
 
 
 
 
 
 
156
  function wpt_add_term_rate_limit( $term ) {
157
  $default = wpt_default_rate_limit();
158
  ?>
159
- <div class="form-field">
160
- <label for="wpt_rate_limit"><?php _e( 'Max Tweets per hour on this term','wp-tweets-pro' ); ?></label> <input type='number' value='<?php echo esc_attr( $default ); ?>' id='wpt_rate_limit' name='wpt_rate_limit' />
161
  </div>
162
- <?php
163
  }
164
 
 
 
 
 
 
165
  function wpt_view_rate_limits() {
166
  $limits = get_option( 'wpt_rate_limits' );
167
  if ( is_array( $limits ) ) {
168
-
169
  $output = '<ul>';
170
- foreach( $limits as $auth => $term ) {
171
- $author = ( $auth == 0 ) ? get_option( 'wtt_twitter_username' ) : get_user_meta( $auth, 'wtt_twitter_username', true );
172
  $output .= "<li><h4><a href='https://twitter.com/$author'>@$author</a>:</h4><ul>";
173
  foreach ( $term as $id => $value ) {
174
- $count = count( $value );
175
- $term_array = explode( '+', $id );
176
- $t = $term_array[0];
177
- $x = $term_array[1];
178
- $limit = wpt_get_rate_limit( $t );
179
- $term_object = get_term( $t, $x );
180
- $term_label = $term_object->name;
181
  $rate_limiting = ( $count >= $limit ) ? 'rate-limited' : 'active';
182
- $dashicon = ( $count >= $limit ) ? "<span class='dashicons dashicons-no' aria-hidden='true'></span>" : "<span class='dashicons dashicons-yes' aria-hidden='true'></span>";
183
- $output .= "<li class='$rate_limiting'>$dashicon<strong>$term_label</strong>: "
184
- . sprintf( _n( '%s Tweet sent, %s allowed.', '%s Tweets sent, %s allowed.', $count, 'wp-to-twitter' ), "<strong>$count</strong>", "<strong>$limit</strong>" )
185
- . "</li>";
186
  }
187
- $output .= "</ul>";
188
  }
189
- $output .= "</ul>";
190
-
191
  } else {
192
  $output = __( 'No Tweets have been sent this hour.', 'wp-to-twitter' );
193
  }
194
-
195
  return $output;
196
- }
1
  <?php
2
+ /**
3
+ * Rate limiting in WP to Twitter
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
 
15
 
16
+ add_action( 'wptratelimits', 'wpt_clear_rate_limits' );
17
  /**
18
  * Hourly cron job to reset rate limits
19
  */
 
20
  function wpt_clear_rate_limits() {
21
  delete_option( 'wpt_rate_limits' );
22
  }
24
  /**
25
  * Logs successful Tweets for rate limiting.
26
  *
27
+ * @param int $auth Author.
28
+ * @param string $ts Timestamp.
29
+ * @param int $post_ID Post ID.
30
  */
31
  function wpt_log_success( $auth, $ts, $post_ID ) {
32
+ if ( ! $post_ID ) {
33
+ return;
34
+ }
35
+
36
+ // get record of recent Tweets.
37
  $rate_limit = get_option( 'wpt_rate_limits' );
38
  if ( ! is_array( $rate_limit ) ) {
39
  $rate_limit = array();
40
  }
41
+ $post = get_post( $post_ID );
42
+ $post_type = $post->post_type;
43
  $object_taxonomies = get_object_taxonomies( $post_type );
44
+ $terms = wp_get_object_terms( $post_ID, $object_taxonomies, array( 'fields' => 'all' ) );
45
+
46
+ foreach ( $terms as $term ) {
47
  $term_id = $term->term_id;
48
+ $tax = $term->taxonomy;
49
+
50
+ $rate_limit[ $auth ][ $term_id . '+' . $tax ][] = $post_ID;
51
  }
52
+
53
  update_option( 'wpt_rate_limits', $rate_limit );
54
  }
55
 
56
  /**
57
  * Test Tweets against rate limiting rules.
58
  *
59
+ * @param int $post_ID Post ID.
60
+ * @param int $auth Author ID.
61
  *
62
  * @return boolean True if OK to Tweet.
63
  */
64
  function wpt_test_rate_limit( $post_ID, $auth ) {
65
+ // record of recent Tweets.
66
  $rate_limit = get_option( 'wpt_rate_limits' );
67
+ $return = true;
68
+ if ( ! $rate_limit ) {
69
  return true;
70
  } else {
71
  $post = get_post( $post_ID );
72
  if ( is_object( $post ) ) {
73
+ $post_type = $post->post_type;
74
  $object_taxonomies = get_object_taxonomies( $post_type );
75
+ $terms = wp_get_object_terms( $post_ID, $object_taxonomies, array( 'fields' => 'all' ) );
76
+
77
+ foreach ( $terms as $term ) {
78
  $term_id = $term->term_id;
79
+ $limit = wpt_get_rate_limit( $term_id );
80
+ $tax = $term->taxonomy;
81
+ $count = ( isset( $rate_limit[ $auth ][ $term_id . '+' . $tax ] ) ) ? count( $rate_limit[ $auth ][ $term_id . '+' . $tax ] ) : false;
82
  if ( $count && $count >= $limit ) {
83
  $return = false;
84
  }
85
  }
86
  } else {
87
+ // don't rate limit if no post.
88
  $return = true;
89
  }
90
  }
91
+
92
  return $return;
93
  }
94
 
95
  /**
96
  * Default rate limiting value. Limit can't be 0.
97
  *
98
+ * @param int $term Term ID.
99
  *
100
  * @return integer Default rate limit
101
  */
102
  function wpt_default_rate_limit( $term = false ) {
103
+ $limit = ( '' != get_option( 'wpt_default_rate_limit' ) ) ? get_option( 'wpt_default_rate_limit' ) : 10;
104
+ $limit = ( 0 == $limit ) ? 1 : $limit;
105
+
106
+ return apply_filters( 'wpt_default_rate_limit', $limit, $term );
107
  }
108
 
109
  /**
110
+ * Get the current rate limit for a given term ID.
111
  *
112
+ * @param string $term Term ID.
 
113
  * @uses filter wpt_default_rate_limit
114
  *
115
  * @return integer Number of Tweets allowed per hour in this category.
116
  */
117
  function wpt_get_rate_limit( $term ) {
118
  $limits = get_option( 'wpt_rate_limit' );
119
+ $limit = isset( $limits[ $term ] ) ? $limits[ $term ] : wpt_default_rate_limit( $term );
120
+ if ( ! is_int( $limit ) ) {
121
  $limit = wpt_default_rate_limit( $term );
122
  }
123
+
124
  return $limit;
125
  }
126
 
127
  add_action( 'init', 'wpt_term_rate_limits' );
128
+ /**
129
+ * Get term-based rate limits.
130
+ */
131
  function wpt_term_rate_limits() {
132
+ $args = apply_filters( 'wpt_rate_limit_taxonomies', array() );
133
  $taxonomies = get_taxonomies( $args );
134
  if ( ! is_array( $taxonomies ) ) {
135
  $taxonomies = array();
137
  foreach ( $taxonomies as $value ) {
138
  add_action( $value . '_add_form_fields', 'wpt_add_term_rate_limit', 10, 1 );
139
  add_action( $value . '_edit_form_fields', 'wpt_edit_term_rate_limit', 10, 2 );
140
+ add_action( 'edit_' . $value, 'wpt_save_term_rate_limit', 10, 2 );
141
+ add_action( 'created_' . $value, 'wpt_save_term_rate_limit', 10, 2 );
142
  }
143
  }
144
 
145
+ /**
146
+ * Save rate limit for a term.
147
+ *
148
+ * @param int $term_id Term ID.
149
+ * @param int $tax_id Taxonomy ID.
150
+ */
151
  function wpt_save_term_rate_limit( $term_id, $tax_id ) {
152
+ $limits = get_option( 'wpt_rate_limit' );
153
  $option_set = isset( $_POST['wpt_rate_limit'] ) ? $_POST['wpt_rate_limit'] : wpt_default_rate_limit( $term_id );
154
  if ( isset( $_POST['taxonomy'] ) ) {
155
+ if ( isset( $_POST['wpt_rate_limit'] ) ) {
156
+ $limits[ $term_id ] = $option_set;
157
  update_option( 'wpt_rate_limit', $limits );
158
+ }
159
  }
160
  }
161
 
162
+ /**
163
+ * Edit term rate limits.
164
+ *
165
+ * @param object $term Term object.
166
+ * @param object $taxonomy Taxonomy object.
167
+ */
168
  function wpt_edit_term_rate_limit( $term, $taxonomy ) {
169
+ $t_id = $term->term_id;
170
+ $limits = get_option( 'wpt_rate_limit' );
171
+ $option_set = isset( $limits[ $t_id ] ) ? $limits[ $t_id ] : wpt_default_rate_limit( $t_id );
172
+ ?>
173
+ <tr class="form-field">
174
+ <th valign="top" scope="row">
175
+ <label for="wpt_rate_limit"><?php _e( 'Max Tweets per hour on this term', 'wp-tweets-pro' ); ?></label>
176
+ </th>
177
+ <td>
178
+ <input type='number' size='4' value='<?php echo esc_attr( $option_set ); ?>' name='wpt_rate_limit' id='wpt_rate_limit' />
179
+ </td>
180
+ </tr>
181
+ <?php
182
  }
183
 
184
+ /**
185
+ * Add a rate limit for a given term.
186
+ *
187
+ * @param object $term Term Object.
188
+ */
189
  function wpt_add_term_rate_limit( $term ) {
190
  $default = wpt_default_rate_limit();
191
  ?>
192
+ <div class="form-field">
193
+ <label for="wpt_rate_limit"><?php _e( 'Max Tweets per hour on this term', 'wp-tweets-pro' ); ?></label> <input type='number' value='<?php echo esc_attr( $default ); ?>' id='wpt_rate_limit' name='wpt_rate_limit' />
194
  </div>
195
+ <?php
196
  }
197
 
198
+ /**
199
+ * View rate limit status.
200
+ *
201
+ * @return string Rate limit info.
202
+ */
203
  function wpt_view_rate_limits() {
204
  $limits = get_option( 'wpt_rate_limits' );
205
  if ( is_array( $limits ) ) {
 
206
  $output = '<ul>';
207
+ foreach ( $limits as $auth => $term ) {
208
+ $author = ( 0 == $auth ) ? get_option( 'wtt_twitter_username' ) : get_user_meta( $auth, 'wtt_twitter_username', true );
209
  $output .= "<li><h4><a href='https://twitter.com/$author'>@$author</a>:</h4><ul>";
210
  foreach ( $term as $id => $value ) {
211
+ $count = count( $value );
212
+ $term_array = explode( '+', $id );
213
+ $t = $term_array[0];
214
+ $x = $term_array[1];
215
+ $limit = wpt_get_rate_limit( $t );
216
+ $term_object = get_term( $t, $x );
217
+ $term_label = $term_object->name;
218
  $rate_limiting = ( $count >= $limit ) ? 'rate-limited' : 'active';
219
+ $dashicon = ( $count >= $limit ) ? "<span class='dashicons dashicons-no' aria-hidden='true'></span>" : "<span class='dashicons dashicons-yes' aria-hidden='true'></span>";
220
+ $output .= "<li class='$rate_limiting'>$dashicon<strong>$term_label</strong>: ";
221
+ // Translators: Number of tweets sent, number allowed.
222
+ $output .= sprintf( _n( '%1$s Tweet sent, %2$s allowed.', '%1$s Tweets sent, %2$s allowed.', $count, 'wp-to-twitter' ), "<strong>$count</strong>", "<strong>$limit</strong>" ) . '</li>';
223
  }
224
+ $output .= '</ul>';
225
  }
226
+ $output .= '</ul>';
 
227
  } else {
228
  $output = __( 'No Tweets have been sent this hour.', 'wp-to-twitter' );
229
  }
230
+
231
  return $output;
232
+ }
wpt-truncate.php CHANGED
@@ -1,58 +1,81 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
5
 
 
 
 
 
 
6
  function wpt_max_length() {
7
- $config = get_transient( 'wpt_twitter_config' );
8
  if ( ! $config ) {
9
- $connection = wtt_oauth_connection();
10
  if ( $connection ) {
11
- $config = $connection->get( 'https://api.twitter.com/1.1/help/configuration.json' );
12
- set_transient( 'wpt_twitter_config', $config, 60*60*24 );
13
  } else {
14
- $config = json_encode( array(
15
- 'http_length' => 23,
16
- 'https_length' => 23,
17
- 'reserved_chars' => 24
18
  ) );
19
  }
20
  }
21
-
22
  $decoded = json_decode( $config );
23
-
24
  if ( is_object( $decoded ) && isset( $decoded->short_url_length ) ) {
25
  $short_url_length = $decoded->short_url_length;
26
  $short_url_https = $decoded->short_url_length_https;
27
  $reserved_char = $decoded->characters_reserved_per_media;
28
- $values = array(
29
- 'http_length' => $short_url_length,
30
- 'https_length' => $short_url_https,
31
- 'reserved_chars' => $reserved_char
32
- );
33
-
34
  } else {
35
- // if config query is invalid, use default values; these may become invalid
36
- $values = array(
37
- 'http_length' => 23,
38
- 'https_length' => 23,
39
- 'reserved_chars' => 24
40
- );
41
  }
42
-
43
  $values['base_length'] = intval( ( get_option( 'wpt_tweet_length' ) ) ? get_option( 'wpt_tweet_length' ) : 140 ) - 1;
44
-
45
- return apply_filters( 'wpt_max_length', $values );
46
  }
47
 
48
  add_filter( 'wpt_tweet_sentence', 'wpt_filter_urls', 10, 2 );
 
 
 
 
 
 
 
 
49
  function wpt_filter_urls( $tweet, $post_ID ) {
50
- preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $tweet, $match);
51
  $title = get_the_title( $post_ID );
52
-
53
- if ( isset( $match[0] ) && !empty( $match[0] ) ) {
54
  $urls = $match[0];
55
- foreach( $urls as $url ) {
56
  if ( esc_url( $url ) ) {
57
  $short = wpt_shorten_url( $url, $title, $post_ID, false, false );
58
  if ( $short ) {
@@ -61,85 +84,90 @@ function wpt_filter_urls( $tweet, $post_ID ) {
61
  }
62
  }
63
  }
64
-
65
  return $tweet;
66
  }
67
 
68
-
 
 
 
 
 
 
 
 
 
 
69
  function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = false ) {
70
- // media file no longer needs accounting in shortening. 9/22/2016
71
- $maxlength = wpt_max_length();
72
- $length = $maxlength['base_length'];
73
- $tweet = apply_filters( 'wpt_tweet_sentence', $tweet, $post_ID );
74
- $tweet = trim( wpt_custom_shortcodes( $tweet, $post_ID ) );
75
- $tweet = trim( wpt_user_meta_shortcodes( $tweet, $post['authId'] ) );
76
- $encoding = ( get_option( 'blog_charset' ) != 'UTF-8' && get_option( 'blog_charset' ) != '' ) ? get_option( 'blog_charset' ) : 'UTF-8';
77
- $diff = 0;
78
-
79
- // Add custom append/prepend fields to Tweet text
80
- if ( get_option( 'jd_twit_prepend' ) != "" && $tweet != '' ) {
81
- $tweet = stripslashes( get_option( 'jd_twit_prepend' ) ) . " " . $tweet;
 
 
 
82
  }
83
- if ( get_option( 'jd_twit_append' ) != "" && $tweet != '' ) {
84
- $tweet = $tweet . " " . stripslashes( get_option( 'jd_twit_append' ) );
85
- }
86
-
87
  // there are no tags in this Tweet. Truncate and return.
88
- if ( !wpt_has_tags( $tweet ) ) {
89
  $post_tweet = mb_substr( $tweet, 0, $length, $encoding );
90
  return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 1 );
91
  }
92
-
93
- // create full unconditional post tweet - prior to truncation
94
  // order matters; arrays have to be ordered the same way.
95
- $tags = array_map( 'wpt_make_tag', wpt_tags() );
96
- $values = wpt_create_values( $post, $post_ID, $ref );
97
-
98
  $post_tweet = str_ireplace( $tags, $values, $tweet );
99
- // check total length
100
  $str_length = mb_strlen( urldecode( wpt_normalize( $post_tweet ) ), $encoding );
101
-
102
- /**
103
- * Check whether completed replacement is still within allowed length.
104
- *
105
- * If so, post as is.
106
- */
107
  if ( $str_length < $length + 1 ) {
108
  if ( mb_strlen( wpt_normalize( $post_tweet ) ) > $length + 1 ) {
109
  $post_tweet = mb_substr( $post_tweet, 0, $length, $encoding );
110
  }
111
 
112
- return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 2 ); // return early if all is well without replacements.
113
  } else {
114
  $has_excerpt_tag = wpt_has( $tweet, '#post#' );
115
  $has_title_tag = wpt_has( $tweet, '#title#' );
116
  $has_short_url = wpt_has( $tweet, '#url#' );
117
  $has_long_url = wpt_has( $tweet, '#longurl#' );
118
-
119
- $url_strlen = mb_strlen( urldecode( wpt_normalize( $values['url'] ) ), $encoding );
120
- $longurl_strlen = mb_strlen( urldecode( wpt_normalize( $values['longurl'] ) ), $encoding );
121
- /**
122
- * Tweet is too long, so we'll have to truncate that sucker.
123
- */
124
  $length_array = wpt_length_array( $values, $encoding );
125
 
126
- // Twitter's t.co shortener is mandatory. All URLS are max-character value set by Twitter.
127
  $tco = ( wpt_is_ssl( $values['url'] ) ) ? $maxlength['https_length'] : $maxlength['http_length'];
128
  $order = get_option( 'wpt_truncation_order' );
129
  if ( is_array( $order ) ) {
130
  asort( $order );
131
  $preferred = array();
132
  foreach ( $order as $k => $v ) {
133
- if ( $k == 'excerpt' ) {
134
- $k = 'post';
135
- $value = $length_array[ 'post' ];
136
- } else if ( $k == 'blogname' ) {
137
- $k = 'blog';
138
- $value = $length_array[ 'blog' ];
139
  } else {
140
  $value = $length_array[ $k ];
141
  }
142
-
143
  $preferred[ $k ] = $value;
144
  }
145
  } else {
@@ -147,30 +175,26 @@ function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = fa
147
  }
148
  if ( $has_short_url ) {
149
  $diff = ( ( $url_strlen - $tco ) > 0 ) ? $url_strlen - $tco : 0;
150
- } else if ( $has_long_url ) {
151
- $diff = ( ( $longurl_strlen - $tco ) > 0 ) ? $longurl_strlen - $tco : 0;
152
  }
153
  if ( $str_length > ( $length + 1 + $diff ) ) {
154
- foreach ( $preferred AS $key => $value ) {
155
- // don't truncate content of post excerpt or title if those tags not in use
156
- if ( ! ( $key == 'excerpt' && ! $has_excerpt_tag ) && ! ( $key == 'title' && ! $has_title_tag ) ) {
157
  $str_length = mb_strlen( urldecode( wpt_normalize( trim( $post_tweet ) ) ), $encoding );
158
  if ( $str_length > ( $length + 1 + $diff ) ) {
159
  $trim = $str_length - ( $length + 1 + $diff );
160
- $old_value = $values[$key];
161
- // prevent URL from being modified
162
  $post_tweet = str_ireplace( array( $values['url'], $values['longurl'] ), array( '#url#', '#longurl#' ), $post_tweet );
163
 
164
- /**
165
- * These tag fields should be removed completely, rather than truncated.
166
- */
167
  if ( wpt_remove_tag( $key ) ) {
168
  $new_value = '';
169
- /**
170
- * These tag fields should have stray characters removed on word boundaries
171
- */
172
- } else if ( $key == 'tags' ) {
173
- // remove any stray hash characters due to string truncation
174
  if ( mb_strlen( $old_value ) - $trim <= 2 ) {
175
  $new_value = '';
176
  } else {
@@ -179,23 +203,19 @@ function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = fa
179
  $new_value = trim( mb_substr( $new_value, 0, mb_strrpos( $new_value, '#', $encoding ) - 1 ) );
180
  }
181
  }
182
- /**
183
- * Just flat out truncate everything else cold.
184
- */
185
  } else {
186
- // trim letters
187
  $new_value = mb_substr( $old_value, 0, - ( $trim ), $encoding );
188
- // trim rest of last word
189
  $last_space = strrpos( $new_value, ' ' );
190
- $new_value = mb_substr( $new_value, 0, $last_space, $encoding );
191
- /**
192
- * If you want to add something like an ellipsis after truncation, use this filter.
193
- */
194
- $new_value = apply_filters( 'wpt_filter_truncated_value', $new_value, $key, $old_value );
195
  }
196
  $post_tweet = str_ireplace( $old_value, $new_value, $post_tweet );
197
- // put URL back before checking length
198
- $post_tweet = str_ireplace( array( '#url#', '#longurl#' ), array( $values['url'], $values['longurl'] ), $post_tweet );
199
  } else {
200
  if ( mb_strlen( wpt_normalize( $post_tweet ), $encoding ) > ( $length + 1 + $diff ) ) {
201
  $post_tweet = mb_substr( $post_tweet, 0, ( $length + $diff ), $encoding );
@@ -204,32 +224,32 @@ function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = fa
204
  }
205
  }
206
  }
207
-
208
  // this is needed in case a tweet needs to be truncated outright and the truncation values aren't in the above.
209
- // 1) removes URL 2) checks length of remainder 3) Replaces URL
210
  if ( mb_strlen( wpt_normalize( $post_tweet ) ) > $length + 1 ) {
211
  $tweet = false;
212
  if ( $has_short_url ) {
213
  $url = $values['url'];
214
  $tag = '#url#';
215
- } else if ( $has_long_url ) {
216
  $url = $values['longurl'];
217
  $tag = '#longurl#';
218
  } else {
219
  $post_tweet = mb_substr( $post_tweet, 0, ( $length + $diff ), $encoding );
220
  $tweet = true;
221
  }
222
-
223
- if ( !$tweet ) {
224
  $temp = str_ireplace( $url, $tag, $post_tweet );
225
  if ( mb_strlen( wpt_normalize( $temp ) ) > ( ( $length + 1 ) - ( $tco - strlen( $tag ) ) ) && $temp != $post_tweet ) {
226
- if ( stripos( $temp, '#url#' ) === false && stripos( $temp, '#longurl#' ) === false ) {
227
- $post_tweet = trim( mb_substr( $temp, 0, $length, $encoding ) );
228
  } else {
229
- $post_tweet = trim( mb_substr( $temp, 0, ( $length - $tco - 1 ), $encoding ) );
230
  }
231
  // it's possible to trim off the #url# part in this process. If that happens, put it back.
232
- $sub_sentence = ( !wpt_has( $post_tweet, $tag ) && ( $has_short_url || $has_long_url ) ) ? $post_tweet . ' ' . $tag : $post_tweet;
233
  $post_tweet = str_ireplace( $tag, $url, $sub_sentence );
234
  }
235
  }
@@ -239,14 +259,29 @@ function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = fa
239
  return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 3 );
240
  }
241
 
 
 
 
 
 
 
 
 
242
  function wpt_has( $string, $tag ) {
243
  if ( strpos( $string, $tag ) === false ) {
244
  return false;
245
  }
246
-
247
  return true;
248
  }
249
 
 
 
 
 
 
 
 
250
  function wpt_has_tags( $string ) {
251
  $tags = wpt_tags();
252
  foreach ( $tags as $tag ) {
@@ -258,33 +293,64 @@ function wpt_has_tags( $string ) {
258
  return false;
259
  }
260
 
 
 
 
 
 
 
 
261
  function wpt_remove_tag( $key ) {
262
- switch( $key ) {
263
  case 'account':
264
  case 'author':
265
  case 'category':
266
  case 'date':
267
  case 'modified':
268
  case 'reference':
269
- case '@': $return = true; break;
270
- default: $return = false;
 
 
 
271
  }
272
-
273
  return $return;
274
  }
275
 
 
 
 
 
 
276
  function wpt_tags() {
277
  return apply_filters( 'wpt_tags', array( 'url', 'title', 'blog', 'post', 'category', 'date', 'author', 'displayname', 'tags', 'modified', 'reference', 'account', '@', 'cat_desc', 'longurl' ) );
278
  }
279
 
 
 
 
 
 
 
 
280
  function wpt_make_tag( $value ) {
281
  return '#' . $value . '#';
282
  }
283
 
 
 
 
 
 
 
 
 
 
284
  function wpt_create_values( $post, $post_ID, $ref ) {
285
- $shrink = ( $post['shortUrl'] != '' ) ? $post['shortUrl'] : apply_filters( 'wptt_shorten_link', $post['postLink'], $post['postTitle'], $post_ID, false );
286
- // generate template variable values
287
- $auth = $post['authId'];
288
  $title = trim( apply_filters( 'wpt_status', $post['postTitle'], $post_ID, 'title' ) );
289
  $blogname = trim( $post['blogTitle'] );
290
  $excerpt = trim( apply_filters( 'wpt_status', $post['postExcerpt'], $post_ID, 'post' ) );
@@ -296,108 +362,123 @@ function wpt_create_values( $post, $post_ID, $ref ) {
296
  $account = get_option( 'wtt_twitter_username' );
297
  $date = trim( $post['postDate'] );
298
  $modified = trim( $post['postModified'] );
299
- if ( get_option( 'jd_individual_twitter_users' ) == 1 ) {
300
- if ( $user_account == '' ) {
301
- if ( get_user_meta( $auth, 'wp-to-twitter-enable-user', true ) == 'mainAtTwitter' ) {
302
- $account = $user_account = stripcslashes( get_user_meta( $auth, 'wp-to-twitter-user-username', true ) );
303
- } else if ( get_user_meta( $auth, 'wp-to-twitter-enable-user', true ) == 'mainAtTwitterPlus' ) {
304
- $account = $user_account = stripcslashes( get_user_meta( $auth, 'wp-to-twitter-user-username', true ) . ' @' . get_option( 'wtt_twitter_username' ) );
 
 
305
  }
306
  } else {
307
  $account = "$user_account";
308
  }
309
  }
310
  $display_name = get_the_author_meta( 'display_name', $auth );
311
- $author = ( $user_account != '' ) ? "@$user_account" : $display_name; // value of #author#
312
- $account = ( $account != '' ) ? "@$account" : ''; // value of #account#
313
- $uaccount = ( $user_account != '' ) ? "@$user_account" : "$account"; // value of #@#
314
- // clean up data if extra @ included in user data //
315
- $account = str_ireplace( '@@', '@', $account );
316
- $uaccount = str_ireplace( '@@', '@', $uaccount );
317
- $author = str_ireplace( '@@', '@', $author );
318
-
319
- if ( get_user_meta( $auth, 'wpt-remove', true ) == 'on' ) {
320
  $account = '';
321
  }
322
-
323
- if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() == true ) {
324
  $reference = ( $ref ) ? $account : '@' . get_option( 'wtt_twitter_username' );
325
  } else {
326
  $reference = '';
327
- }
328
-
329
- return array(
330
- 'url' => $thisposturl,
331
- 'title' => $title,
332
- 'blog' => $blogname,
333
- 'post' => $excerpt,
334
- 'category' => $category,
335
- 'date' => $date,
336
- 'author' => $author,
337
  'displayname' => $display_name,
338
- 'tags' => $tags,
339
- 'modified' => $modified,
340
- 'reference' => $reference,
341
- 'account' => $account,
342
- '@' => $uaccount,
343
- 'cat_desc' => $cat_desc,
344
- 'longurl' => $post['postLink']
345
  );
346
  }
347
 
 
 
 
 
 
 
 
 
348
  function wpt_length_array( $values, $encoding ) {
349
  foreach ( $values as $key => $value ) {
350
- $array[$key] = mb_strlen( wpt_normalize( $value ), $encoding );
351
  }
352
 
353
  return $array;
354
  }
355
 
356
-
357
  /**
358
- * Parse custom shortcodes
359
  *
360
- * @param string $sentence Tweet template
361
  * @param integer $post_ID Post ID.
362
  *
363
  * @return string $sentence with any custom shortcodes replaced with their appropriate content.
364
  */
365
  function wpt_custom_shortcodes( $sentence, $post_ID ) {
366
  $pattern = '/([([\[\]?)([A-Za-z0-9-_])*(\]\]]?)+/';
367
- $params = array( 0 => "[[", 1 => "]]" );
 
 
 
368
  preg_match_all( $pattern, $sentence, $matches );
369
  if ( $matches && is_array( $matches[0] ) ) {
370
  foreach ( $matches[0] as $value ) {
371
  $shortcode = "$value";
372
- $field = str_replace( $params, "", $shortcode );
373
  $custom = apply_filters( 'wpt_custom_shortcode', strip_tags( get_post_meta( $post_ID, $field, true ) ), $post_ID, $field );
374
  $sentence = str_replace( $shortcode, $custom, $sentence );
375
  }
376
  }
377
-
378
  return $sentence;
379
  }
380
 
381
  /**
382
- * Parse user meta shortcodes
383
  *
384
- * @param string $sentence Tweet template
385
- * @param integer $auth_ID Post Author ID.
386
  *
387
  * @return string $sentence with any custom shortcodes replaced with their appropriate content.
388
  */
389
- function wpt_user_meta_shortcodes( $sentence, $auth_ID ) {
390
  $pattern = '/([({\{\}?)([A-Za-z0-9-_])*(\}\}}?)+/';
391
- $params = array( 0 => "{{", 1 => "}}" );
 
 
 
392
  preg_match_all( $pattern, $sentence, $matches );
393
  if ( $matches && is_array( $matches[0] ) ) {
394
  foreach ( $matches[0] as $value ) {
395
  $shortcode = "$value";
396
- $field = str_replace( $params, "", $shortcode );
397
- $custom = apply_filters( 'wpt_user_meta_shortcode', strip_tags( get_user_meta( $auth_ID, $field, true ) ), $auth_ID, $field );
398
  $sentence = str_replace( $shortcode, $custom, $sentence );
399
  }
400
  }
401
-
402
  return $sentence;
403
- }
1
  <?php
2
+ /**
3
+ * Construct and check lengths of Tweets - WP to Twitter
4
+ *
5
+ * @category Core
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
+ /**
17
+ * Check the current allowed max lengths.
18
+ *
19
+ * @return array of URL lengths and params.
20
+ */
21
  function wpt_max_length() {
22
+ $config = get_transient( 'wpt_twitter_config' );
23
  if ( ! $config ) {
24
+ $connection = wpt_oauth_connection();
25
  if ( $connection ) {
26
+ $config = $connection->get( 'https://api.twitter.com/1.1/help/configuration.json' );
27
+ set_transient( 'wpt_twitter_config', $config, 60 * 60 * 24 );
28
  } else {
29
+ $config = json_encode( array(
30
+ 'http_length' => 23,
31
+ 'https_length' => 23,
32
+ 'reserved_chars' => 24,
33
  ) );
34
  }
35
  }
36
+
37
  $decoded = json_decode( $config );
38
+
39
  if ( is_object( $decoded ) && isset( $decoded->short_url_length ) ) {
40
  $short_url_length = $decoded->short_url_length;
41
  $short_url_https = $decoded->short_url_length_https;
42
  $reserved_char = $decoded->characters_reserved_per_media;
43
+ $values = array(
44
+ 'http_length' => $short_url_length,
45
+ 'https_length' => $short_url_https,
46
+ 'reserved_chars' => $reserved_char,
47
+ );
48
+
49
  } else {
50
+ // if config query is invalid, use default values; these may become invalid.
51
+ $values = array(
52
+ 'http_length' => 23,
53
+ 'https_length' => 23,
54
+ 'reserved_chars' => 24,
55
+ );
56
  }
57
+
58
  $values['base_length'] = intval( ( get_option( 'wpt_tweet_length' ) ) ? get_option( 'wpt_tweet_length' ) : 140 ) - 1;
59
+
60
+ return apply_filters( 'wpt_max_length', $values );
61
  }
62
 
63
  add_filter( 'wpt_tweet_sentence', 'wpt_filter_urls', 10, 2 );
64
+ /**
65
+ * Filter the URLs in a tweet and shorten them.
66
+ *
67
+ * @param string $tweet Tweet.
68
+ * @param int $post_ID Post ID.
69
+ *
70
+ * @return string New tweet text.
71
+ */
72
  function wpt_filter_urls( $tweet, $post_ID ) {
73
+ preg_match_all( '#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $tweet, $match );
74
  $title = get_the_title( $post_ID );
75
+
76
+ if ( isset( $match[0] ) && ! empty( $match[0] ) ) {
77
  $urls = $match[0];
78
+ foreach ( $urls as $url ) {
79
  if ( esc_url( $url ) ) {
80
  $short = wpt_shorten_url( $url, $title, $post_ID, false, false );
81
  if ( $short ) {
84
  }
85
  }
86
  }
87
+
88
  return $tweet;
89
  }
90
 
91
+ /**
92
+ * Parse the text of a Tweet to ensure included tags don't exceed length requirements.
93
+ *
94
+ * @param string $tweet Tweet text.
95
+ * @param array $post Post data.
96
+ * @param int $post_ID Post ID.
97
+ * @param boolean $retweet Is this a retweet.
98
+ * @param boolean $ref Reference.
99
+ *
100
+ * @return string New text.
101
+ */
102
  function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = false ) {
103
+ // media file no longer needs accounting in shortening. 9/22/2016.
104
+ $maxlength = wpt_max_length();
105
+ $length = $maxlength['base_length'];
106
+ $tweet = apply_filters( 'wpt_tweet_sentence', $tweet, $post_ID );
107
+ $tweet = trim( wpt_custom_shortcodes( $tweet, $post_ID ) );
108
+ $tweet = trim( wpt_user_meta_shortcodes( $tweet, $post['authId'] ) );
109
+ $encoding = ( 'UTF-8' != get_option( 'blog_charset' ) && '' != get_option( 'blog_charset' ) ) ? get_option( 'blog_charset' ) : 'UTF-8';
110
+ $diff = 0;
111
+
112
+ // Add custom append/prepend fields to Tweet text.
113
+ if ( '' != get_option( 'jd_twit_prepend' ) && '' != $tweet ) {
114
+ $tweet = stripslashes( get_option( 'jd_twit_prepend' ) ) . ' ' . $tweet;
115
+ }
116
+ if ( '' != get_option( 'jd_twit_append' ) && '' != $tweet ) {
117
+ $tweet = $tweet . ' ' . stripslashes( get_option( 'jd_twit_append' ) );
118
  }
119
+
 
 
 
120
  // there are no tags in this Tweet. Truncate and return.
121
+ if ( ! wpt_has_tags( $tweet ) ) {
122
  $post_tweet = mb_substr( $tweet, 0, $length, $encoding );
123
  return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 1 );
124
  }
125
+
126
+ // create full unconditional post tweet - prior to truncation.
127
  // order matters; arrays have to be ordered the same way.
128
+ $tags = array_map( 'wpt_make_tag', wpt_tags() );
129
+ $values = wpt_create_values( $post, $post_ID, $ref );
130
+
131
  $post_tweet = str_ireplace( $tags, $values, $tweet );
132
+ // check total length.
133
  $str_length = mb_strlen( urldecode( wpt_normalize( $post_tweet ) ), $encoding );
134
+
135
+ // Check whether completed replacement is still within allowed length.
 
 
 
 
136
  if ( $str_length < $length + 1 ) {
137
  if ( mb_strlen( wpt_normalize( $post_tweet ) ) > $length + 1 ) {
138
  $post_tweet = mb_substr( $post_tweet, 0, $length, $encoding );
139
  }
140
 
141
+ return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 2 ); // return early if all is well.
142
  } else {
143
  $has_excerpt_tag = wpt_has( $tweet, '#post#' );
144
  $has_title_tag = wpt_has( $tweet, '#title#' );
145
  $has_short_url = wpt_has( $tweet, '#url#' );
146
  $has_long_url = wpt_has( $tweet, '#longurl#' );
147
+
148
+ $url_strlen = mb_strlen( urldecode( wpt_normalize( $values['url'] ) ), $encoding );
149
+ $longurl_strlen = mb_strlen( urldecode( wpt_normalize( $values['longurl'] ) ), $encoding );
150
+
151
+ // Tweet is too long, so we'll have to truncate that sucker.
 
152
  $length_array = wpt_length_array( $values, $encoding );
153
 
154
+ // Twitter's t.co shortener is mandatory. All URLS are max-character value set by Twitter.
155
  $tco = ( wpt_is_ssl( $values['url'] ) ) ? $maxlength['https_length'] : $maxlength['http_length'];
156
  $order = get_option( 'wpt_truncation_order' );
157
  if ( is_array( $order ) ) {
158
  asort( $order );
159
  $preferred = array();
160
  foreach ( $order as $k => $v ) {
161
+ if ( 'excerpt' == $k ) {
162
+ $k = 'post';
163
+ $value = $length_array['post'];
164
+ } elseif ( 'blogname' == $k ) {
165
+ $k = 'blog';
166
+ $value = $length_array['blog'];
167
  } else {
168
  $value = $length_array[ $k ];
169
  }
170
+
171
  $preferred[ $k ] = $value;
172
  }
173
  } else {
175
  }
176
  if ( $has_short_url ) {
177
  $diff = ( ( $url_strlen - $tco ) > 0 ) ? $url_strlen - $tco : 0;
178
+ } elseif ( $has_long_url ) {
179
+ $diff = ( ( $longurl_strlen - $tco ) > 0 ) ? $longurl_strlen - $tco : 0;
180
  }
181
  if ( $str_length > ( $length + 1 + $diff ) ) {
182
+ foreach ( $preferred as $key => $value ) {
183
+ // don't truncate content of post excerpt or title if those tags not in use.
184
+ if ( ! ( 'excerpt' == $key && ! $has_excerpt_tag ) && ! ( 'title' == $key && ! $has_title_tag ) ) {
185
  $str_length = mb_strlen( urldecode( wpt_normalize( trim( $post_tweet ) ) ), $encoding );
186
  if ( $str_length > ( $length + 1 + $diff ) ) {
187
  $trim = $str_length - ( $length + 1 + $diff );
188
+ $old_value = $values[ $key ];
189
+ // prevent URL from being modified.
190
  $post_tweet = str_ireplace( array( $values['url'], $values['longurl'] ), array( '#url#', '#longurl#' ), $post_tweet );
191
 
192
+ // These tag fields should be removed completely, rather than truncated.
 
 
193
  if ( wpt_remove_tag( $key ) ) {
194
  $new_value = '';
195
+ // These tag fields should have stray characters removed on word boundaries.
196
+ } elseif ( 'tags' == $key ) {
197
+ // remove any stray hash characters due to string truncation.
 
 
198
  if ( mb_strlen( $old_value ) - $trim <= 2 ) {
199
  $new_value = '';
200
  } else {
203
  $new_value = trim( mb_substr( $new_value, 0, mb_strrpos( $new_value, '#', $encoding ) - 1 ) );
204
  }
205
  }
206
+ // Just flat out truncate everything else cold.
 
 
207
  } else {
208
+ // trim letters.
209
  $new_value = mb_substr( $old_value, 0, - ( $trim ), $encoding );
210
+ // trim rest of last word.
211
  $last_space = strrpos( $new_value, ' ' );
212
+ $new_value = mb_substr( $new_value, 0, $last_space, $encoding );
213
+ // If you want to add something like an ellipsis after truncation, use this filter.
214
+ $new_value = apply_filters( 'wpt_filter_truncated_value', $new_value, $key, $old_value );
 
 
215
  }
216
  $post_tweet = str_ireplace( $old_value, $new_value, $post_tweet );
217
+ // put URL back before checking length.
218
+ $post_tweet = str_ireplace( array( '#url#', '#longurl#' ), array( $values['url'], $values['longurl'] ), $post_tweet );
219
  } else {
220
  if ( mb_strlen( wpt_normalize( $post_tweet ), $encoding ) > ( $length + 1 + $diff ) ) {
221
  $post_tweet = mb_substr( $post_tweet, 0, ( $length + $diff ), $encoding );
224
  }
225
  }
226
  }
227
+
228
  // this is needed in case a tweet needs to be truncated outright and the truncation values aren't in the above.
229
+ // 1) removes URL 2) checks length of remainder 3) Replaces URL.
230
  if ( mb_strlen( wpt_normalize( $post_tweet ) ) > $length + 1 ) {
231
  $tweet = false;
232
  if ( $has_short_url ) {
233
  $url = $values['url'];
234
  $tag = '#url#';
235
+ } elseif ( $has_long_url ) {
236
  $url = $values['longurl'];
237
  $tag = '#longurl#';
238
  } else {
239
  $post_tweet = mb_substr( $post_tweet, 0, ( $length + $diff ), $encoding );
240
  $tweet = true;
241
  }
242
+
243
+ if ( ! $tweet ) {
244
  $temp = str_ireplace( $url, $tag, $post_tweet );
245
  if ( mb_strlen( wpt_normalize( $temp ) ) > ( ( $length + 1 ) - ( $tco - strlen( $tag ) ) ) && $temp != $post_tweet ) {
246
+ if ( false === stripos( $temp, '#url#' ) && false === stripos( $temp, '#longurl#' ) ) {
247
+ $post_tweet = trim( mb_substr( $temp, 0, $length, $encoding ) );
248
  } else {
249
+ $post_tweet = trim( mb_substr( $temp, 0, ( $length - $tco - 1 ), $encoding ) );
250
  }
251
  // it's possible to trim off the #url# part in this process. If that happens, put it back.
252
+ $sub_sentence = ( ! wpt_has( $post_tweet, $tag ) && ( $has_short_url || $has_long_url ) ) ? $post_tweet . ' ' . $tag : $post_tweet;
253
  $post_tweet = str_ireplace( $tag, $url, $sub_sentence );
254
  }
255
  }
259
  return apply_filters( 'wpt_custom_truncate', $post_tweet, $tweet, $post_ID, $retweet, 3 );
260
  }
261
 
262
+ /**
263
+ * Check whether a tag is within the string.
264
+ *
265
+ * @param string $string String. Probably a Tweet.
266
+ * @param string $tag Template tag text.
267
+ *
268
+ * @return boolean.
269
+ */
270
  function wpt_has( $string, $tag ) {
271
  if ( strpos( $string, $tag ) === false ) {
272
  return false;
273
  }
274
+
275
  return true;
276
  }
277
 
278
+ /**
279
+ * Check whether any tags are present.
280
+ *
281
+ * @param string $string String. Probably a Tweet.
282
+ *
283
+ * @return boolean.
284
+ */
285
  function wpt_has_tags( $string ) {
286
  $tags = wpt_tags();
287
  foreach ( $tags as $tag ) {
293
  return false;
294
  }
295
 
296
+ /**
297
+ * Get a tag to remove.
298
+ *
299
+ * @param string $key Template tag.
300
+ *
301
+ * @return boolean.
302
+ */
303
  function wpt_remove_tag( $key ) {
304
+ switch ( $key ) {
305
  case 'account':
306
  case 'author':
307
  case 'category':
308
  case 'date':
309
  case 'modified':
310
  case 'reference':
311
+ case '@':
312
+ $return = true;
313
+ break;
314
+ default:
315
+ $return = false;
316
  }
317
+
318
  return $return;
319
  }
320
 
321
+ /**
322
+ * Get all valid template tags.
323
+ *
324
+ * @return array tags.
325
+ */
326
  function wpt_tags() {
327
  return apply_filters( 'wpt_tags', array( 'url', 'title', 'blog', 'post', 'category', 'date', 'author', 'displayname', 'tags', 'modified', 'reference', 'account', '@', 'cat_desc', 'longurl' ) );
328
  }
329
 
330
+ /**
331
+ * Adjust a tag string into its ## usage.
332
+ *
333
+ * @param string $value Any text.
334
+ *
335
+ * @return string wrapped.
336
+ */
337
  function wpt_make_tag( $value ) {
338
  return '#' . $value . '#';
339
  }
340
 
341
+ /**
342
+ * Create values. Get the value of tags.
343
+ *
344
+ * @param array $post Post array.
345
+ * @param int $post_ID Post ID.
346
+ * @param boolean $ref Use referential author.
347
+ *
348
+ * @return array of values.
349
+ */
350
  function wpt_create_values( $post, $post_ID, $ref ) {
351
+ $shrink = ( '' != $post['shortUrl'] ) ? $post['shortUrl'] : apply_filters( 'wptt_shorten_link', $post['postLink'], $post['postTitle'], $post_ID, false );
352
+ // generate template variable values.
353
+ $auth = $post['authId'];
354
  $title = trim( apply_filters( 'wpt_status', $post['postTitle'], $post_ID, 'title' ) );
355
  $blogname = trim( $post['blogTitle'] );
356
  $excerpt = trim( apply_filters( 'wpt_status', $post['postExcerpt'], $post_ID, 'post' ) );
362
  $account = get_option( 'wtt_twitter_username' );
363
  $date = trim( $post['postDate'] );
364
  $modified = trim( $post['postModified'] );
365
+ if ( 1 == get_option( 'jd_individual_twitter_users' ) ) {
366
+ if ( '' == $user_account ) {
367
+ if ( 'mainAtTwitter' == get_user_meta( $auth, 'wp-to-twitter-enable-user', true ) ) {
368
+ $user_account = stripcslashes( get_user_meta( $auth, 'wp-to-twitter-user-username', true ) );
369
+ $account = $user_account;
370
+ } elseif ( 'mainAtTwitterPlus' == get_user_meta( $auth, 'wp-to-twitter-enable-user', true ) ) {
371
+ $user_account = stripcslashes( get_user_meta( $auth, 'wp-to-twitter-user-username', true ) . ' @' . get_option( 'wtt_twitter_username' ) );
372
+ $account = $user_account;
373
  }
374
  } else {
375
  $account = "$user_account";
376
  }
377
  }
378
  $display_name = get_the_author_meta( 'display_name', $auth );
379
+ $author = ( '' != $user_account ) ? "@$user_account" : $display_name; // value of #author#.
380
+ $account = ( '' != $account ) ? "@$account" : ''; // value of #account#.
381
+ $uaccount = ( '' != $user_account ) ? "@$user_account" : "$account"; // value of #@#.
382
+ // clean up data if extra @ included in user data.
383
+ $account = str_ireplace( '@@', '@', $account );
384
+ $uaccount = str_ireplace( '@@', '@', $uaccount );
385
+ $author = str_ireplace( '@@', '@', $author );
386
+
387
+ if ( 'on' == get_user_meta( $auth, 'wpt-remove', true ) ) {
388
  $account = '';
389
  }
390
+
391
+ if ( function_exists( 'wpt_pro_exists' ) && true == wpt_pro_exists() ) {
392
  $reference = ( $ref ) ? $account : '@' . get_option( 'wtt_twitter_username' );
393
  } else {
394
  $reference = '';
395
+ }
396
+
397
+ return array(
398
+ 'url' => $thisposturl,
399
+ 'title' => $title,
400
+ 'blog' => $blogname,
401
+ 'post' => $excerpt,
402
+ 'category' => $category,
403
+ 'date' => $date,
404
+ 'author' => $author,
405
  'displayname' => $display_name,
406
+ 'tags' => $tags,
407
+ 'modified' => $modified,
408
+ 'reference' => $reference,
409
+ 'account' => $account,
410
+ '@' => $uaccount,
411
+ 'cat_desc' => $cat_desc,
412
+ 'longurl' => $post['postLink'],
413
  );
414
  }
415
 
416
+ /**
417
+ * Generate array of length values of every value.
418
+ *
419
+ * @param array $values All values.
420
+ * @param string $encoding Current encoding.
421
+ *
422
+ * @return array.
423
+ */
424
  function wpt_length_array( $values, $encoding ) {
425
  foreach ( $values as $key => $value ) {
426
+ $array[ $key ] = mb_strlen( wpt_normalize( $value ), $encoding );
427
  }
428
 
429
  return $array;
430
  }
431
 
 
432
  /**
433
+ * Parse custom shortcodes
434
  *
435
+ * @param string $sentence Tweet template.
436
  * @param integer $post_ID Post ID.
437
  *
438
  * @return string $sentence with any custom shortcodes replaced with their appropriate content.
439
  */
440
  function wpt_custom_shortcodes( $sentence, $post_ID ) {
441
  $pattern = '/([([\[\]?)([A-Za-z0-9-_])*(\]\]]?)+/';
442
+ $params = array(
443
+ 0 => '[[',
444
+ 1 => ']]',
445
+ );
446
  preg_match_all( $pattern, $sentence, $matches );
447
  if ( $matches && is_array( $matches[0] ) ) {
448
  foreach ( $matches[0] as $value ) {
449
  $shortcode = "$value";
450
+ $field = str_replace( $params, '', $shortcode );
451
  $custom = apply_filters( 'wpt_custom_shortcode', strip_tags( get_post_meta( $post_ID, $field, true ) ), $post_ID, $field );
452
  $sentence = str_replace( $shortcode, $custom, $sentence );
453
  }
454
  }
455
+
456
  return $sentence;
457
  }
458
 
459
  /**
460
+ * Parse user meta shortcodes
461
  *
462
+ * @param string $sentence Tweet template.
463
+ * @param integer $auth_id Post Author ID.
464
  *
465
  * @return string $sentence with any custom shortcodes replaced with their appropriate content.
466
  */
467
+ function wpt_user_meta_shortcodes( $sentence, $auth_id ) {
468
  $pattern = '/([({\{\}?)([A-Za-z0-9-_])*(\}\}}?)+/';
469
+ $params = array(
470
+ 0 => '{{',
471
+ 1 => '}}',
472
+ );
473
  preg_match_all( $pattern, $sentence, $matches );
474
  if ( $matches && is_array( $matches[0] ) ) {
475
  foreach ( $matches[0] as $value ) {
476
  $shortcode = "$value";
477
+ $field = str_replace( $params, '', $shortcode );
478
+ $custom = apply_filters( 'wpt_user_meta_shortcode', strip_tags( get_user_meta( $auth_id, $field, true ) ), $auth_id, $field );
479
  $sentence = str_replace( $shortcode, $custom, $sentence );
480
  }
481
  }
482
+
483
  return $sentence;
484
+ }
wpt-widget.php CHANGED
@@ -1,24 +1,147 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
- } // Exit if accessed directly
 
 
 
5
 
6
  /**
7
- * wpt Latest Tweets widget class.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  */
 
 
 
 
 
 
 
 
 
 
9
 
10
- function wpt_get_user( $twitter_ID = false ) {
11
- if ( ! $twitter_ID ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  return;
13
  }
14
- $options = array( 'screen_name' => $twitter_ID );
15
  $key = get_option( 'app_consumer_key' );
16
  $secret = get_option( 'app_consumer_secret' );
17
  $token = get_option( 'oauth_token' );
18
  $token_secret = get_option( 'oauth_token_secret' );
19
  if ( $key && $secret && $token && $token_secret ) {
20
- $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
21
- $result = $connection->get( "https://api.twitter.com/1.1/users/show.json?screen_name=$twitter_ID&include_ext_alt_text=true", $options );
22
 
23
  return json_decode( $result );
24
  } else {
@@ -27,71 +150,86 @@ function wpt_get_user( $twitter_ID = false ) {
27
  }
28
 
29
  add_shortcode( 'get_tweets', 'wpt_get_twitter_feed' );
 
 
 
 
 
 
 
 
30
  function wpt_get_twitter_feed( $atts, $content ) {
31
- extract( shortcode_atts( array(
32
- 'id' => false,
33
- 'num' => 10,
34
- 'duration' => 1800,
35
- 'replies' => 0,
36
- 'rts' => 1,
37
- 'links' => 1,
38
- 'mentions' => 1,
39
- 'hashtags' => 0,
40
- 'intents' => 1,
41
- 'source' => 0,
42
  'show_images' => 1,
43
- 'hide_header' => 0
44
  ), $atts, 'get_tweets' ) );
45
  $instance = array(
46
- 'twitter_id' => $id,
47
- 'twitter_num' => $num,
48
- 'twitter_duration' => $duration,
49
- 'twitter_hide_replies' => $replies,
50
- 'twitter_include_rts' => $rts,
51
- 'link_links' => $links,
52
- 'link_mentions' => $mentions,
53
- 'link_hashtags' => $hashtags,
54
- 'intents' => $intents,
55
- 'source' => $source,
56
- 'show_images' => $show_images,
57
- 'hide_header' => $hide_header
58
  );
59
 
60
  return wpt_twitter_feed( $instance );
61
  }
62
 
 
 
 
 
 
 
 
63
  function wpt_twitter_feed( $instance ) {
64
  $header = '';
65
  if ( ! isset( $instance['search'] ) ) {
66
- $twitter_ID = ( isset( $instance['twitter_id'] ) && $instance['twitter_id'] != '' ) ? $instance['twitter_id'] : get_option( 'wtt_twitter_username' );
67
- $user = wpt_get_user( $twitter_ID );
68
  if ( empty( $user ) ) {
69
  return __( 'Error: You are not connected to Twitter.', 'wp-to-twitter' );
70
  }
71
  if ( isset( $user->errors ) && $user->errors[0]->message ) {
72
- return __( "Error: ", 'wp-to-twitter' ) . $user->errors[0]->message;
73
  }
74
  $avatar = $user->profile_image_url_https;
75
  $name = $user->name;
76
  $verified = sanitize_title( $user->verified );
77
  $img_alignment = ( is_rtl() ) ? 'wpt-right' : 'wpt-left';
78
  $follow_alignment = ( is_rtl() ) ? 'wpt-left' : 'wpt-right';
79
- $follow_url = esc_url( 'https://twitter.com/' . $twitter_ID );
80
- $follow_button = apply_filters( 'wpt_follow_button', "<a href='$follow_url' class='twitter-follow-button $follow_alignment' data-width='30px' data-show-screen-name='false' data-size='large' data-show-count='false' data-lang='en'>Follow @" . esc_html( $twitter_ID ) . "</a>" );
81
- $header .= '<div class="wpt-header">';
82
- $header .= "<div class='wpt-follow-button'>$follow_button</div>
83
  <p>
84
  <img src='$avatar' alt='' class='wpt-twitter-avatar $img_alignment $verified' />
85
  <span class='wpt-twitter-name'>$name</span><br />
86
- <span class='wpt-twitter-id'><a href='$follow_url'>@" . esc_html( $twitter_ID ) . "</a></span>
87
- </p>";
88
- $header .= '</div>';
89
  } else {
90
- $twitter_ID = false;
91
  }
92
-
93
- $hide_header = ( isset( $instance['hide_header'] ) && $instance['hide_header'] == 1 ) ? true : false;
94
-
95
  if ( ! isset( $instance['search'] ) ) {
96
  $options['exclude_replies'] = ( isset( $instance['twitter_hide_replies'] ) ) ? $instance['twitter_hide_replies'] : false;
97
  $options['include_rts'] = $instance['twitter_include_rts'];
@@ -100,39 +238,52 @@ function wpt_twitter_feed( $instance ) {
100
  $options['geocode'] = $instance['geocode'];
101
  $options['result_type'] = $instance['result_type'];
102
  }
103
-
104
  if ( $hide_header ) {
105
- $header = '';
106
  }
107
-
108
- $return = $header . '<ul>' . "\n";
109
-
110
  $opts['links'] = $instance['link_links'];
111
  $opts['mentions'] = $instance['link_mentions'];
112
  $opts['hashtags'] = $instance['link_hashtags'];
113
  $opts['show_images'] = isset( $instance['show_images'] ) ? $instance['show_images'] : false;
114
- $rawtweets = WPT_getTweets( $instance['twitter_num'], $twitter_ID, $options );
115
 
116
  if ( isset( $rawtweets['error'] ) ) {
117
- $return .= "<li>" . $rawtweets['error'] . "</li>";
118
  } else {
119
- /** Build the tweets array */
120
  $tweets = array();
121
  foreach ( $rawtweets as $tweet ) {
122
 
123
  if ( is_object( $tweet ) ) {
124
  $tweet = json_decode( json_encode( $tweet ), true );
125
  }
 
 
 
 
 
 
 
 
 
 
 
126
  if ( $instance['source'] ) {
127
- $source = $tweet['source'];
128
- $timetweet = sprintf( __( '<a href="%3$s">about %1$s ago</a> via %2$s', 'wp-to-twitter' ), human_time_diff( strtotime( $tweet['created_at'] ) ), $source, "http://twitter.com/" . $twitter_ID . "/status/$tweet[id_str]" );
 
129
  } else {
130
- $timetweet = sprintf( __( '<a href="%2$s">about %1$s ago</a>', 'wp-to-twitter' ), human_time_diff( strtotime( $tweet['created_at'] ) ), "http://twitter.com/$twitter_ID/status/$tweet[id_str]" );
 
131
  }
132
  $tweet_classes = wpt_generate_classes( $tweet );
133
 
134
  $intents = ( $instance['intents'] ) ? "<div class='wpt-intents-border'></div><div class='wpt-intents'><a class='wpt-reply' href='https://twitter.com/intent/tweet?in_reply_to=$tweet[id_str]'><span></span><span class='intent-text reply-text'>Reply</span></a> <a class='wpt-retweet' href='https://twitter.com/intent/retweet?tweet_id=$tweet[id_str]'><span></span><span class='intent-text retweet-text'>Retweet</span></a> <a class='wpt-favorite' href='https://twitter.com/intent/favorite?tweet_id=$tweet[id_str]'><span></span><span class='intent-text favorite-text'>Favorite</span></a></div>" : '';
135
- /** Add tweet to array */
136
  $before_tweet = apply_filters( 'wpt_before_tweet', '', $tweet );
137
  $after_tweet = apply_filters( 'wpt_after_tweet', '', $tweet );
138
  $tweets[] = '<li class="' . $tweet_classes . '">' . $before_tweet . wpt_tweet_linkify( $tweet['text'], $opts, $tweet ) . "<br /><span class='wpt-tweet-time'>$timetweet</span> $intents " . $after_tweet . "</li>\n";
@@ -147,486 +298,3 @@ function wpt_twitter_feed( $instance ) {
147
 
148
  return $return;
149
  }
150
-
151
-
152
- class WPT_Latest_Tweets_Widget extends WP_Widget {
153
-
154
- /**
155
- * Holds widget settings defaults, populated in constructor.
156
- *
157
- * @var array
158
- */
159
- protected $defaults;
160
-
161
- /**
162
- * Constructor. Set the default widget options and create widget.
163
- *
164
- * @since 0.1.8
165
- */
166
- function __construct() {
167
-
168
- $this->defaults = array(
169
- 'title' => '',
170
- 'twitter_id' => '',
171
- 'twitter_num' => '',
172
- 'twitter_duration' => '',
173
- 'twitter_hide_replies' => 0,
174
- 'twitter_include_rts' => 0,
175
- 'link_links' => '',
176
- 'link_mentions' => '',
177
- 'link_hashtags' => '',
178
- 'intents' => '',
179
- 'source' => '',
180
- 'show_images' => '',
181
- 'hide_header' => 0
182
- );
183
-
184
- $widget_ops = array(
185
- 'classname' => 'wpt-latest-tweets',
186
- 'description' => __( 'Display a list of your latest tweets.', 'wp-to-twitter' ),
187
- 'customize_selective_refresh' => true
188
- );
189
-
190
- $control_ops = array(
191
- 'id_base' => 'wpt-latest-tweets',
192
- 'width' => 200,
193
- 'height' => 250,
194
- );
195
- parent::__construct( 'wpt-latest-tweets', __( 'WP to Twitter - Latest Tweets', 'wp-to-twitter' ), $widget_ops, $control_ops );
196
- }
197
-
198
- /**
199
- * Echo the widget content.
200
- *
201
- * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
202
- * @param array $instance The settings for the particular instance of the widget
203
- */
204
-
205
- function widget( $args, $instance ) {
206
- extract( $args );
207
- wp_enqueue_script( 'twitter-platform', "https://platform.twitter.com/widgets.js" );
208
- /** Merge with defaults */
209
- $instance = wp_parse_args( (array) $instance, $this->defaults );
210
-
211
- echo $before_widget;
212
- if ( $instance['title'] ) {
213
- echo $before_title . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $after_title;
214
- }
215
- echo wpt_twitter_feed( $instance );
216
- echo $after_widget;
217
- }
218
-
219
- /**
220
- * Update a particular instance.
221
- *
222
- * This function should check that $new_instance is set correctly.
223
- * The newly calculated value of $instance should be returned.
224
- * If "false" is returned, the instance won't be saved/updated.
225
- *
226
- * @since 0.1
227
- *
228
- * @param array $new_instance New settings for this instance as input by the user via form()
229
- * @param array $old_instance Old settings for this instance
230
- *
231
- * @return array Settings to save or bool false to cancel saving
232
- */
233
- function update( $new_instance, $old_instance ) {
234
- /** Force the cache to refresh */
235
- update_option( 'wpt_delete_cache', 'true' );
236
- $new_instance['title'] = strip_tags( $new_instance['title'] );
237
-
238
- return $new_instance;
239
- }
240
-
241
- /**
242
- * Echo the settings update form.
243
- *
244
- * @param array $instance Current settings
245
- *
246
- * @return string
247
- */
248
- function form( $instance ) {
249
-
250
- /** Merge with defaults */
251
- $instance = wp_parse_args( (array) $instance, $this->defaults );
252
- ?>
253
- <p>
254
- <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'wp-to-twitter' ); ?>:</label>
255
- <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
256
- name="<?php echo $this->get_field_name( 'title' ); ?>"
257
- value="<?php echo esc_attr( $instance['title'] ); ?>" class="widefat"/>
258
- </p>
259
-
260
- <p>
261
- <label
262
- for="<?php echo $this->get_field_id( 'twitter_id' ); ?>"><?php _e( 'Twitter Username', 'wp-to-twitter' ); ?>
263
- :</label>
264
- <input type="text" id="<?php echo $this->get_field_id( 'twitter_id' ); ?>"
265
- name="<?php echo $this->get_field_name( 'twitter_id' ); ?>"
266
- value="<?php echo esc_attr( $instance['twitter_id'] ); ?>" class="widefat"/>
267
- </p>
268
-
269
- <p>
270
- <input id="<?php echo $this->get_field_id( 'hide_header' ); ?>" type="checkbox"
271
- name="<?php echo $this->get_field_name( 'hide_header' ); ?>"
272
- value="1" <?php checked( $instance['hide_header'], 1 ); ?>/>
273
- <label
274
- for="<?php echo $this->get_field_id( 'hide_header' ); ?>"><?php _e( 'Hide Widget Header', 'wp-to-twitter' ); ?></label>
275
- </p>
276
-
277
- <p>
278
- <label
279
- for="<?php echo $this->get_field_id( 'twitter_num' ); ?>"><?php _e( 'Number of Tweets to Show', 'wp-to-twitter' ); ?>
280
- :</label>
281
- <input type="text" id="<?php echo $this->get_field_id( 'twitter_num' ); ?>"
282
- name="<?php echo $this->get_field_name( 'twitter_num' ); ?>"
283
- value="<?php echo esc_attr( $instance['twitter_num'] ); ?>" size="3"/>
284
- </p>
285
-
286
- <p>
287
- <input id="<?php echo $this->get_field_id( 'twitter_hide_replies' ); ?>" type="checkbox"
288
- name="<?php echo $this->get_field_name( 'twitter_hide_replies' ); ?>"
289
- value="1" <?php checked( $instance['twitter_hide_replies'], 1 ); ?>/>
290
- <label
291
- for="<?php echo $this->get_field_id( 'twitter_hide_replies' ); ?>"><?php _e( 'Hide @ Replies', 'wp-to-twitter' ); ?></label>
292
- </p>
293
-
294
- <p>
295
- <input id="<?php echo $this->get_field_id( 'twitter_include_rts' ); ?>" type="checkbox"
296
- name="<?php echo $this->get_field_name( 'twitter_include_rts' ); ?>"
297
- value="1" <?php checked( $instance['twitter_include_rts'], 1 ); ?>/>
298
- <label
299
- for="<?php echo $this->get_field_id( 'twitter_include_rts' ); ?>"><?php _e( 'Include Retweets', 'wp-to-twitter' ); ?></label>
300
- </p>
301
-
302
- <p>
303
- <input id="<?php echo $this->get_field_id( 'link_links' ); ?>" type="checkbox"
304
- name="<?php echo $this->get_field_name( 'link_links' ); ?>"
305
- value="1" <?php checked( $instance['link_links'], 1 ); ?>/>
306
- <label
307
- for="<?php echo $this->get_field_id( 'link_links' ); ?>"><?php _e( 'Parse links', 'wp-to-twitter' ); ?></label>
308
- </p>
309
-
310
- <p>
311
- <input id="<?php echo $this->get_field_id( 'link_mentions' ); ?>" type="checkbox"
312
- name="<?php echo $this->get_field_name( 'link_mentions' ); ?>"
313
- value="1" <?php checked( $instance['link_mentions'], 1 ); ?>/>
314
- <label
315
- for="<?php echo $this->get_field_id( 'link_mentions' ); ?>"><?php _e( 'Parse @mentions', 'wp-to-twitter' ); ?></label>
316
- </p>
317
-
318
- <p>
319
- <input id="<?php echo $this->get_field_id( 'show_images' ); ?>" type="checkbox"
320
- name="<?php echo $this->get_field_name( 'show_images' ); ?>"
321
- value="1" <?php checked( $instance['show_images'], 1 ); ?>/>
322
- <label
323
- for="<?php echo $this->get_field_id( 'show_images' ); ?>"><?php _e( 'Show Images', 'wp-to-twitter' ); ?></label>
324
- </p>
325
-
326
- <p>
327
- <input id="<?php echo $this->get_field_id( 'link_hashtags' ); ?>" type="checkbox"
328
- name="<?php echo $this->get_field_name( 'link_hashtags' ); ?>"
329
- value="1" <?php checked( $instance['link_hashtags'], 1 ); ?>/>
330
- <label
331
- for="<?php echo $this->get_field_id( 'link_hashtags' ); ?>"><?php _e( 'Parse #hashtags', 'wp-to-twitter' ); ?></label>
332
- </p>
333
-
334
- <p>
335
- <input id="<?php echo $this->get_field_id( 'intents' ); ?>" type="checkbox"
336
- name="<?php echo $this->get_field_name( 'intents' ); ?>"
337
- value="1" <?php checked( $instance['intents'], 1 ); ?>/>
338
- <label
339
- for="<?php echo $this->get_field_id( 'intents' ); ?>"><?php _e( 'Include Reply/Retweet/Favorite Links', 'wp-to-twitter' ); ?></label>
340
- </p>
341
-
342
- <p>
343
- <input id="<?php echo $this->get_field_id( 'source' ); ?>" type="checkbox"
344
- name="<?php echo $this->get_field_name( 'source' ); ?>"
345
- value="1" <?php checked( $instance['source'], 1 ); ?>/>
346
- <label
347
- for="<?php echo $this->get_field_id( 'source' ); ?>"><?php _e( 'Include Tweet source', 'wp-to-twitter' ); ?></label>
348
- </p>
349
- <p>
350
- <input id="<?php echo $this->get_field_id( 'cache' ); ?>" type="checkbox" name="<?php echo $this->get_field_name( 'cache' ); ?>" value="1" />
351
- <label for="<?php echo $this->get_field_id( 'cache' ); ?>"><?php _e( 'Clear cache', 'wp-to-twitter' ); ?></label>
352
- </p>
353
- <?php
354
- }
355
- }
356
-
357
- add_action( 'widgets_init', 'wpt_register_widgets' );
358
- function wpt_register_widgets() {
359
- register_widget( 'WPT_Latest_Tweets_Widget' );
360
- register_widget( 'WPT_Search_Tweets_Widget' );
361
- }
362
-
363
- class WPT_Search_Tweets_Widget extends WP_Widget {
364
-
365
- /**
366
- * Holds widget settings defaults, populated in constructor.
367
- *
368
- * @var array
369
- */
370
- protected $defaults;
371
-
372
- /**
373
- * Constructor. Set the default widget options and create widget.
374
- *
375
- * @since 0.1.8
376
- */
377
- function __construct() {
378
-
379
- $this->defaults = array(
380
- 'title' => '',
381
- 'twitter_num' => '',
382
- 'search' => '',
383
- 'result_type' => 'recent', // mixed, recent, popular
384
- 'geocode' => '', // 37.777,-127.98,2km
385
- 'link_links' => '',
386
- 'link_mentions' => '',
387
- 'link_hashtags' => '',
388
- 'intents' => '',
389
- 'source' => ''
390
- );
391
-
392
- $widget_ops = array(
393
- 'classname' => 'wpt-search-tweets',
394
- 'description' => __( 'Display a list of tweets returned by a search.', 'wp-to-twitter' ),
395
- 'customize_selective_refresh' => true
396
- );
397
-
398
- $control_ops = array(
399
- 'id_base' => 'wpt-search-tweets',
400
- 'width' => 200,
401
- 'height' => 250,
402
- );
403
- parent::__construct( 'wpt-search-tweets', __( 'WP to Twitter - Searched Tweets', 'wp-to-twitter' ), $widget_ops, $control_ops );
404
- }
405
-
406
- /**
407
- * Echo the widget content.
408
- *
409
- * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
410
- * @param array $instance The settings for the particular instance of the widget
411
- */
412
-
413
- function widget( $args, $instance ) {
414
- extract( $args );
415
- wp_enqueue_script( 'twitter-platform', "https://platform.twitter.com/widgets.js" );
416
- /** Merge with defaults */
417
- $instance = wp_parse_args( (array) $instance, $this->defaults );
418
- echo $before_widget;
419
- if ( $instance['title'] ) {
420
- echo $before_title . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $after_title;
421
- }
422
- echo wpt_twitter_feed( $instance );
423
- echo $after_widget;
424
- }
425
-
426
- /**
427
- * Update a particular instance.
428
- *
429
- * This function should check that $new_instance is set correctly.
430
- * The newly calculated value of $instance should be returned.
431
- * If "false" is returned, the instance won't be saved/updated.
432
- *
433
- * @since 0.1
434
- *
435
- * @param array $new_instance New settings for this instance as input by the user via form()
436
- * @param array $old_instance Old settings for this instance
437
- *
438
- * @return array Settings to save or bool false to cancel saving
439
- */
440
- function update( $new_instance, $old_instance ) {
441
- /** Force the cache to refresh */
442
- update_option( 'wpt_delete_cache', 'true' );
443
- $new_instance['title'] = strip_tags( $new_instance['title'] );
444
-
445
- return $new_instance;
446
- }
447
-
448
- /**
449
- * Echo the settings update form.
450
- *
451
- * @param array $instance Current settings
452
- */
453
- function form( $instance ) {
454
-
455
- /** Merge with defaults */
456
- $instance = wp_parse_args( (array) $instance, $this->defaults );
457
-
458
- ?>
459
- <p>
460
- <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'wp-to-twitter' ); ?>:</label>
461
- <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
462
- name="<?php echo $this->get_field_name( 'title' ); ?>"
463
- value="<?php echo esc_attr( $instance['title'] ); ?>" class="widefat"/>
464
- </p>
465
-
466
- <p>
467
- <label for="<?php echo $this->get_field_id( 'search' ); ?>"><?php _e( 'Search String', 'wp-to-twitter' ); ?>
468
- :</label>
469
- <input type="text" id="<?php echo $this->get_field_id( 'search' ); ?>"
470
- name="<?php echo $this->get_field_name( 'search' ); ?>"
471
- value="<?php echo esc_attr( $instance['search'] ); ?>" class="widefat"/>
472
- </p>
473
-
474
- <p>
475
- <label
476
- for="<?php echo $this->get_field_id( 'twitter_num' ); ?>"><?php _e( 'Number of Tweets to Show', 'wp-to-twitter' ); ?>
477
- :</label>
478
- <input type="text" id="<?php echo $this->get_field_id( 'twitter_num' ); ?>"
479
- name="<?php echo $this->get_field_name( 'twitter_num' ); ?>"
480
- value="<?php echo esc_attr( $instance['twitter_num'] ); ?>" size="3"/>
481
- </p>
482
-
483
- <p>
484
- <label
485
- for="<?php echo $this->get_field_id( 'result_type' ); ?>"><?php _e( 'Type of Results', 'wp-to-twitter' ); ?></label>
486
- <select name="<?php echo $this->get_field_name( 'result_type' ); ?>"
487
- id="<?php echo $this->get_field_id( 'result_type' ); ?>">
488
- <option
489
- value='recent'<?php echo ( $instance['result_type'] == 'recent' ) ? ' selected="selected"' : ''; ?>><?php _e( 'Recent Tweets', 'wp-to-twitter' ); ?></option>
490
- <option
491
- value='popular'<?php echo ( $instance['result_type'] == 'popular' ) ? ' selected="selected"' : ''; ?>><?php _e( 'Popular Tweets', 'wp-to-twitter' ); ?></option>
492
- <option
493
- value='mixed'<?php echo ( $instance['result_type'] == 'mixed' ) ? ' selected="selected"' : ''; ?>><?php _e( 'Mixed', 'wp-to-twitter' ); ?></option>
494
- </select>
495
- </p>
496
-
497
- <p>
498
- <label
499
- for="<?php echo $this->get_field_id( 'geocode' ); ?>"><?php _e( 'Geocode (Latitude,Longitude,Radius)', 'wp-to-twitter' ); ?>
500
- :</label>
501
- <input type="text" id="<?php echo $this->get_field_id( 'geocode' ); ?>"
502
- class="widefat"
503
- name="<?php echo $this->get_field_name( 'geocode' ); ?>"
504
- value="<?php echo esc_attr( $instance['geocode'] ); ?>" size="32"
505
- placeholder="37.781157,-122.398720,2km"/>
506
- </p>
507
-
508
- <p>
509
- <input id="<?php echo $this->get_field_id( 'link_links' ); ?>" type="checkbox"
510
- name="<?php echo $this->get_field_name( 'link_links' ); ?>"
511
- value="1" <?php checked( $instance['link_links'] ); ?>/>
512
- <label
513
- for="<?php echo $this->get_field_id( 'link_links' ); ?>"><?php _e( 'Parse links', 'wp-to-twitter' ); ?></label>
514
- </p>
515
-
516
- <p>
517
- <input id="<?php echo $this->get_field_id( 'link_mentions' ); ?>" type="checkbox"
518
- name="<?php echo $this->get_field_name( 'link_mentions' ); ?>"
519
- value="1" <?php checked( $instance['link_mentions'] ); ?>/>
520
- <label
521
- for="<?php echo $this->get_field_id( 'link_mentions' ); ?>"><?php _e( 'Parse @mentions', 'wp-to-twitter' ); ?></label>
522
- </p>
523
-
524
- <p>
525
- <input id="<?php echo $this->get_field_id( 'link_hashtags' ); ?>" type="checkbox"
526
- name="<?php echo $this->get_field_name( 'link_hashtags' ); ?>"
527
- value="1" <?php checked( $instance['link_hashtags'] ); ?>/>
528
- <label
529
- for="<?php echo $this->get_field_id( 'link_hashtags' ); ?>"><?php _e( 'Parse #hashtags', 'wp-to-twitter' ); ?></label>
530
- </p>
531
-
532
- <p>
533
- <input id="<?php echo $this->get_field_id( 'intents' ); ?>" type="checkbox"
534
- name="<?php echo $this->get_field_name( 'intents' ); ?>"
535
- value="1" <?php checked( $instance['intents'] ); ?>/>
536
- <label
537
- for="<?php echo $this->get_field_id( 'intents' ); ?>"><?php _e( 'Include Reply/Retweet/Favorite Links', 'wp-to-twitter' ); ?></label>
538
- </p>
539
-
540
- <p>
541
- <input id="<?php echo $this->get_field_id( 'source' ); ?>" type="checkbox"
542
- name="<?php echo $this->get_field_name( 'source' ); ?>"
543
- value="1" <?php checked( $instance['source'] ); ?>/>
544
- <label
545
- for="<?php echo $this->get_field_id( 'source' ); ?>"><?php _e( 'Include Tweet source', 'wp-to-twitter' ); ?></label>
546
- </p>
547
- <?php
548
- }
549
- }
550
-
551
- /**
552
- * Adds links to the contents of a tweet.
553
- * Forked from genesis_tweet_linkify, removed target = _blank
554
- *
555
- * Takes the content of a tweet, detects @replies, #hashtags, and
556
- * http:// links, and links them appropriately.
557
- *
558
- * @since 0.1
559
- *
560
- * @link http://www.snipe.net/2009/09/php-twitter-clickable-links/
561
- *
562
- * @param string $text A string representing the content of a tweet
563
- *
564
- * @return string Linkified tweet content
565
- */
566
- function wpt_tweet_linkify( $text, $opts, $tweet ) {
567
- if ( $opts['show_images'] == true ) {
568
- $media = isset( $tweet['entities']['media'] ) ? $tweet['entities']['media'] : false;
569
- if ( $media ) {
570
- $media_urls = array();
571
- if ( !empty( $media ) ) {
572
- foreach ( $media as $key => $image ) {
573
- $media_urls[] = $image['url'];
574
- // alt attributes are not available on Twitter.
575
- $alt = isset( $tweet['extended_entities']['media'][$key]['ext_alt_text'] ) ? $tweet['extended_entities']['media'][$key]['ext_alt_text'] : '';
576
- $text .= "<img src='$image[media_url_https]' alt='$alt' class='wpt-twitter-image' />";
577
- }
578
- }
579
- if ( !empty( $media_urls ) ) {
580
- foreach ( $media_urls as $media_url ) {
581
- $text = str_replace( "$media_url", '', $text );
582
- }
583
- }
584
- }
585
- }
586
- $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#", '\\1<a href="\\2" rel="nofollow">\\2</a>', $text ) : $text;
587
- $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#", '\\1<a href="http://\\2" rel="nofollow">\\2</a>', $text ) : $text;
588
- $text = ( $opts['mentions'] == true ) ? preg_replace( '/@(\w+)/', '<a href="https://twitter.com/\\1" rel="nofollow">@\\1</a>', $text ) : $text;
589
- $text = ( $opts['hashtags'] == true ) ? preg_replace( '/#(\w+)/', '<a href="https://twitter.com/search?q=%23\\1" rel="nofollow">#\\1</a>', $text ) : $text;
590
- $urls = $tweet['entities']['urls'];
591
- if ( is_array( $urls ) ) {
592
- foreach ( $urls as $url ) {
593
-
594
- $text = str_replace( ">$url[url]<", ">$url[display_url]<", $text );
595
- }
596
- }
597
-
598
- return $text;
599
- }
600
-
601
- /* implement getTweets */
602
- function WPT_getTweets( $count = 20, $username = false, $options = false ) {
603
-
604
- $config['key'] = get_option( 'app_consumer_key' );
605
- $config['secret'] = get_option( 'app_consumer_secret' );
606
- $config['token'] = get_option( 'oauth_token' );
607
- $config['token_secret'] = get_option( 'oauth_token_secret' );
608
- $config['screenname'] = get_option( 'wtt_twitter_username' );
609
- $config['cache_expire'] = intval( apply_filters( 'wpt_cache_expire', 1800 ) );
610
- if ( $config['cache_expire'] < 1 ) {
611
- $config['cache_expire'] = 1800;
612
- }
613
- $config['directory'] = plugin_dir_path( __FILE__ );
614
-
615
- $obj = new WPT_TwitterFeed( $config );
616
- $res = $obj->getTweets( $count, $username, $options );
617
- update_option( 'wpt_tdf_last_error', $obj->st_last_error );
618
-
619
- return $res;
620
-
621
- }
622
-
623
- function wpt_generate_classes( $tweet ) {
624
- // take Tweet array and parse selected options into classes.
625
- $classes[] = ( $tweet['favorited'] ) ? 'favorited' : '';
626
- $clasees[] = ( $tweet['retweeted'] ) ? 'retweeted' : '';
627
- $classes[] = ( isset( $tweet['possibly_sensitive'] ) && $tweet['possibly_sensitive'] ) ? 'sensitive' : '';
628
- $classes[] = 'lang-' . $tweet['lang'];
629
- $class = trim( implode( ' ', $classes ) );
630
-
631
- return $class;
632
- }
1
  <?php
2
+ /**
3
+ * WP to Twitter Widgets
4
+ *
5
+ * @category Widgets
6
+ * @package WP to Twitter
7
+ * @author Joe Dolson
8
+ * @license GPLv2 or later
9
+ * @link https://www.joedolson.com/wp-to-twitter/
10
+ */
11
+
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
+
16
+ require_once( dirname( __FILE__ ) . '/classes/class-wpt-latest-tweets-widget.php' );
17
+ require_once( dirname( __FILE__ ) . '/classes/class-wpt-search-tweets-widget.php' );
18
 
19
  /**
20
+ * Adds links to the contents of a tweet.
21
+ * Forked from genesis_tweet_linkify, removed target = _blank
22
+ *
23
+ * Takes the content of a tweet, detects @replies, #hashtags, and
24
+ * http:// links, and links them appropriately.
25
+ *
26
+ * @since 0.1
27
+ *
28
+ * @link http://www.snipe.net/2009/09/php-twitter-clickable-links/
29
+ *
30
+ * @param string $text A string representing the content of a tweet.
31
+ * @param array $opts Array of options.
32
+ * @param array $tweet Array of Tweet information.
33
+ *
34
+ * @return string Linkified tweet content
35
  */
36
+ function wpt_tweet_linkify( $text, $opts, $tweet ) {
37
+ if ( true == $opts['show_images'] ) {
38
+ $media = isset( $tweet['entities']['media'] ) ? $tweet['entities']['media'] : false;
39
+ if ( $media ) {
40
+ $media_urls = array();
41
+ if ( ! empty( $media ) ) {
42
+ foreach ( $media as $key => $image ) {
43
+ $media_urls[] = $image['url'];
44
+ $alt = isset( $tweet['extended_entities']['media'][ $key ]['ext_alt_text'] ) ? $tweet['extended_entities']['media'][ $key ]['ext_alt_text'] : '';
45
+ $text .= "<img src='$image[media_url_https]' alt='$alt' class='wpt-twitter-image' />";
46
 
47
+ }
48
+ }
49
+ if ( ! empty( $media_urls ) ) {
50
+ foreach ( $media_urls as $media_url ) {
51
+ $text = str_replace( $media_url, '', $text );
52
+ }
53
+ }
54
+ }
55
+ }
56
+ $restore = false;
57
+ if ( false !== strpos( $text, '…' ) ) {
58
+ $text = str_replace( '…', ' ______ ', $text );
59
+ $restore = true;
60
+ }
61
+ $text = ( true == $opts['links'] ) ? preg_replace( '#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#', '\\1<a href="\\2" rel="nofollow">\\2</a>', $text ) : $text;
62
+ $text = ( true == $opts['links'] ) ? preg_replace( '#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#', '\\1<a href="http://\\2" rel="nofollow">\\2</a>', $text ) : $text;
63
+ $text = ( true == $opts['mentions'] ) ? preg_replace( '/@(\w+)/', '<a href="https://twitter.com/\\1" rel="nofollow">@\\1</a>', $text ) : $text;
64
+ $text = ( true == $opts['hashtags'] ) ? preg_replace( '/#(\w+)/', '<a href="https://twitter.com/search?q=%23\\1" rel="nofollow">#\\1</a>', $text ) : $text;
65
+ $urls = $tweet['entities']['urls'];
66
+ if ( is_array( $urls ) ) {
67
+ foreach ( $urls as $url ) {
68
+ $text = str_replace( ">$url[url]<", ">$url[display_url]<", $text );
69
+ }
70
+ }
71
+ if ( true == $restore ) {
72
+ $text = str_replace( ' ______ ', '…', $text );
73
+ }
74
+
75
+ return $text;
76
+ }
77
+
78
+ /**
79
+ * Implement get_tweets
80
+ *
81
+ * @param int $count How many Tweets.
82
+ * @param string $username Username passed.
83
+ * @param array $options Widget options.
84
+ *
85
+ * @return Tweets.
86
+ */
87
+ function wpt_get_tweets( $count = 20, $username = false, $options = false ) {
88
+
89
+ $config['key'] = get_option( 'app_consumer_key' );
90
+ $config['secret'] = get_option( 'app_consumer_secret' );
91
+ $config['token'] = get_option( 'oauth_token' );
92
+ $config['token_secret'] = get_option( 'oauth_token_secret' );
93
+ $config['screenname'] = get_option( 'wtt_twitter_username' );
94
+ $config['cache_expire'] = intval( apply_filters( 'wpt_cache_expire', 1800 ) );
95
+ if ( $config['cache_expire'] < 1 ) {
96
+ $config['cache_expire'] = 1800;
97
+ }
98
+ $config['directory'] = plugin_dir_path( __FILE__ );
99
+
100
+ $obj = new WPT_TwitterFeed( $config );
101
+ $res = $obj->get_tweets( $count, $username, $options );
102
+ update_option( 'wpt_tdf_last_error', $obj->st_last_error );
103
+
104
+ return $res;
105
+
106
+ }
107
+
108
+ /**
109
+ * Generate relevant classes for a Tweet.
110
+ *
111
+ * @param array $tweet Tweet info.
112
+ *
113
+ * @return array classes.
114
+ */
115
+ function wpt_generate_classes( $tweet ) {
116
+ // take Tweet array and parse selected options into classes.
117
+ $classes[] = ( $tweet['favorited'] ) ? 'favorited' : '';
118
+ $clasees[] = ( $tweet['retweeted'] ) ? 'retweeted' : '';
119
+ $classes[] = ( isset( $tweet['possibly_sensitive'] ) && $tweet['possibly_sensitive'] ) ? 'sensitive' : '';
120
+ $classes[] = 'lang-' . $tweet['lang'];
121
+ $class = trim( implode( ' ', $classes ) );
122
+
123
+ return $class;
124
+ }
125
+
126
+ /**
127
+ * Get information about user.
128
+ *
129
+ * @param string $twitter_id Twitter screen name.
130
+ *
131
+ * @return array
132
+ */
133
+ function wpt_get_user( $twitter_id = false ) {
134
+ if ( ! $twitter_id ) {
135
  return;
136
  }
137
+ $options = array( 'screen_name' => $twitter_id );
138
  $key = get_option( 'app_consumer_key' );
139
  $secret = get_option( 'app_consumer_secret' );
140
  $token = get_option( 'oauth_token' );
141
  $token_secret = get_option( 'oauth_token_secret' );
142
  if ( $key && $secret && $token && $token_secret ) {
143
+ $connection = new Wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
144
+ $result = $connection->get( "https://api.twitter.com/1.1/users/show.json?screen_name=$twitter_id&include_ext_alt_text=true", $options );
145
 
146
  return json_decode( $result );
147
  } else {
150
  }
151
 
152
  add_shortcode( 'get_tweets', 'wpt_get_twitter_feed' );
153
+ /**
154
+ * Get a Twitter Feed.
155
+ *
156
+ * @param array $atts Display attributes.
157
+ * @param string $content Fallback content.
158
+ *
159
+ * @return Twitter feed.
160
+ */
161
  function wpt_get_twitter_feed( $atts, $content ) {
162
+ $atts = ( shortcode_atts( array(
163
+ 'id' => false,
164
+ 'num' => 10,
165
+ 'duration' => 1800,
166
+ 'replies' => 0,
167
+ 'rts' => 1,
168
+ 'links' => 1,
169
+ 'mentions' => 1,
170
+ 'hashtags' => 0,
171
+ 'intents' => 1,
172
+ 'source' => 0,
173
  'show_images' => 1,
174
+ 'hide_header' => 0,
175
  ), $atts, 'get_tweets' ) );
176
  $instance = array(
177
+ 'twitter_id' => $atts['id'],
178
+ 'twitter_num' => $atts['num'],
179
+ 'twitter_duration' => $atts['duration'],
180
+ 'twitter_hide_replies' => $atts['replies'],
181
+ 'twitter_include_rts' => $atts['rts'],
182
+ 'link_links' => $atts['links'],
183
+ 'link_mentions' => $atts['mentions'],
184
+ 'link_hashtags' => $atts['hashtags'],
185
+ 'intents' => $atts['intents'],
186
+ 'source' => $atts['source'],
187
+ 'show_images' => $atts['show_images'],
188
+ 'hide_header' => $atts['hide_header'],
189
  );
190
 
191
  return wpt_twitter_feed( $instance );
192
  }
193
 
194
+ /**
195
+ * Get the twitter feed data.
196
+ *
197
+ * @param array $instance Config for this instance.
198
+ *
199
+ * @return string.
200
+ */
201
  function wpt_twitter_feed( $instance ) {
202
  $header = '';
203
  if ( ! isset( $instance['search'] ) ) {
204
+ $twitter_id = ( isset( $instance['twitter_id'] ) && '' != $instance['twitter_id'] ) ? $instance['twitter_id'] : get_option( 'wtt_twitter_username' );
205
+ $user = wpt_get_user( $twitter_id );
206
  if ( empty( $user ) ) {
207
  return __( 'Error: You are not connected to Twitter.', 'wp-to-twitter' );
208
  }
209
  if ( isset( $user->errors ) && $user->errors[0]->message ) {
210
+ return __( 'Error:', 'wp-to-twitter' ) . ' ' . $user->errors[0]->message;
211
  }
212
  $avatar = $user->profile_image_url_https;
213
  $name = $user->name;
214
  $verified = sanitize_title( $user->verified );
215
  $img_alignment = ( is_rtl() ) ? 'wpt-right' : 'wpt-left';
216
  $follow_alignment = ( is_rtl() ) ? 'wpt-left' : 'wpt-right';
217
+ $follow_url = esc_url( 'https://twitter.com/' . $twitter_id );
218
+ $follow_button = apply_filters( 'wpt_follow_button', "<a href='$follow_url' class='twitter-follow-button $follow_alignment' data-width='30px' data-show-screen-name='false' data-size='large' data-show-count='false' data-lang='en'>Follow @" . esc_html( $twitter_id ) . '</a>' );
219
+ $header .= '<div class="wpt-header">';
220
+ $header .= "<div class='wpt-follow-button'>$follow_button</div>
221
  <p>
222
  <img src='$avatar' alt='' class='wpt-twitter-avatar $img_alignment $verified' />
223
  <span class='wpt-twitter-name'>$name</span><br />
224
+ <span class='wpt-twitter-id'><a href='$follow_url'>@" . esc_html( $twitter_id ) . '</a></span>
225
+ </p>';
226
+ $header .= '</div>';
227
  } else {
228
+ $twitter_id = false;
229
  }
230
+
231
+ $hide_header = ( isset( $instance['hide_header'] ) && 1 == $instance['hide_header'] ) ? true : false;
232
+
233
  if ( ! isset( $instance['search'] ) ) {
234
  $options['exclude_replies'] = ( isset( $instance['twitter_hide_replies'] ) ) ? $instance['twitter_hide_replies'] : false;
235
  $options['include_rts'] = $instance['twitter_include_rts'];
238
  $options['geocode'] = $instance['geocode'];
239
  $options['result_type'] = $instance['result_type'];
240
  }
241
+
242
  if ( $hide_header ) {
243
+ $header = '';
244
  }
245
+
246
+ $return = $header . '<ul>' . "\n";
247
+
248
  $opts['links'] = $instance['link_links'];
249
  $opts['mentions'] = $instance['link_mentions'];
250
  $opts['hashtags'] = $instance['link_hashtags'];
251
  $opts['show_images'] = isset( $instance['show_images'] ) ? $instance['show_images'] : false;
252
+ $rawtweets = wpt_get_tweets( $instance['twitter_num'], $twitter_id, $options );
253
 
254
  if ( isset( $rawtweets['error'] ) ) {
255
+ $return .= '<li>' . $rawtweets['error'] . '</li>';
256
  } else {
257
+ // Build the tweets array.
258
  $tweets = array();
259
  foreach ( $rawtweets as $tweet ) {
260
 
261
  if ( is_object( $tweet ) ) {
262
  $tweet = json_decode( json_encode( $tweet ), true );
263
  }
264
+
265
+ if ( isset( $tweet['retweeted_status']['user']['id_str'] ) ) {
266
+ $posted_by = $tweet['retweeted_status']['user']['id_str'];
267
+ } elseif ( isset( $tweet['in_reply_to_screen_name'] ) ) {
268
+ $posted_by = $tweet['in_reply_to_screen_name'];
269
+ } elseif ( isset( $tweet['user']['id_str'] ) ) {
270
+ $posted_by = $tweet['user']['id_str'];
271
+ } else {
272
+ $posted_by = $twitter_id;
273
+ }
274
+
275
  if ( $instance['source'] ) {
276
+ $source = $tweet['source'];
277
+ // Translators: 1 - time string, 2 - name of Tweet app, 3 - Link to Tweet.
278
+ $timetweet = sprintf( __( '<a href="%3$s">about %1$s ago</a> via %2$s', 'wp-to-twitter' ), human_time_diff( strtotime( $tweet['created_at'] ) ), $source, 'http://twitter.com/' . $posted_by . "/status/$tweet[id_str]" );
279
  } else {
280
+ // Translators: 1 - time string; 2 - link to Tweet.
281
+ $timetweet = sprintf( __( '<a href="%2$s">about %1$s ago</a>', 'wp-to-twitter' ), human_time_diff( strtotime( $tweet['created_at'] ) ), "http://twitter.com/$posted_by/status/$tweet[id_str]" );
282
  }
283
  $tweet_classes = wpt_generate_classes( $tweet );
284
 
285
  $intents = ( $instance['intents'] ) ? "<div class='wpt-intents-border'></div><div class='wpt-intents'><a class='wpt-reply' href='https://twitter.com/intent/tweet?in_reply_to=$tweet[id_str]'><span></span><span class='intent-text reply-text'>Reply</span></a> <a class='wpt-retweet' href='https://twitter.com/intent/retweet?tweet_id=$tweet[id_str]'><span></span><span class='intent-text retweet-text'>Retweet</span></a> <a class='wpt-favorite' href='https://twitter.com/intent/favorite?tweet_id=$tweet[id_str]'><span></span><span class='intent-text favorite-text'>Favorite</span></a></div>" : '';
286
+ // Add tweet to array.
287
  $before_tweet = apply_filters( 'wpt_before_tweet', '', $tweet );
288
  $after_tweet = apply_filters( 'wpt_after_tweet', '', $tweet );
289
  $tweets[] = '<li class="' . $tweet_classes . '">' . $before_tweet . wpt_tweet_linkify( $tweet['text'], $opts, $tweet ) . "<br /><span class='wpt-tweet-time'>$timetweet</span> $intents " . $after_tweet . "</li>\n";
298
 
299
  return $return;
300
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
wpt_twitter_oauth.php DELETED
@@ -1,368 +0,0 @@
1
- <?php
2
- /*
3
- * Abraham Williams (abraham@abrah.am) http://abrah.am
4
- *
5
- * The first PHP Library to support WPOAuth for Twitter's REST API.
6
- *
7
- */
8
-
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- exit;
11
- } // Exit if accessed directly
12
-
13
- require_once( 'WP_OAuth.php' );
14
-
15
- if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
16
-
17
- /**
18
- * Twitter WPOAuth class
19
- */
20
- class wpt_TwitterOAuth {
21
- /* Contains the last HTTP status code returned */
22
- public $http_code;
23
- /* Contains the last API call. */
24
- public $url;
25
- /* Set up the API root URL. */
26
- public $host = "https://api.twitter.com/1.1/";
27
- /* Set timeout default. */
28
- public $format = 'json';
29
- /* Decode returned json data. */
30
- public $decode_json = false;
31
- /* Contains the last API call */
32
- private $last_api_call;
33
- /* containe the header */
34
- public $http_header;
35
- /* contains the body */
36
- public $body;
37
-
38
- /**
39
- * Set API URLS
40
- */
41
- function accessTokenURL() {
42
- return "https://api.twitter.com/oauth/access_token";
43
- }
44
-
45
- function authenticateURL() {
46
- return "https://api.twitter.com/oauth/authenticate";
47
- }
48
-
49
- function authorizeURL() {
50
- return "https://api.twitter.com/oauth/authorize";
51
- }
52
-
53
- function requestTokenURL() {
54
- return "https://api.twitter.com/oauth/request_token";
55
- }
56
-
57
- /**
58
- * Debug helpers
59
- */
60
- function lastStatusCode() {
61
- return $this->http_code;
62
- }
63
-
64
- function lastAPICall() {
65
- return $this->last_api_call;
66
- }
67
-
68
- /**
69
- * construct TwitterWPOAuth object
70
- */
71
- function __construct( $consumer_key, $consumer_secret, $WPOAuth_token = null, $WPOAuth_token_secret = null ) {
72
- $this->sha1_method = new WPOAuthSignatureMethod_HMAC_SHA1();
73
- $this->consumer = new WPOAuthConsumer( $consumer_key, $consumer_secret );
74
- if ( ! empty( $WPOAuth_token ) && ! empty( $WPOAuth_token_secret ) ) {
75
- $this->token = new WPOAuthConsumer( $WPOAuth_token, $WPOAuth_token_secret );
76
- } else {
77
- $this->token = null;
78
- }
79
- }
80
-
81
-
82
- /**
83
- * Get a request_token from Twitter
84
- *
85
- * @returns a key/value array containing WPOAuth_token and WPOAuth_token_secret
86
- */
87
- function getRequestToken() {
88
- $r = $this->WPOAuthRequest( $this->requestTokenURL() );
89
- $token = $this->WPOAuthParseResponse( $r );
90
- $this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
91
-
92
- return $token;
93
- }
94
-
95
- /**
96
- * Parse a URL-encoded WPOAuth response
97
- *
98
- * @return a key/value array
99
- */
100
- function WPOAuthParseResponse( $responseString ) {
101
- $r = array();
102
- foreach ( explode( '&', $responseString ) as $param ) {
103
- $pair = explode( '=', $param, 2 );
104
- if ( count( $pair ) != 2 ) {
105
- continue;
106
- }
107
- $r[ urldecode( $pair[0] ) ] = urldecode( $pair[1] );
108
- }
109
-
110
- return $r;
111
- }
112
-
113
- /**
114
- * Get the authorize URL
115
- *
116
- * @returns a string
117
- */
118
- function getAuthorizeURL( $token ) {
119
- if ( is_array( $token ) ) {
120
- $token = $token['WPOAuth_token'];
121
- }
122
-
123
- return $this->authorizeURL() . '?WPOAuth_token=' . $token;
124
- }
125
-
126
-
127
- /**
128
- * Get the authenticate URL
129
- *
130
- * @returns a string
131
- */
132
- function getAuthenticateURL( $token ) {
133
- if ( is_array( $token ) ) {
134
- $token = $token['WPOAuth_token'];
135
- }
136
-
137
- return $this->authenticateURL() . '?WPOAuth_token=' . $token;
138
- }
139
-
140
- /**
141
- * Exchange the request token and secret for an access token and
142
- * secret, to sign API calls.
143
- *
144
- * @returns array("WPOAuth_token" => the access token,
145
- * "WPOAuth_token_secret" => the access secret)
146
- */
147
- function getAccessToken( $token = null ) {
148
- $r = $this->WPOAuthRequest( $this->accessTokenURL() );
149
- $token = $this->WPOAuthParseResponse( $r );
150
- $this->token = new WPOAuthConsumer( $token['WPOAuth_token'], $token['WPOAuth_token_secret'] );
151
-
152
- return $token;
153
- }
154
-
155
- /**
156
- * Wrapper for POST requests
157
- */
158
- function post( $url, $parameters = array() ) {
159
- $response = $this->WPOAuthRequest( $url, $parameters, 'POST' );
160
- if ( $this->format === 'json' && $this->decode_json ) {
161
- return json_decode( $response );
162
- }
163
-
164
- return $response;
165
- }
166
-
167
- /**
168
- * Wrapper for MEDIA requests
169
- */
170
- function media( $url, $parameters = array() ) {
171
- $response = $this->WPOAuthRequest( $url, $parameters, 'MEDIA' );
172
- if ( $this->format === 'json' && $this->decode_json ) {
173
- return json_decode( $response );
174
- }
175
-
176
- return $response;
177
- }
178
-
179
- /**
180
- * Wrapper for GET requests
181
- */
182
- function get( $url, $parameters = array() ) {
183
- $response = $this->WPOAuthRequest( $url, $parameters, 'GET' );
184
- if ( $this->format === 'json' && $this->decode_json ) {
185
- return json_decode( $response );
186
- }
187
-
188
- return $response;
189
- }
190
-
191
- /**
192
- * Wrapper for metadata requests
193
- */
194
- function meta( $url, $parameters = array() ) {
195
- $response = $this->WPOAuthRequest( $url, $parameters, 'META' );
196
- if ( $this->format === 'json' && $this->decode_json ) {
197
- return json_decode( $response );
198
- }
199
-
200
- return $response;
201
- }
202
-
203
- /**
204
- * Handles a status update that includes an image.
205
- *
206
- * @param type $url
207
- * @param type $args
208
- *
209
- * @return boolean
210
- */
211
- function handleMediaRequest( $url, $args = array() ) {
212
- /* Load tmhOAuth for Media uploads only when needed: https://github.com/themattharris/tmhOAuth */
213
- /* It's not possible to upload media using WP_HTTP, so this needs to use cURL. */
214
- if ( ! class_exists( 'tmhOAuth' ) ) {
215
- require_once( plugin_dir_path( __FILE__ ) . 'tmhOAuth/tmhOAuth.php' );
216
- require_once( plugin_dir_path( __FILE__ ) . 'tmhOAuth/tmhUtilities.php' );
217
- }
218
- $auth = $args['auth'];
219
- if ( ! $auth ) {
220
- $ack = get_option( 'app_consumer_key' );
221
- $acs = get_option( 'app_consumer_secret' );
222
- $ot = get_option( 'oauth_token' );
223
- $ots = get_option( 'oauth_token_secret' );
224
- } else {
225
- $ack = get_user_meta( $auth, 'app_consumer_key', true );
226
- $acs = get_user_meta( $auth, 'app_consumer_secret', true );
227
- $ot = get_user_meta( $auth, 'oauth_token', true );
228
- $ots = get_user_meta( $auth, 'oauth_token_secret', true );
229
- }
230
- // when performing as a scheduled action, need to include file.php
231
- if ( ! function_exists( 'get_home_path' ) ) {
232
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
233
- }
234
- $connect = array(
235
- 'consumer_key' => $ack,
236
- 'consumer_secret' => $acs,
237
- 'user_token' => $ot,
238
- 'user_secret' => $ots
239
- );
240
- $tmhOAuth = new tmhOAuth( $connect );
241
- $attachment = $args['media'];
242
-
243
- $image_sizes = get_intermediate_image_sizes();
244
- if ( in_array( 'large', $image_sizes ) ) {
245
- $size = 'large';
246
- } else {
247
- $size = array_pop( $image_sizes );
248
- }
249
- $upload = wp_get_attachment_image_src( $attachment, apply_filters( 'wpt_upload_image_size', $size ) );
250
- $image_url = $upload[0];
251
- $remote = wp_remote_get( $image_url );
252
- if ( is_wp_error( $remote ) ) {
253
- $transport = 'curl';
254
- $binary = wp_get_curl( $image_url );
255
- } else {
256
- $transport = 'wp_http';
257
- $binary = wp_remote_retrieve_body( $remote );
258
- }
259
- wpt_mail( 'Media fetched binary', print_r( $remote, 1 ) . "\n\n" . print_r( $binary, 1 ) );
260
- if ( !$binary ) {
261
- return;
262
- }
263
-
264
- $mime_type = get_post_mime_type( $attachment );
265
- if ( ! $mime_type ) {
266
- $mime_type = 'image/jpeg';
267
- }
268
- /* End New */
269
-
270
- $code = $tmhOAuth->request(
271
- 'POST',
272
- $url,
273
- array( 'media' => "$binary" ),
274
- true, // use auth
275
- true // multipart
276
- );
277
-
278
- $response = $tmhOAuth->response['response'];
279
- $full = $tmhOAuth->response;
280
- wpt_mail( "Media Posted", "
281
- Media ID #$args[media] ($transport)" . "\n\n" .
282
- "Twitter Response" . "\n" . print_r( $full, 1 ) . "\n\n" .
283
- "Attachment Details" . "\n" . print_r( $upload, 1 ) . "\n\n" .
284
- "Img Request Response" . "\n" . print_r( $remote, 1 )
285
- );
286
-
287
- if ( is_wp_error( $response ) ) {
288
- return '';
289
- }
290
-
291
- $this->http_code = $code;
292
- $this->last_api_call = $url;
293
- $this->format = 'json';
294
- $this->http_header = $response;
295
- $response = json_decode( $response );
296
- $media_id = $response->media_id_string;
297
-
298
- /**
299
- * Eventually, use this to add alt text. Not supported at this time.
300
- *
301
- $metadata_api = 'https://upload.twitter.com/1.1/media/metadata/create.json';
302
- $alt_text = get_post_meta( $args['media'], '_wp_attachment_image_alt', true );
303
- if ( $alt_text != '' ) {
304
- $image_alt = json_encode( array(
305
- 'media_id' => $media_id,
306
- 'alt_text' => array(
307
- 'text' => $alt_text
308
- )
309
- ) );
310
- $post_image = $tmhOAuth->request(
311
- 'POST',
312
- $metadata_api,
313
- array( 'body' => $image_alt ),
314
- true
315
- );
316
-
317
- wpt_debug( 'Test of post image alt', print_r( $post_image, 1 ) );
318
- }
319
- */
320
-
321
- return $media_id;
322
- }
323
-
324
- /**
325
- * Format and sign an WPOAuth / API request
326
- */
327
- function WPOAuthRequest( $url, $args = array(), $method = null ) {
328
-
329
- //Handle media requests using tmhOAuth library.
330
- if ( $method == 'MEDIA' ) {
331
- return $this->handleMediaRequest( $url, $args );
332
- }
333
-
334
- if ( empty( $method ) ) {
335
- $method = empty( $args ) ? "GET" : "POST";
336
- }
337
- $req = WPOAuthRequest::from_consumer_and_token( $this->consumer, $this->token, $method, $url, $args );
338
- $req->sign_request( $this->sha1_method, $this->consumer, $this->token );
339
-
340
-
341
- $response = false;
342
- $url = null;
343
-
344
- switch ( $method ) {
345
- case 'GET':
346
- $url = $req->to_url();
347
- $response = wp_remote_get( $url );
348
- break;
349
- case 'POST':
350
- $url = $req->get_normalized_http_url();
351
- $args = wp_parse_args( $req->to_postdata() );
352
- $response = wp_remote_post( $url, array( 'body' => $args, 'timeout' => 30 ) );
353
- break;
354
- }
355
-
356
- if ( is_wp_error( $response ) ) {
357
- return false;
358
- }
359
- $this->http_code = $response['response']['code'];
360
- $this->body = json_decode( $response['body'] );
361
- $this->last_api_call = $url;
362
- $this->format = 'json';
363
- $this->http_header = $response['headers'];
364
-
365
- return $response['body'];
366
- }
367
- }
368
- }