WordPress Social Tools, Related Posts, Monetization – Shareaholic - Version 7.4.0.0

Version Description

  • Share Buttons App
    • Share Counts for Google+, Reddit, StumbleUpon, VK, Buffer, etc! This release features an optional and all new server side Share Counts API. Toggle this option under the "Advanced Settings" section.
    • Major performance upgrade and speed boost! Your pages will load faster for your visitors as share count lookups are now consolidated to one single HTTP request per page load (vs a call for each sharing service). The share counts are also heavily cached on both the client and server for super fast lookups and page performance.
Download this release

Release Info

Developer shareaholic
Plugin Icon 128x128 WordPress Social Tools, Related Posts, Monetization – Shareaholic
Version 7.4.0.0
Comparing to
See all releases

Code changes from version 7.3.0.1 to 7.4.0.0

admin.php CHANGED
@@ -17,6 +17,15 @@ class ShareaholicAdmin {
17
  */
18
  public static function admin_init() {
19
  ShareaholicUtilities::check_for_other_plugin();
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
  /**
@@ -283,7 +292,7 @@ class ShareaholicAdmin {
283
  if(isset($_POST['already_submitted']) && $_POST['already_submitted'] == 'Y' &&
284
  check_admin_referer($action, 'nonce_field')) {
285
  echo "<div class='updated settings_updated'><p><strong>". sprintf(__('Settings successfully saved', 'shareaholic')) . "</strong></p></div>";
286
- foreach (array('disable_tracking', 'disable_og_tags', 'disable_admin_bar_menu') as $setting) {
287
  if (isset($settings[$setting]) &&
288
  !isset($_POST['shareaholic'][$setting]) &&
289
  $settings[$setting] == 'on') {
@@ -312,6 +321,10 @@ class ShareaholicAdmin {
312
  if (isset($_POST['shareaholic']['disable_admin_bar_menu'])) {
313
  ShareaholicUtilities::update_options(array('disable_admin_bar_menu' => $_POST['shareaholic']['disable_admin_bar_menu']));
314
  }
 
 
 
 
315
  }
316
 
317
  ShareaholicUtilities::load_template('advanced_settings', array(
@@ -372,5 +385,4 @@ class ShareaholicAdmin {
372
  ));
373
  }
374
  }
375
- }
376
- ?>
17
  */
18
  public static function admin_init() {
19
  ShareaholicUtilities::check_for_other_plugin();
20
+
21
+ // workaround: http://codex.wordpress.org/Function_Reference/register_activation_hook
22
+ if ( is_admin() && get_option( 'Activated_Plugin_Shareaholic' ) == 'shareaholic' ) {
23
+ delete_option( 'Activated_Plugin_Shareaholic' );
24
+ /* do stuff once right after activation */
25
+ if (has_action('wp_ajax_nopriv_shareaholic_share_counts_api') && has_action('wp_ajax_shareaholic_share_counts_api')) {
26
+ ShareaholicUtilities::share_counts_api_connectivity_check();
27
+ }
28
+ }
29
  }
30
 
31
  /**
292
  if(isset($_POST['already_submitted']) && $_POST['already_submitted'] == 'Y' &&
293
  check_admin_referer($action, 'nonce_field')) {
294
  echo "<div class='updated settings_updated'><p><strong>". sprintf(__('Settings successfully saved', 'shareaholic')) . "</strong></p></div>";
295
+ foreach (array('disable_tracking', 'disable_og_tags', 'disable_admin_bar_menu', 'disable_internal_share_counts_api') as $setting) {
296
  if (isset($settings[$setting]) &&
297
  !isset($_POST['shareaholic'][$setting]) &&
298
  $settings[$setting] == 'on') {
321
  if (isset($_POST['shareaholic']['disable_admin_bar_menu'])) {
322
  ShareaholicUtilities::update_options(array('disable_admin_bar_menu' => $_POST['shareaholic']['disable_admin_bar_menu']));
323
  }
324
+
325
+ if (isset($_POST['shareaholic']['disable_internal_share_counts_api'])) {
326
+ ShareaholicUtilities::update_options(array('disable_internal_share_counts_api' => $_POST['shareaholic']['disable_internal_share_counts_api']));
327
+ }
328
  }
329
 
330
  ShareaholicUtilities::load_template('advanced_settings', array(
385
  ));
386
  }
387
  }
388
+ }
 
lib/social-share-counts/README.md DELETED
@@ -1,27 +0,0 @@
1
- social-share-counts
2
- ===================
3
-
4
- A library to check how many times a URL has been shared on Facebook, Twitter, Pinterest, Google+, etc.
5
-
6
-
7
- Contributing
8
- ------------
9
-
10
- 1. Fork the [official repository](https://github.com/shareaholic/social-share-counts/tree/master).
11
- 2. Make your changes in a topic branch.
12
- 3. Send a pull request.
13
-
14
- Credits
15
- -------
16
-
17
- ![Shareaholic](https://blog.shareaholic.com/wp-content/uploads/2013/10/new-shareaholic-logo.png)
18
-
19
- social-share-counts is maintained and funded by [Shareaholic, Inc](https://shareaholic.com/). The names and logos for Shareaholic are trademarks of Shareaholic, Inc.
20
-
21
- Thank you to all [the contributors](https://github.com/shareaholic/social-share-counts/contributors)!
22
-
23
-
24
- License
25
- -------
26
-
27
- social-share-counts is Copyright © 2014 Shareaholic Inc. It is free software, and may be redistributed under the terms specified in the [LICENSE](https://github.com/shareaholic/social-share-counts/blob/master/LICENSE) file.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/social-share-counts/curl_multi_share_count.php CHANGED
@@ -32,7 +32,7 @@ class ShareaholicCurlMultiShareCount extends ShareaholicShareCount {
32
  */
33
  public function get_counts() {
34
  $services_length = count($this->services);
35
- $config = $this->get_services_config();
36
  $response = array();
37
  $response['status'] = 200;
38
 
@@ -53,8 +53,6 @@ class ShareaholicCurlMultiShareCount extends ShareaholicShareCount {
53
  $this->$config[$service]['prepare']($this->url, $config);
54
  }
55
 
56
- $endpoint = sprintf($config[$service]['url'], $this->url);
57
-
58
  // Create the curl handle
59
  $curl_handles[$service] = curl_init();
60
 
@@ -85,7 +83,12 @@ class ShareaholicCurlMultiShareCount extends ShareaholicShareCount {
85
  ),
86
  );
87
  $callback = $config[$service]['callback'];
88
- $response['data'][$service] = $this->$callback($result);
 
 
 
 
 
89
  }
90
  curl_multi_close($multi_handle);
91
  }
@@ -94,7 +97,7 @@ class ShareaholicCurlMultiShareCount extends ShareaholicShareCount {
94
 
95
  private function curl_setopts($curl_handle, $config, $service) {
96
  // set the url to make the curl request
97
- curl_setopt($curl_handle, CURLOPT_URL, sprintf($config[$service]['url'], $this->url));
98
 
99
  // other necessary settings:
100
  // CURLOPT_HEADER means include header in output, which we do not want
@@ -102,10 +105,9 @@ class ShareaholicCurlMultiShareCount extends ShareaholicShareCount {
102
  curl_setopt_array($curl_handle, array(
103
  CURLOPT_HEADER => 0,
104
  CURLOPT_RETURNTRANSFER => 1,
105
- CURLOPT_TIMEOUT => 2,
106
  CURLOPT_SSL_VERIFYPEER => false,
107
  CURLOPT_SSL_VERIFYHOST => false,
108
- CURLOPT_FRESH_CONNECT => true,
109
  ));
110
 
111
  // set the http method: default is GET
32
  */
33
  public function get_counts() {
34
  $services_length = count($this->services);
35
+ $config = self::get_services_config();
36
  $response = array();
37
  $response['status'] = 200;
38
 
53
  $this->$config[$service]['prepare']($this->url, $config);
54
  }
55
 
 
 
56
  // Create the curl handle
57
  $curl_handles[$service] = curl_init();
58
 
83
  ),
84
  );
85
  $callback = $config[$service]['callback'];
86
+ $counts = $this->$callback($result);
87
+ if(is_numeric($counts)) {
88
+ $response['data'][$service] = $counts;
89
+ }
90
+ curl_multi_remove_handle($multi_handle, $handle);
91
+ curl_close($handle);
92
  }
93
  curl_multi_close($multi_handle);
94
  }
97
 
98
  private function curl_setopts($curl_handle, $config, $service) {
99
  // set the url to make the curl request
100
+ curl_setopt($curl_handle, CURLOPT_URL, str_replace('%s', $this->url, $config[$service]['url']));
101
 
102
  // other necessary settings:
103
  // CURLOPT_HEADER means include header in output, which we do not want
105
  curl_setopt_array($curl_handle, array(
106
  CURLOPT_HEADER => 0,
107
  CURLOPT_RETURNTRANSFER => 1,
108
+ CURLOPT_TIMEOUT => 5,
109
  CURLOPT_SSL_VERIFYPEER => false,
110
  CURLOPT_SSL_VERIFYHOST => false,
 
111
  ));
112
 
113
  // set the http method: default is GET
lib/social-share-counts/curl_multi_share_count_test.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
-
3
- require_once('curl_multi_share_count.php');
4
-
5
- class ShareaholicCurlMultiShareCountsTest extends PHPUnit_Framework_TestCase
6
- {
7
- public function setUp() {
8
- $this->url = 'https://blog.shareaholic.com';
9
- $counts = new ShareaholicCurlMultiShareCount($this->url, array());
10
- $this->services = array_keys($counts->get_services_config());
11
-
12
- // all callbacks take a predefined response structure
13
- $this->response = array(
14
- 'response' => array(
15
- 'code' => 200
16
- ),
17
- );
18
- }
19
-
20
- public function tearDown() {
21
-
22
- }
23
-
24
-
25
- public function testGetCount() {
26
- // test that this function returns the expected API response
27
- $share_count = new ShareaholicCurlMultiShareCount($this->url, $this->services);
28
- $response = $share_count->get_counts();
29
-
30
- $this->assertNotNull($response, 'The response array should not be null');
31
-
32
- foreach($this->services as $service) {
33
- $this->assertNotNull($response['data'][$service], 'The ' . $service . ' count should not be null');
34
- }
35
- }
36
-
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/social-share-counts/drupal_http.php DELETED
@@ -1,93 +0,0 @@
1
- <?php
2
- /**
3
- * This file holds the ShareaholicHttp class.
4
- *
5
- * @package shareaholic
6
- */
7
-
8
- /**
9
- * The purpose of this class is to provide an interface around any native
10
- * http function (wp_remote_get, drupal_http_request, curl) so that one
11
- * use this consistent API for making http request with well defined input
12
- * and output.
13
- *
14
- * @package shareaholic
15
- */
16
- class ShareaholicHttp {
17
-
18
- /**
19
- * Performs a HTTP request with a url, array of options, and ignore_error flag
20
- *
21
- *
22
- * The options object is an associative array that takes the following options:
23
- * - method: The http method for the request as a string. Defaults is 'GET'.
24
- *
25
- * - headers: The headers to send with the request as an associative array of name/value pairs. Default is empty array.
26
- *
27
- * - body: The body to send with the request as an associative array of name/value pairs. Default is NULL.
28
- * If the body is meant to be parsed as json, specify the content type in the headers option to be 'application/json'.
29
- *
30
- * - redirection: The number of redirects to follow for this request as an integer, Default is 5.
31
- *
32
- * - timeout: The number of seconds the request should take as an integer. Default is 15 (seconds).
33
- *
34
- * - user-agent: The useragent for the request. Default is mozilla browser useragent.
35
- *
36
- *
37
- * This function returns an object on success or false if there were errors.
38
- * The object is an associative array with the following keys:
39
- * - headers: the response headers as an array of key/value pairs
40
- * - body: the response body as a string
41
- * - response: an array with the following keys:
42
- * - code: the response code
43
- * - message: the status message
44
- *
45
- *
46
- * @param string $url The url you are sending the request to
47
- * @param array $options An array of supported options to pass to the request
48
- * @param bool $ignore_error A flag indicating to log error or not. Default is false.
49
- *
50
- * @return mixed It returns an associative array of name value pairs or false if there was an error.
51
- */
52
- public static function send($url, $options = array(), $ignore_error = false) {
53
- return self::send_with_drupal($url, $options, $ignore_error);
54
- }
55
-
56
- private static function send_with_drupal($url, $options, $ignore_error) {
57
- $request = array();
58
- $result = array();
59
- $request['method'] = isset($options['method']) ? $options['method'] : 'GET';
60
- $request['headers'] = isset($options['headers']) ? $options['headers'] : array();
61
- $request['max_redirects'] = isset($options['redirection']) ? $options['redirection'] : 5;
62
- $request['timeout'] = isset($options['timeout']) ? $options['timeout'] : 15;
63
- $request['headers']['User-Agent'] = isset($options['user-agent']) ? $options['user-agent'] : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0';
64
-
65
- if(isset($options['body'])) {
66
- if(isset($request['headers']['Content-Type']) && $request['headers']['Content-Type'] === 'application/json') {
67
- $request['data'] = json_encode($options['body']);
68
- } else {
69
- $request['data'] = http_build_query($options['body']);
70
- }
71
- } else {
72
- $request['body'] = NULL;
73
- }
74
-
75
- $response = drupal_http_request($url, $request);
76
-
77
- if(isset($response->error)) {
78
- if(!$ignore_error) {
79
- ShareaholicUtilities::log('ShareaholicHttp Error for ' . $url . ' with error ' . $response->error);
80
- }
81
- return false;
82
- }
83
-
84
- $result['headers'] = $response->headers;
85
- $result['body'] = $response->data;
86
- $result['response'] = array(
87
- 'code' => $response->code,
88
- 'message' => $response->status_message,
89
- );
90
-
91
- return $result;
92
- }
93
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/social-share-counts/http.php DELETED
@@ -1,105 +0,0 @@
1
- <?php
2
- /**
3
- * This file holds the ShareaholicHttp class.
4
- *
5
- * @package shareaholic
6
- */
7
-
8
- /**
9
- * The purpose of this class is to provide an interface around any native
10
- * http function (wp_remote_get, drupal_http_request, curl) so that one
11
- * use this consistent API for making http request with well defined input
12
- * and output.
13
- *
14
- * @package shareaholic
15
- */
16
- class ShareaholicHttp {
17
-
18
- /**
19
- * Performs a HTTP request with a url and array of options
20
- *
21
- *
22
- * The options object is an associative array that takes the following options:
23
- * - method: The http method for the request as a string. Defaults is 'GET'.
24
- *
25
- * - headers: The headers to send with the request as an associative array of name/value pairs. Default is empty array.
26
- *
27
- * - body: The body to send with the request as an associative array of name/value pairs. Default is NULL.
28
- * If the body is meant to be parsed as json, specify the content type in the headers option to be 'application/json'.
29
- *
30
- * - redirection: The number of redirects to follow for this request as an integer, Default is 5.
31
- *
32
- * - timeout: The number of seconds the request should take as an integer. Default is 15 (seconds).
33
- *
34
- * - user-agent: The useragent for the request. Default is mozilla browser useragent.
35
- *
36
- *
37
- * This function returns an object of the response.
38
- * The object is an associative array with the following keys:
39
- * - body: the response body as a string
40
- * - response: an array with the following keys:
41
- * - code: the response code
42
- *
43
- *
44
- * @param string $url The url you are sending the request to
45
- * @param array $options An array of supported options to pass to the request
46
- *
47
- * @return array It returns an associative array of name value pairs
48
- */
49
- public static function send($url, $options = array()) {
50
- return self::send_with_curl($url, $options);
51
- }
52
-
53
- private static function send_with_curl($url, $options) {
54
- $curl_handle = curl_init($url);
55
-
56
- curl_setopt($curl_handle, CURLOPT_HEADER, 0);
57
- curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
58
-
59
- // set the timeout
60
- $timeout = isset($options['timeout']) ? $options['timeout'] : 15;
61
- curl_setopt($curl_handle, CURLOPT_TIMEOUT, $timeout);
62
-
63
- // set the http method: default is GET
64
- if($option['method'] === 'POST') {
65
- curl_setopt($curl_handle, CURLOPT_POST, 1);
66
- }
67
-
68
- // set the body and headers
69
- $headers = isset($options['headers']) ? $options['headers'] : array();
70
- $body = isset($options['body']) ? $options['body'] : NULL;
71
-
72
- if(isset($body)) {
73
- if(isset($headers['Content-Type']) && $headers['Content-Type'] === 'application/json') {
74
- $data_string = json_encode($body);
75
-
76
- curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array(
77
- 'Content-Type: application/json',
78
- 'Content-Length: ' . strlen($data_string))
79
- );
80
-
81
- curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $data_string);
82
- }
83
- }
84
-
85
- // set the useragent
86
- $useragent = isset($options['user-agent']) ? $options['user-agent'] : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0';
87
- curl_setopt($curl_handle, CURLOPT_USERAGENT, $useragent);
88
-
89
- // set the max redirects
90
- if(isset($options['redirection'])) {
91
- curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
92
- curl_setopt($curl_handle, CURLOPT_MAXREDIRS, $option['redirection']);
93
- }
94
-
95
- $output = curl_exec($curl_handle);
96
-
97
- $result['body'] = $output;
98
- $result['response'] = array(
99
- 'code' => curl_getinfo($curl_handle, CURLINFO_HTTP_CODE),
100
- );
101
-
102
- curl_close($curl_handle);
103
- return $result;
104
- }
105
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/social-share-counts/seq_share_count.php CHANGED
@@ -32,7 +32,7 @@ class ShareaholicSeqShareCount extends ShareaholicShareCount {
32
  */
33
  public function get_counts() {
34
  $services_length = count($this->services);
35
- $config = $this->get_services_config();
36
  $response = array();
37
  $response['status'] = 200;
38
 
@@ -54,12 +54,15 @@ class ShareaholicSeqShareCount extends ShareaholicShareCount {
54
  'body' => isset($config[$service]['body']) ? $config[$service]['body'] : NULL,
55
  );
56
 
57
- $result = ShareaholicHttp::send(sprintf($config[$service]['url'], $this->url), $options);
58
  if(!$result) {
59
  $response['status'] = 500;
60
  }
61
  $callback = $config[$service]['callback'];
62
- $response['data'][$service] = $this->$callback($result);
 
 
 
63
  }
64
  return $response;
65
  }
32
  */
33
  public function get_counts() {
34
  $services_length = count($this->services);
35
+ $config = self::get_services_config();
36
  $response = array();
37
  $response['status'] = 200;
38
 
54
  'body' => isset($config[$service]['body']) ? $config[$service]['body'] : NULL,
55
  );
56
 
57
+ $result = ShareaholicHttp::send(str_replace('%s', $this->url, $config[$service]['url']), $options);
58
  if(!$result) {
59
  $response['status'] = 500;
60
  }
61
  $callback = $config[$service]['callback'];
62
+ $counts = $this->$callback($result);
63
+ if(is_numeric($counts)) {
64
+ $response['data'][$service] = $counts;
65
+ }
66
  }
67
  return $response;
68
  }
lib/social-share-counts/seq_share_count_test.php DELETED
@@ -1,186 +0,0 @@
1
- <?php
2
-
3
- require_once('seq_share_count.php');
4
- require_once('http.php');
5
-
6
- class ShareaholicSeqShareCountsTest extends PHPUnit_Framework_TestCase
7
- {
8
- public function setUp() {
9
- $this->url = 'https://blog.shareaholic.com';
10
- $counts = new ShareaholicSeqShareCount($this->url, array());
11
- $this->services = array_keys($counts->get_services_config());
12
-
13
- // all callbacks take a predefined response structure
14
- $this->response = array(
15
- 'response' => array(
16
- 'code' => 200
17
- ),
18
- );
19
- }
20
-
21
- public function tearDown() {
22
-
23
- }
24
-
25
- public function testFacebookCountCallback() {
26
- // given a typical facebook counts api response, test that
27
- // it gives back the expected result (the total_count which is 16)
28
- $json = '[{"url":"https:\/\/blog.shareaholic.com\/","normalized_url":"https:\/\/blog.shareaholic.com\/","share_count":12,"like_count":4,"comment_count":0,"total_count":16,"click_count":0,"comments_fbid":350586041699622,"commentsbox_count":0}]';
29
- $this->response['body'] = $json;
30
-
31
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
32
- $facebook_count = $share_count->facebook_count_callback($this->response);
33
-
34
- $this->assertEquals(16, $facebook_count, 'It should get the correct fb count');
35
- }
36
-
37
-
38
- public function testTwitterCountCallback() {
39
- // given a typical twitter counts api response, test that
40
- // it gives back the expected result (the count which is 3)
41
- $json = '{"count":3,"url":"https:\/\/blog.shareaholic.com\/"}';
42
- $this->response['body'] = $json;
43
-
44
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
45
- $twitter_count = $share_count->twitter_count_callback($this->response);
46
-
47
- $this->assertEquals(3, $twitter_count, 'It should get the correct twtr count');
48
- }
49
-
50
-
51
- public function testLinkedinCountCallback() {
52
- // given a typical linkedin counts api response, test that
53
- // it gives back the expected result (the count which is 8)
54
- $json = '{"count":8,"fCnt":"8","fCntPlusOne":"9","url":"https:\/\/blog.shareaholic.com\/"}';
55
- $this->response['body'] = $json;
56
-
57
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
58
- $linkedin_count = $share_count->linkedin_count_callback($this->response);
59
-
60
- $this->assertEquals(8, $linkedin_count, 'It should get the correct linkedin count');
61
- }
62
-
63
-
64
- public function testGoogleplusCountCallback() {
65
- // given a typical google+ counts api response, test that
66
- // it gives back the expected result (the count which is 10)
67
- $json = '[{"id": "p", "result": {"kind": "pos#plusones", "id": "https://blog.shareaholic.com/", "isSetByViewer": false, "metadata": {"type": "URL", "globalCounts": {"count": 10.0}}}}]';
68
- $this->response['body'] = $json;
69
-
70
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
71
- $google_plus_count = $share_count->google_plus_count_callback($this->response);
72
-
73
- $this->assertEquals(10, $google_plus_count, 'It should get the correct google_plus count');
74
- }
75
-
76
-
77
- public function testDeliciousCountCallback() {
78
- // given a typical delicious counts api response, test that
79
- // it gives back the expected result (the total_posts which is 5462)
80
- $json = '[{"url": "http://www.delicious.com/", "total_posts": 5462, "top_tags": {"web2.0": 1, "web": 1, "search": 1, "technology": 1, "bookmarking": 1, "del.icio.us": 1, "delicious": 1, "social": 1, "home": 1, "tools": 1}, "hash": "ea83167936715d3f712f4fb6c78f92d2", "title": "Delicious"}]';
81
- $this->response['body'] = $json;
82
-
83
- $share_count = new ShareaholicSeqShareCount('http://www.delicious.com/', $this->services);
84
- $delicious_count = $share_count->delicious_count_callback($this->response);
85
-
86
- $this->assertEquals(5462, $delicious_count, 'It should get the correct delicious count');
87
- }
88
-
89
-
90
- public function testPinterestCountCallback() {
91
- // given a typical pinterest counts api response, test that
92
- // it gives back the expected result (the count which is 1)
93
- $body = 'f({"count": 1, "url": "https://blog.shareaholic.com"})';
94
- $this->response['body'] = $body;
95
-
96
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
97
- $count = $share_count->pinterest_count_callback($this->response);
98
-
99
- $this->assertEquals(1, $count, 'It should get the correct pinterest count');
100
- }
101
-
102
-
103
- public function testBufferCountCallback() {
104
- // given a typical buffer counts api response, test that
105
- // it gives back the expected result (the shares which is 3)
106
- $body = '{"shares":3}';
107
- $this->response['body'] = $body;
108
-
109
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
110
- $count = $share_count->buffer_count_callback($this->response);
111
-
112
- $this->assertEquals(3, $count, 'It should get the correct buffer count');
113
- }
114
-
115
- public function testStumbleuponCountCallback() {
116
- // given a typical stumbleupon counts api response, test that
117
- // it gives back the expected result (the views which is 1)
118
- $body = '{"result":{"url":"https:\/\/blog.shareaholic.com\/","in_index":true,"publicid":"1Qat7p","views":1,"title":"Blog \/ Shareaholic (@shareaholic)","thumbnail":"http:\/\/cdn.stumble-upon.com\/mthumb\/672\/157433672.jpg","thumbnail_b":"http:\/\/cdn.stumble-upon.com\/bthumb\/672\/157433672.jpg","submit_link":"http:\/\/www.stumbleupon.com\/submit\/?url=https:\/\/blog.shareaholic.com\/","badge_link":"http:\/\/www.stumbleupon.com\/badge\/?url=https:\/\/blog.shareaholic.com\/","info_link":"http:\/\/www.stumbleupon.com\/url\/https%253A\/\/blog.shareaholic.com\/"},"timestamp":1394771877,"success":true}';
119
- $this->response['body'] = $body;
120
-
121
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
122
- $count = $share_count->stumbleupon_count_callback($this->response);
123
-
124
- $this->assertEquals(1, $count, 'It should get the correct stumbleupon count');
125
- }
126
-
127
- public function testRedditCountCallback() {
128
- // given a typical reddit counts api response, test that
129
- // it gives back the expected result (the ups which is 1)
130
- // NOTE: the actual JSON output was too long so some keys were removed
131
- $body = '{"kind": "Listing", "data": {"modhash": "", "children": [{"kind": "t3", "data": {"domain": "reddit.com", "banned_by": null, "likes": null, "clicked": false, "stickied": false, "score": 1, "downs": 0, "url": "http://reddit.com", "ups": 1, "num_comments": 0, "distinguished": null}}], "after": null, "before": null}}';
132
- $this->response['body'] = $body;
133
-
134
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
135
- $count = $share_count->reddit_count_callback($this->response);
136
-
137
- $this->assertEquals(1, $count, 'It should get the correct reddit count');
138
- }
139
-
140
- public function testVkCountCallback() {
141
- // given a typical vk counts api response, test that
142
- // it gives back the expected result (3781)
143
- $body = 'VK.Share.count(0, 3781);';
144
- $this->response['body'] = $body;
145
-
146
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
147
- $count = $share_count->vk_count_callback($this->response);
148
-
149
- $this->assertEquals(3781, $count, 'It should get the correct vk count');
150
- }
151
-
152
- public function testOdnoklassnikiCountCallback() {
153
- // given a typical odnoklassniki counts api response, test that
154
- // it gives back the expected result (1)
155
- $body = "ODKL.updateCount('odklcnt0','1');";
156
- $this->response['body'] = $body;
157
-
158
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
159
- $count = $share_count->odnoklassniki_count_callback($this->response);
160
-
161
- $this->assertEquals(1, $count, 'It should get the correct odnoklassniki count');
162
- }
163
-
164
- public function testGooglePlusPrepareRequest() {
165
- $count = new ShareaholicSeqShareCount($this->url, $this->services);
166
- $config = $count->get_services_config();
167
-
168
- // check that the function sets the post body in the $config object
169
- $count->google_plus_prepare_request($this->url, $config);
170
- $this->assertNotNull($config['google_plus']['body'], 'The post body for google plus should not be null');
171
-
172
- }
173
-
174
- public function testGetCount() {
175
- // test that this function returns the expected API response
176
- $share_count = new ShareaholicSeqShareCount($this->url, $this->services);
177
- $response = $share_count->get_counts();
178
-
179
- $this->assertNotNull($response, 'The response array should not be null');
180
-
181
- foreach($this->services as $service) {
182
- $this->assertNotNull($response['data'][$service], 'The ' . $service . ' count should not be null');
183
- }
184
- }
185
-
186
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/social-share-counts/share_count.php CHANGED
@@ -23,26 +23,30 @@ abstract class ShareaholicShareCount {
23
  $this->services = $services;
24
  }
25
 
26
- public function get_services_config() {
27
  return array(
28
  'facebook' => array(
29
- 'url' => 'https://api.facebook.com/method/links.getStats?format=json&urls=%s',
30
  'method' => 'GET',
 
31
  'callback' => 'facebook_count_callback',
32
  ),
33
  'twitter' => array(
34
  'url' => 'http://cdn.api.twitter.com/1/urls/count.json?url=%s',
35
  'method' => 'GET',
 
36
  'callback' => 'twitter_count_callback',
37
  ),
38
  'linkedin' => array(
39
  'url' => 'http://www.linkedin.com/countserv/count/share?format=json&url=%s',
40
  'method' => 'GET',
 
41
  'callback' => 'linkedin_count_callback',
42
  ),
43
  'google_plus' => array(
44
  'url' => 'https://clients6.google.com/rpc',
45
  'method' => 'POST',
 
46
  'headers' => array('Content-Type' => 'application/json'),
47
  'body' => NULL,
48
  'prepare' => 'google_plus_prepare_request',
@@ -51,55 +55,75 @@ abstract class ShareaholicShareCount {
51
  'delicious' => array(
52
  'url' => 'http://feeds.delicious.com/v2/json/urlinfo/data?url=%s',
53
  'method' => 'GET',
 
54
  'callback' => 'delicious_count_callback',
55
  ),
56
  'pinterest' => array(
57
  'url' => 'http://api.pinterest.com/v1/urls/count.json?url=%s&callback=f',
58
  'method' => 'GET',
 
59
  'callback' => 'pinterest_count_callback',
60
  ),
61
  'buffer' => array(
62
  'url' => 'https://api.bufferapp.com/1/links/shares.json?url=%s',
63
  'method' => 'GET',
 
64
  'callback' => 'buffer_count_callback',
65
  ),
66
  'stumbleupon' => array(
67
  'url' => 'http://www.stumbleupon.com/services/1.01/badge.getinfo?url=%s',
68
  'method' => 'GET',
 
69
  'callback' => 'stumbleupon_count_callback',
70
  ),
71
  'reddit' => array(
72
  'url' => 'http://buttons.reddit.com/button_info.json?url=%s',
73
  'method' => 'GET',
 
74
  'callback' => 'reddit_count_callback',
75
  ),
76
  'vk' => array(
77
  'url' => 'http://vk.com/share.php?act=count&url=%s',
78
  'method' => 'GET',
 
79
  'callback' => 'vk_count_callback',
80
  ),
81
  'odnoklassniki' => array(
82
  'url' => 'http://www.odnoklassniki.ru/dk?st.cmd=extLike&uid=odklcnt0&ref=%s',
83
  'method' => 'GET',
 
84
  'callback' => 'odnoklassniki_count_callback',
85
  ),
86
  );
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  /**
91
  * Callback function for facebook count API
92
  * Gets the facebook counts from response
93
  *
94
  * @param Array $response The response from calling the API
95
- * @return Integer The counts from the API
96
  */
97
  public function facebook_count_callback($response) {
98
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
99
- return 0;
100
  }
101
  $body = json_decode($response['body'], true);
102
- return isset($body[0]['total_count']) ? $body[0]['total_count'] : 0;
103
  }
104
 
105
 
@@ -108,11 +132,11 @@ abstract class ShareaholicShareCount {
108
  * Gets the twitter counts from response
109
  *
110
  * @param Array $response The response from calling the API
111
- * @return Integer The counts from the API
112
  */
113
  public function twitter_count_callback($response) {
114
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
115
- return 0;
116
  }
117
  $body = json_decode($response['body'], true);
118
  return isset($body['count']) ? $body['count'] : 0;
@@ -124,11 +148,11 @@ abstract class ShareaholicShareCount {
124
  * Gets the linkedin counts from response
125
  *
126
  * @param Array $response The response from calling the API
127
- * @return Integer The counts from the API
128
  */
129
  public function linkedin_count_callback($response) {
130
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
131
- return 0;
132
  }
133
  $body = json_decode($response['body'], true);
134
  return isset($body['count']) ? $body['count'] : 0;
@@ -174,11 +198,11 @@ abstract class ShareaholicShareCount {
174
  * Gets the google plus counts from response
175
  *
176
  * @param Array $response The response from calling the API
177
- * @return Integer The counts from the API
178
  */
179
  public function google_plus_count_callback($response) {
180
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
181
- return 0;
182
  }
183
  $body = json_decode($response['body'], true);
184
  return isset($body[0]['result']['metadata']['globalCounts']['count']) ? intval($body[0]['result']['metadata']['globalCounts']['count']) : 0;
@@ -190,11 +214,11 @@ abstract class ShareaholicShareCount {
190
  * Gets the delicious counts from response
191
  *
192
  * @param Array $response The response from calling the API
193
- * @return Integer The counts from the API
194
  */
195
  public function delicious_count_callback($response) {
196
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
197
- return 0;
198
  }
199
  $body = json_decode($response['body'], true);
200
  return isset($body[0]['total_posts']) ? $body[0]['total_posts'] : 0;
@@ -206,11 +230,11 @@ abstract class ShareaholicShareCount {
206
  * Gets the pinterest counts from response
207
  *
208
  * @param Array $response The response from calling the API
209
- * @return Integer The counts from the API
210
  */
211
  public function pinterest_count_callback($response) {
212
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
213
- return 0;
214
  }
215
  $response['body'] = substr($response['body'], 2, strlen($response['body']) - 3);
216
  $body = json_decode($response['body'], true);
@@ -223,11 +247,11 @@ abstract class ShareaholicShareCount {
223
  * Gets the buffer share counts from response
224
  *
225
  * @param Array $response The response from calling the API
226
- * @return Integer The counts from the API
227
  */
228
  public function buffer_count_callback($response) {
229
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
230
- return 0;
231
  }
232
  $body = json_decode($response['body'], true);
233
  return isset($body['shares']) ? $body['shares'] : 0;
@@ -239,11 +263,11 @@ abstract class ShareaholicShareCount {
239
  * Gets the stumbleupon counts from response
240
  *
241
  * @param Array $response The response from calling the API
242
- * @return Integer The counts from the API
243
  */
244
  public function stumbleupon_count_callback($response) {
245
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
246
- return 0;
247
  }
248
  $body = json_decode($response['body'], true);
249
  return isset($body['result']['views']) ? $body['result']['views'] : 0;
@@ -255,11 +279,11 @@ abstract class ShareaholicShareCount {
255
  * Gets the reddit counts from response
256
  *
257
  * @param Array $response The response from calling the API
258
- * @return Integer The counts from the API
259
  */
260
  public function reddit_count_callback($response) {
261
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
262
- return 0;
263
  }
264
  $body = json_decode($response['body'], true);
265
  return isset($body['data']['children'][0]['data']['ups']) ? $body['data']['children'][0]['data']['ups'] : 0;
@@ -271,11 +295,11 @@ abstract class ShareaholicShareCount {
271
  * Gets the vk counts from response
272
  *
273
  * @param Array $response The response from calling the API
274
- * @return Integer The counts from the API
275
  */
276
  public function vk_count_callback($response) {
277
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
278
- return 0;
279
  }
280
 
281
  // This API does not return JSON. Just plain text JS. Example:
@@ -292,11 +316,11 @@ abstract class ShareaholicShareCount {
292
  * Gets the odnoklassniki counts from response
293
  *
294
  * @param Array $response The response from calling the API
295
- * @return Integer The counts from the API
296
  */
297
  public function odnoklassniki_count_callback($response) {
298
- if(!$response || !preg_match('/20*/', $response['response']['code'])) {
299
- return 0;
300
  }
301
 
302
  // Another weird API. Similar to vk, extract the 2nd param from the response:
23
  $this->services = $services;
24
  }
25
 
26
+ public static function get_services_config() {
27
  return array(
28
  'facebook' => array(
29
+ 'url' => 'https://graph.facebook.com/fql?q=SELECT%20url,normalized_url,total_count%20FROM%20link_stat%20WHERE%20url%20=%20"%s"',
30
  'method' => 'GET',
31
+ 'timeout' => 3, // in number of seconds
32
  'callback' => 'facebook_count_callback',
33
  ),
34
  'twitter' => array(
35
  'url' => 'http://cdn.api.twitter.com/1/urls/count.json?url=%s',
36
  'method' => 'GET',
37
+ 'timeout' => 3,
38
  'callback' => 'twitter_count_callback',
39
  ),
40
  'linkedin' => array(
41
  'url' => 'http://www.linkedin.com/countserv/count/share?format=json&url=%s',
42
  'method' => 'GET',
43
+ 'timeout' => 3,
44
  'callback' => 'linkedin_count_callback',
45
  ),
46
  'google_plus' => array(
47
  'url' => 'https://clients6.google.com/rpc',
48
  'method' => 'POST',
49
+ 'timeout' => 1,
50
  'headers' => array('Content-Type' => 'application/json'),
51
  'body' => NULL,
52
  'prepare' => 'google_plus_prepare_request',
55
  'delicious' => array(
56
  'url' => 'http://feeds.delicious.com/v2/json/urlinfo/data?url=%s',
57
  'method' => 'GET',
58
+ 'timeout' => 3,
59
  'callback' => 'delicious_count_callback',
60
  ),
61
  'pinterest' => array(
62
  'url' => 'http://api.pinterest.com/v1/urls/count.json?url=%s&callback=f',
63
  'method' => 'GET',
64
+ 'timeout' => 3,
65
  'callback' => 'pinterest_count_callback',
66
  ),
67
  'buffer' => array(
68
  'url' => 'https://api.bufferapp.com/1/links/shares.json?url=%s',
69
  'method' => 'GET',
70
+ 'timeout' => 1,
71
  'callback' => 'buffer_count_callback',
72
  ),
73
  'stumbleupon' => array(
74
  'url' => 'http://www.stumbleupon.com/services/1.01/badge.getinfo?url=%s',
75
  'method' => 'GET',
76
+ 'timeout' => 1,
77
  'callback' => 'stumbleupon_count_callback',
78
  ),
79
  'reddit' => array(
80
  'url' => 'http://buttons.reddit.com/button_info.json?url=%s',
81
  'method' => 'GET',
82
+ 'timeout' => 1,
83
  'callback' => 'reddit_count_callback',
84
  ),
85
  'vk' => array(
86
  'url' => 'http://vk.com/share.php?act=count&url=%s',
87
  'method' => 'GET',
88
+ 'timeout' => 1,
89
  'callback' => 'vk_count_callback',
90
  ),
91
  'odnoklassniki' => array(
92
  'url' => 'http://www.odnoklassniki.ru/dk?st.cmd=extLike&uid=odklcnt0&ref=%s',
93
  'method' => 'GET',
94
+ 'timeout' => 1,
95
  'callback' => 'odnoklassniki_count_callback',
96
  ),
97
  );
98
  }
99
 
100
+ /**
101
+ * Check if calling the service returned any type of error
102
+ *
103
+ * @param object $response A response object
104
+ * @return bool true if it has an error or false if it does not
105
+ */
106
+ public function has_http_error($response) {
107
+ if(!$response || !isset($response['response']['code']) || !preg_match('/20*/', $response['response']['code']) || !isset($response['body'])) {
108
+ return true;
109
+ }
110
+ return false;
111
+ }
112
+
113
 
114
  /**
115
  * Callback function for facebook count API
116
  * Gets the facebook counts from response
117
  *
118
  * @param Array $response The response from calling the API
119
+ * @return mixed The counts from the API or false if error
120
  */
121
  public function facebook_count_callback($response) {
122
+ if($this->has_http_error($response)) {
123
+ return false;
124
  }
125
  $body = json_decode($response['body'], true);
126
+ return isset($body['data'][0]['total_count']) ? $body['data'][0]['total_count'] : 0;
127
  }
128
 
129
 
132
  * Gets the twitter counts from response
133
  *
134
  * @param Array $response The response from calling the API
135
+ * @return mixed The counts from the API or false if error
136
  */
137
  public function twitter_count_callback($response) {
138
+ if($this->has_http_error($response)) {
139
+ return false;
140
  }
141
  $body = json_decode($response['body'], true);
142
  return isset($body['count']) ? $body['count'] : 0;
148
  * Gets the linkedin counts from response
149
  *
150
  * @param Array $response The response from calling the API
151
+ * @return mixed The counts from the API or false if error
152
  */
153
  public function linkedin_count_callback($response) {
154
+ if($this->has_http_error($response)) {
155
+ return false;
156
  }
157
  $body = json_decode($response['body'], true);
158
  return isset($body['count']) ? $body['count'] : 0;
198
  * Gets the google plus counts from response
199
  *
200
  * @param Array $response The response from calling the API
201
+ * @return mixed The counts from the API or false if error
202
  */
203
  public function google_plus_count_callback($response) {
204
+ if($this->has_http_error($response)) {
205
+ return false;
206
  }
207
  $body = json_decode($response['body'], true);
208
  return isset($body[0]['result']['metadata']['globalCounts']['count']) ? intval($body[0]['result']['metadata']['globalCounts']['count']) : 0;
214
  * Gets the delicious counts from response
215
  *
216
  * @param Array $response The response from calling the API
217
+ * @return mixed The counts from the API or false if error
218
  */
219
  public function delicious_count_callback($response) {
220
+ if($this->has_http_error($response)) {
221
+ return false;
222
  }
223
  $body = json_decode($response['body'], true);
224
  return isset($body[0]['total_posts']) ? $body[0]['total_posts'] : 0;
230
  * Gets the pinterest counts from response
231
  *
232
  * @param Array $response The response from calling the API
233
+ * @return mixed The counts from the API or false if error
234
  */
235
  public function pinterest_count_callback($response) {
236
+ if($this->has_http_error($response)) {
237
+ return false;
238
  }
239
  $response['body'] = substr($response['body'], 2, strlen($response['body']) - 3);
240
  $body = json_decode($response['body'], true);
247
  * Gets the buffer share counts from response
248
  *
249
  * @param Array $response The response from calling the API
250
+ * @return mixed The counts from the API or false if error
251
  */
252
  public function buffer_count_callback($response) {
253
+ if($this->has_http_error($response)) {
254
+ return false;
255
  }
256
  $body = json_decode($response['body'], true);
257
  return isset($body['shares']) ? $body['shares'] : 0;
263
  * Gets the stumbleupon counts from response
264
  *
265
  * @param Array $response The response from calling the API
266
+ * @return mixed The counts from the API or false if error
267
  */
268
  public function stumbleupon_count_callback($response) {
269
+ if($this->has_http_error($response)) {
270
+ return false;
271
  }
272
  $body = json_decode($response['body'], true);
273
  return isset($body['result']['views']) ? $body['result']['views'] : 0;
279
  * Gets the reddit counts from response
280
  *
281
  * @param Array $response The response from calling the API
282
+ * @return mixed The counts from the API or false if error
283
  */
284
  public function reddit_count_callback($response) {
285
+ if($this->has_http_error($response)) {
286
+ return false;
287
  }
288
  $body = json_decode($response['body'], true);
289
  return isset($body['data']['children'][0]['data']['ups']) ? $body['data']['children'][0]['data']['ups'] : 0;
295
  * Gets the vk counts from response
296
  *
297
  * @param Array $response The response from calling the API
298
+ * @return mixed The counts from the API or false if error
299
  */
300
  public function vk_count_callback($response) {
301
+ if($this->has_http_error($response)) {
302
+ return false;
303
  }
304
 
305
  // This API does not return JSON. Just plain text JS. Example:
316
  * Gets the odnoklassniki counts from response
317
  *
318
  * @param Array $response The response from calling the API
319
+ * @return mixed The counts from the API or false if error
320
  */
321
  public function odnoklassniki_count_callback($response) {
322
+ if($this->has_http_error($response)) {
323
+ return false;
324
  }
325
 
326
  // Another weird API. Similar to vk, extract the 2nd param from the response:
public.php CHANGED
@@ -9,6 +9,7 @@
9
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/wordpress_http.php');
10
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/seq_share_count.php');
11
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/curl_multi_share_count.php');
 
12
 
13
  /**
14
  * This class is all about drawing the stuff in publishers'
@@ -49,7 +50,8 @@ class ShareaholicPublic {
49
  ShareaholicUtilities::get_or_create_api_key()) {
50
  ShareaholicUtilities::load_template('script_tag', array(
51
  'shareaholic_url' => Shareaholic::URL,
52
- 'api_key' => ShareaholicUtilities::get_option('api_key')
 
53
  ));
54
  }
55
  }
@@ -413,17 +415,26 @@ class ShareaholicPublic {
413
  *
414
  */
415
  public static function share_counts_api() {
416
- $url = isset($_GET['url']) ? $_GET['url'] : NULL;
417
- $services = isset($_GET['services']) ? $_GET['services'] : NULL;
418
- $result = array();
419
 
420
- if(is_array($services) && count($services) > 0 && !empty($url)) {
421
- if(self::has_curl()) {
422
- $shares = new ShareaholicCurlMultiShareCount($url, $services);
423
- } else {
424
- $shares = new ShareaholicSeqShareCount($url, $services);
 
 
 
 
 
 
 
 
 
 
 
425
  }
426
- $result = $shares->get_counts();
427
  }
428
 
429
  header('Content-Type: application/json');
9
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/wordpress_http.php');
10
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/seq_share_count.php');
11
  require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/curl_multi_share_count.php');
12
+ require_once(SHAREAHOLIC_DIR . '/public_js.php');
13
 
14
  /**
15
  * This class is all about drawing the stuff in publishers'
50
  ShareaholicUtilities::get_or_create_api_key()) {
51
  ShareaholicUtilities::load_template('script_tag', array(
52
  'shareaholic_url' => Shareaholic::URL,
53
+ 'api_key' => ShareaholicUtilities::get_option('api_key'),
54
+ 'page_config' => ShareaholicPublicJS::get_page_config(),
55
  ));
56
  }
57
  }
415
  *
416
  */
417
  public static function share_counts_api() {
418
+ $cache_key = 'shr_api_res-' . md5( $_SERVER['QUERY_STRING'] );
419
+ $result = get_transient($cache_key);
 
420
 
421
+ if (!$result) {
422
+ $url = isset($_GET['url']) ? $_GET['url'] : NULL;
423
+ $services = isset($_GET['services']) ? $_GET['services'] : NULL;
424
+ $result = array();
425
+
426
+ if(is_array($services) && count($services) > 0 && !empty($url)) {
427
+ if(self::has_curl()) {
428
+ $shares = new ShareaholicCurlMultiShareCount($url, $services);
429
+ } else {
430
+ $shares = new ShareaholicSeqShareCount($url, $services);
431
+ }
432
+ $result = $shares->get_counts();
433
+
434
+ if (isset($result['data'])) {
435
+ set_transient( $cache_key, $result, SHARE_COUNTS_CHECK_CACHE_LENGTH );
436
+ }
437
  }
 
438
  }
439
 
440
  header('Content-Type: application/json');
public_js.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Holds the ShareaholicPublicJS class.
4
+ *
5
+ * @package shareaholic
6
+ */
7
+
8
+ /**
9
+ * This class gets the necessary components ready
10
+ * for rendering the shareaholic js code for the template
11
+ *
12
+ * @package shareaholic
13
+ */
14
+ class ShareaholicPublicJS {
15
+
16
+ /**
17
+ * Gets the page configuration to be used by shareaholic.js
18
+ *
19
+ * This function returns a string representation of the page config object
20
+ * which will be consumed by the shareaholic javascript.
21
+ *
22
+ * @return string The stringified version of the page config
23
+ */
24
+ public static function get_page_config() {
25
+ $config = array(
26
+ 'apps' => array(),
27
+ );
28
+ $functions_map = self::get_function_definitions();
29
+ $share_buttons = self::get_share_buttons_config();
30
+
31
+ // if all the configurations are empty, return an empty JS object
32
+ if(empty($share_buttons)) {
33
+ return '{}';
34
+ }
35
+
36
+ $config['apps']['share_buttons'] = $share_buttons;
37
+
38
+ // Get the json representation of the page configuration
39
+ $json_string = json_encode($config);
40
+
41
+ // Now iterate through the function mapping and do a string replace
42
+ foreach($functions_map as $placeholder => $implementation) {
43
+ $json_string = str_replace('"' . $placeholder . '"', $implementation, $json_string);
44
+ }
45
+ return $json_string;
46
+ }
47
+
48
+ /**
49
+ * Get the share_buttons configuration to be used by Shareaholic.js
50
+ *
51
+ * This function returns an object for the share buttons configuration
52
+ * which will be consumed by Shareaholic.js
53
+ *
54
+ * @return array an associative array of configuration for share buttons
55
+ */
56
+ public static function get_share_buttons_config() {
57
+ $share_buttons = array();
58
+ $disable_share_counts_api = ShareaholicUtilities::get_option('disable_internal_share_counts_api');
59
+ $share_counts_connect_check = ShareaholicUtilities::get_option('share_counts_connect_check');
60
+
61
+ if (isset($disable_share_counts_api)) {
62
+ if (isset($share_counts_connect_check) && $share_counts_connect_check == 'SUCCESS' && $disable_share_counts_api != 'on') {
63
+ $share_buttons['get_share_counts'] = '%get_share_counts%';
64
+ }
65
+ }
66
+ return $share_buttons;
67
+ }
68
+
69
+ /**
70
+ * Get the mapping of function placeholder to function implementation
71
+ *
72
+ * This function will return a mapping of a function placeholder to
73
+ * the function implementation. This is necessary so that we can send
74
+ * functions along to the JS side since json_encode cannot encode functions
75
+ *
76
+ * @return array an associative array of function placeholder to function implementation
77
+ */
78
+ public static function get_function_definitions() {
79
+ return array(
80
+ '%get_share_counts%' => self::get_share_counts_function(),
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Get the share counts functions as a string
86
+ *
87
+ * @return string the stringified version of get_share_counts function
88
+ */
89
+ public static function get_share_counts_function() {
90
+ $ajax_url = admin_url('admin-ajax.php');
91
+ $share_counts_function = <<<DOC
92
+ function(url, services, cb) {
93
+ Shareaholic.Utils.ajax({
94
+ cache: true,
95
+ cache_ttl: '1 minute',
96
+ url: '$ajax_url',
97
+ data: { action: 'shareaholic_share_counts_api', url: url, services: services },
98
+ success: function(res) {
99
+ if(res && res.data) {
100
+ cb(res.data);
101
+ }
102
+ }
103
+ })
104
+ }
105
+ DOC;
106
+ return $share_counts_function;
107
+ }
108
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: shareaholic
3
  Tags: sexybookmarks, shareaholic, shareholic, facebook, twitter, linkedin, URL Shortener, bitly, tinyurl, Goo.gl, Google+1, Google Analytics, Google Plus, Google, Instapaper, Wish List, Digg, Gmail, Google Bookmarks, Translate, Tumblr, AIM, Yahoo Messenger, Delicious, StumbleUpon, mister wong, evernote, add this, addtoany, share this, sharethis, share and follow, share and enjoy, sharing is sexy, sharing is caring, yahoo, reddit, hackernews, tweet button, twitter button, fark, buffer, myspace, orkut, netlog, hubspot, weheartit, printfriendly, yammer, wanelo, pinterest, google translate, bookmarks, social, email button, social share, socialize, sociable, sharebar, bookmark button, share button, social bookmarking, bookmarks menu, bookmarking, share, seo, analytics, stats, sharing, facebook like, facebook recommend, WPMU, mutisite, shortcode, yaarp, yarpp, nrelate, outbrain, linkwithin, related content, related posts, related, popular posts, popular, thumbnails, recommendations
4
  Requires at least: 3.0
5
  Tested up to: 3.8.1
6
- Stable tag: 7.3.0.1
7
 
8
  Adds an attractive social bookmarking menu and related content widget to your posts, pages, index, or any combination of the three.
9
 
@@ -155,6 +155,11 @@ Please see here: [Usage & Installation Instructions](http://support.shareaholic.
155
 
156
  == Changelog ==
157
 
 
 
 
 
 
158
  = 7.3.0.1 =
159
  * Miscellaneous bug fixes and performance enhancements
160
 
@@ -1036,6 +1041,10 @@ Please see here: [Usage & Installation Instructions](http://support.shareaholic.
1036
 
1037
  == Upgrade Notice ==
1038
 
 
 
 
 
1039
  = 7.3.0.1 =
1040
  Miscellaneous bug fixes and performance enhancements
1041
 
3
  Tags: sexybookmarks, shareaholic, shareholic, facebook, twitter, linkedin, URL Shortener, bitly, tinyurl, Goo.gl, Google+1, Google Analytics, Google Plus, Google, Instapaper, Wish List, Digg, Gmail, Google Bookmarks, Translate, Tumblr, AIM, Yahoo Messenger, Delicious, StumbleUpon, mister wong, evernote, add this, addtoany, share this, sharethis, share and follow, share and enjoy, sharing is sexy, sharing is caring, yahoo, reddit, hackernews, tweet button, twitter button, fark, buffer, myspace, orkut, netlog, hubspot, weheartit, printfriendly, yammer, wanelo, pinterest, google translate, bookmarks, social, email button, social share, socialize, sociable, sharebar, bookmark button, share button, social bookmarking, bookmarks menu, bookmarking, share, seo, analytics, stats, sharing, facebook like, facebook recommend, WPMU, mutisite, shortcode, yaarp, yarpp, nrelate, outbrain, linkwithin, related content, related posts, related, popular posts, popular, thumbnails, recommendations
4
  Requires at least: 3.0
5
  Tested up to: 3.8.1
6
+ Stable tag: 7.4.0.0
7
 
8
  Adds an attractive social bookmarking menu and related content widget to your posts, pages, index, or any combination of the three.
9
 
155
 
156
  == Changelog ==
157
 
158
+ = 7.4.0.0 =
159
+ * Share Buttons App
160
+ * Share Counts for Google+, Reddit, StumbleUpon, VK, Buffer, etc! This release features an optional and all new server side Share Counts API. Toggle this option under the "Advanced Settings" section.
161
+ * Major performance upgrade and speed boost! Your pages will load faster for your visitors as share count lookups are now consolidated to one single HTTP request per page load (vs a call for each sharing service). The share counts are also heavily cached on both the client and server for super fast lookups and page performance.
162
+
163
  = 7.3.0.1 =
164
  * Miscellaneous bug fixes and performance enhancements
165
 
1041
 
1042
  == Upgrade Notice ==
1043
 
1044
+ = 7.4.0.0 =
1045
+
1046
+ * Optional and all new server side Share Counts API for share counts for Google+, StumbleUpon, etc! You can toggle this option under the "Advanced Settings" section.
1047
+
1048
  = 7.3.0.1 =
1049
  Miscellaneous bug fixes and performance enhancements
1050
 
shareaholic.php CHANGED
@@ -3,14 +3,14 @@
3
  * The main file!
4
  *
5
  * @package shareaholic
6
- * @version 7.3.0.1
7
  */
8
 
9
  /*
10
  Plugin Name: Shareaholic | share buttons, analytics, related content
11
  Plugin URI: https://shareaholic.com/publishers/
12
  Description: Whether you want to get people sharing, grow your fans, make money, or know who's reading your content, Shareaholic will help you get it done. See <a href="admin.php?page=shareaholic-settings">configuration panel</a> for more settings.
13
- Version: 7.3.0.1
14
  Author: Shareaholic
15
  Author URI: https://shareaholic.com
16
  Text Domain: shareaholic
@@ -36,6 +36,10 @@ Credits & Thanks: https://shareaholic.com/tools/wordpress/credits
36
  define('SHAREAHOLIC_DIR', dirname(__FILE__));
37
  define('SHAREAHOLIC_ASSET_DIR', plugins_url( '/assets/' , __FILE__ ));
38
 
 
 
 
 
39
  // because define can use function returns and const can't
40
  define('SHAREAHOLIC_DEBUG', getenv('SHAREAHOLIC_DEBUG'));
41
 
@@ -57,7 +61,7 @@ class Shareaholic {
57
  const CM_API_URL = 'https://cm-web.shareaholic.com'; // uses static IPs for firewall whitelisting
58
  const REC_API_URL = 'http://recommendations.shareaholic.com';
59
 
60
- const VERSION = '7.3.0.1';
61
 
62
  /**
63
  * Starts off as false so that ::get_instance() returns
@@ -70,6 +74,10 @@ class Shareaholic {
70
  */
71
  private function __construct() {
72
  add_action('wp_ajax_shareaholic_accept_terms_of_service', array('ShareaholicUtilities', 'accept_terms_of_service'));
 
 
 
 
73
 
74
  add_action('init', array('ShareaholicPublic', 'init'));
75
  add_action('the_content', array('ShareaholicPublic', 'draw_canvases'));
@@ -85,7 +93,7 @@ class Shareaholic {
85
  add_action('save_post', array('ShareaholicAdmin', 'save_post'));
86
  add_action('admin_enqueue_scripts', array('ShareaholicAdmin', 'enqueue_scripts'));
87
  add_action('admin_menu', array('ShareaholicAdmin', 'admin_menu'));
88
-
89
  if (!ShareaholicUtilities::has_accepted_terms_of_service()) {
90
  add_action('admin_notices', array('ShareaholicAdmin', 'show_terms_of_service'));
91
  }
@@ -99,16 +107,13 @@ class Shareaholic {
99
  add_action('publish_page', array('ShareaholicUtilities', 'notify_content_manager_singlepage'));
100
  }
101
  add_action('trashed_post', array('ShareaholicUtilities', 'notify_content_manager_singlepage'));
 
102
  register_activation_hook(__FILE__, array($this, 'after_activation'));
103
  register_deactivation_hook( __FILE__, array($this, 'deactivate'));
104
  register_uninstall_hook(__FILE__, array('Shareaholic', 'uninstall'));
105
 
106
  add_action('wp_before_admin_bar_render', array('ShareaholicUtilities', 'admin_bar_extended'));
107
  add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'ShareaholicUtilities::admin_plugin_action_links', -10);
108
-
109
- // add action for share counts API call
110
- add_action('wp_ajax_nopriv_shareaholic_share_counts_api', array($this, 'shareaholic_share_counts_api'));
111
- add_action('wp_ajax_shareaholic_share_counts_api', array($this, 'shareaholic_share_counts_api'));
112
  }
113
 
114
  /**
@@ -159,6 +164,10 @@ class Shareaholic {
159
  ShareaholicUtilities::perform_update();
160
  ShareaholicUtilities::set_version(self::VERSION);
161
  ShareaholicUtilities::notify_content_manager_singledomain();
 
 
 
 
162
  }
163
  }
164
  }
@@ -181,7 +190,10 @@ class Shareaholic {
181
  public function after_activation() {
182
  $this->terms_of_service();
183
  ShareaholicUtilities::log_event("Activate");
184
-
 
 
 
185
  if (ShareaholicUtilities::has_accepted_terms_of_service() && ShareaholicUtilities::get_option('api_key') != NULL){
186
  ShareaholicUtilities::notify_content_manager_singledomain();
187
  }
@@ -205,13 +217,6 @@ class Shareaholic {
205
  ShareaholicUtilities::log_event("Uninstall");
206
  delete_option('shareaholic_settings');
207
  }
208
-
209
- /**
210
- * This function handles the API request to get the share counts
211
- */
212
- public function shareaholic_share_counts_api() {
213
- ShareaholicPublic::share_counts_api();
214
- }
215
  }
216
 
217
  // the magic
3
  * The main file!
4
  *
5
  * @package shareaholic
6
+ * @version 7.4.0.0
7
  */
8
 
9
  /*
10
  Plugin Name: Shareaholic | share buttons, analytics, related content
11
  Plugin URI: https://shareaholic.com/publishers/
12
  Description: Whether you want to get people sharing, grow your fans, make money, or know who's reading your content, Shareaholic will help you get it done. See <a href="admin.php?page=shareaholic-settings">configuration panel</a> for more settings.
13
+ Version: 7.4.0.0
14
  Author: Shareaholic
15
  Author URI: https://shareaholic.com
16
  Text Domain: shareaholic
36
  define('SHAREAHOLIC_DIR', dirname(__FILE__));
37
  define('SHAREAHOLIC_ASSET_DIR', plugins_url( '/assets/' , __FILE__ ));
38
 
39
+ // Caching
40
+ if( !defined( 'SHARE_COUNTS_CHECK_CACHE_LENGTH' ) ) define( 'SHARE_COUNTS_CHECK_CACHE_LENGTH', 60 ); // 60 seconds
41
+ if( !defined( 'RECOMMENDATIONS_STATUS_CHECK_CACHE_LENGTH' ) ) define( 'RECOMMENDATIONS_STATUS_CHECK_CACHE_LENGTH', 60 ); // 60 seconds
42
+
43
  // because define can use function returns and const can't
44
  define('SHAREAHOLIC_DEBUG', getenv('SHAREAHOLIC_DEBUG'));
45
 
61
  const CM_API_URL = 'https://cm-web.shareaholic.com'; // uses static IPs for firewall whitelisting
62
  const REC_API_URL = 'http://recommendations.shareaholic.com';
63
 
64
+ const VERSION = '7.4.0.0';
65
 
66
  /**
67
  * Starts off as false so that ::get_instance() returns
74
  */
75
  private function __construct() {
76
  add_action('wp_ajax_shareaholic_accept_terms_of_service', array('ShareaholicUtilities', 'accept_terms_of_service'));
77
+
78
+ // Share Counts API
79
+ add_action('wp_ajax_nopriv_shareaholic_share_counts_api', array('ShareaholicPublic', 'share_counts_api'));
80
+ add_action('wp_ajax_shareaholic_share_counts_api', array('ShareaholicPublic', 'share_counts_api'));
81
 
82
  add_action('init', array('ShareaholicPublic', 'init'));
83
  add_action('the_content', array('ShareaholicPublic', 'draw_canvases'));
93
  add_action('save_post', array('ShareaholicAdmin', 'save_post'));
94
  add_action('admin_enqueue_scripts', array('ShareaholicAdmin', 'enqueue_scripts'));
95
  add_action('admin_menu', array('ShareaholicAdmin', 'admin_menu'));
96
+
97
  if (!ShareaholicUtilities::has_accepted_terms_of_service()) {
98
  add_action('admin_notices', array('ShareaholicAdmin', 'show_terms_of_service'));
99
  }
107
  add_action('publish_page', array('ShareaholicUtilities', 'notify_content_manager_singlepage'));
108
  }
109
  add_action('trashed_post', array('ShareaholicUtilities', 'notify_content_manager_singlepage'));
110
+
111
  register_activation_hook(__FILE__, array($this, 'after_activation'));
112
  register_deactivation_hook( __FILE__, array($this, 'deactivate'));
113
  register_uninstall_hook(__FILE__, array('Shareaholic', 'uninstall'));
114
 
115
  add_action('wp_before_admin_bar_render', array('ShareaholicUtilities', 'admin_bar_extended'));
116
  add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'ShareaholicUtilities::admin_plugin_action_links', -10);
 
 
 
 
117
  }
118
 
119
  /**
164
  ShareaholicUtilities::perform_update();
165
  ShareaholicUtilities::set_version(self::VERSION);
166
  ShareaholicUtilities::notify_content_manager_singledomain();
167
+ // Call the share counts api to check for connectivity on update
168
+ if (has_action('wp_ajax_nopriv_shareaholic_share_counts_api') && has_action('wp_ajax_shareaholic_share_counts_api')) {
169
+ ShareaholicUtilities::share_counts_api_connectivity_check();
170
+ }
171
  }
172
  }
173
  }
190
  public function after_activation() {
191
  $this->terms_of_service();
192
  ShareaholicUtilities::log_event("Activate");
193
+
194
+ // workaround: http://codex.wordpress.org/Function_Reference/register_activation_hook
195
+ add_option( 'Activated_Plugin_Shareaholic', 'shareaholic' );
196
+
197
  if (ShareaholicUtilities::has_accepted_terms_of_service() && ShareaholicUtilities::get_option('api_key') != NULL){
198
  ShareaholicUtilities::notify_content_manager_singledomain();
199
  }
217
  ShareaholicUtilities::log_event("Uninstall");
218
  delete_option('shareaholic_settings');
219
  }
 
 
 
 
 
 
 
220
  }
221
 
222
  // the magic
templates/advanced_settings.php CHANGED
@@ -29,7 +29,12 @@
29
  <?php echo ($settings['disable_admin_bar_menu'] == 'on' ? 'checked' : '') ?>
30
  <?php } ?>>
31
  <label style="display: inline-block; font-size:12px;" for="admin_bar"><?php echo sprintf(__('Disable Admin Bar Menu', 'shareaholic')); ?></label>
32
-
 
 
 
 
 
33
  <div class='clear' style="padding-top:10px;"></div>
34
  <input type='submit' onclick="this.value='<?php echo sprintf(__('Saving Changes...', 'shareaholic')); ?>';" value='<?php echo sprintf(__('Save Changes', 'shareaholic')); ?>'>
35
  </fieldset>
@@ -47,6 +52,13 @@
47
  <span class="key-status failed"><?php _e('Unable to reach any Shareaholic server', 'shareaholic'); ?></span> <a href="#" onClick="window.location.reload(); this.innerHTML='<?php _e('Checking...', 'shareaholic'); ?>';"><?php _e('Re-check', 'shareaholic'); ?></a>
48
  <div class="key-description"><?php echo sprintf( __('A network problem or firewall is blocking all connections from your web server to Shareaholic.com. <strong>Shareaholic cannot work correctly until this is fixed.</strong> Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Shareaholic and firewalls</a>. Let us <a href="#" onclick="%s">know</a> too, so we can follow up!'), 'http://blog.shareaholic.com/shareaholic-hosting-faq/', 'SnapEngage.startLink();','</a>'); ?></div>
49
  <?php } ?>
 
 
 
 
 
 
 
50
  </fieldset>
51
 
52
  <div class='clear'></div>
29
  <?php echo ($settings['disable_admin_bar_menu'] == 'on' ? 'checked' : '') ?>
30
  <?php } ?>>
31
  <label style="display: inline-block; font-size:12px;" for="admin_bar"><?php echo sprintf(__('Disable Admin Bar Menu', 'shareaholic')); ?></label>
32
+ <br/>
33
+ <input type='checkbox' id='share_counts' name='shareaholic[disable_internal_share_counts_api]' class='check'
34
+ <?php if (isset($settings['disable_internal_share_counts_api'])) { ?>
35
+ <?php echo ($settings['disable_internal_share_counts_api'] == 'on' ? 'checked' : '') ?>
36
+ <?php } ?>>
37
+ <label style="display: inline-block; font-size:12px;" for="share_counts"><?php echo sprintf(__('Disable server-side Share Counts API', 'shareaholic')); ?> <?php echo sprintf(__('(unless there are issues with calling the service, it is recommended NOT to disable this API)', 'shareaholic')); ?></label>
38
  <div class='clear' style="padding-top:10px;"></div>
39
  <input type='submit' onclick="this.value='<?php echo sprintf(__('Saving Changes...', 'shareaholic')); ?>';" value='<?php echo sprintf(__('Save Changes', 'shareaholic')); ?>'>
40
  </fieldset>
52
  <span class="key-status failed"><?php _e('Unable to reach any Shareaholic server', 'shareaholic'); ?></span> <a href="#" onClick="window.location.reload(); this.innerHTML='<?php _e('Checking...', 'shareaholic'); ?>';"><?php _e('Re-check', 'shareaholic'); ?></a>
53
  <div class="key-description"><?php echo sprintf( __('A network problem or firewall is blocking all connections from your web server to Shareaholic.com. <strong>Shareaholic cannot work correctly until this is fixed.</strong> Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Shareaholic and firewalls</a>. Let us <a href="#" onclick="%s">know</a> too, so we can follow up!'), 'http://blog.shareaholic.com/shareaholic-hosting-faq/', 'SnapEngage.startLink();','</a>'); ?></div>
54
  <?php } ?>
55
+ <?php if (ShareaholicUtilities::share_counts_api_connectivity_check() == 'SUCCESS') { ?>
56
+ <span class="key-status passed"><?php _e('Server-side Share Counts API is reachable', 'shareaholic'); ?></span>
57
+ <div class="key-description"><?php _e('The server-side Share Counts API should be working correctly.', 'shareaholic'); ?> <?php _e('All servers and services needed by the API are accessible.', 'shareaholic'); ?></div>
58
+ <?php } else { // can't connect to any server ?>
59
+ <span class="key-status failed"><?php _e('Unable to reach the server-side Share Count API', 'shareaholic'); ?></span> <a href="#" onClick="window.location.reload(); this.innerHTML='<?php _e('Checking...', 'shareaholic'); ?>';"><?php _e('Re-check', 'shareaholic'); ?></a>
60
+ <div class="key-description"><?php echo sprintf( __('A network problem or firewall is blocking connections from your web server to various Share Count APIs. <strong>The API cannot work correctly until this is fixed.</strong> If you continue to face this issue, please contact <a href="#" onclick="%s">us</a> and we will follow up! In the meantime, if you disable the server-side Share Counts API from the Advanced options above, Shareaholic will default to using client-side APIs for share counts successfully -- so nothing to worry about!'), 'SnapEngage.startLink();'); ?></div>
61
+ <?php } ?>
62
  </fieldset>
63
 
64
  <div class='clear'></div>
templates/script_tag.php CHANGED
@@ -10,7 +10,8 @@
10
  var rs = this.readyState;
11
  if (rs && rs != 'complete' && rs != 'loaded') return;
12
  var site_id = '<?php echo $api_key; ?>';
13
- try { Shareaholic.init(site_id); } catch (e) {}
 
14
  };
15
  var s = document.getElementsByTagName('script')[0];
16
  s.parentNode.insertBefore(shr, s);
10
  var rs = this.readyState;
11
  if (rs && rs != 'complete' && rs != 'loaded') return;
12
  var site_id = '<?php echo $api_key; ?>';
13
+ var page_config = <?php echo $page_config; ?>;
14
+ try { Shareaholic.init(site_id, page_config); } catch (e) {}
15
  };
16
  var s = document.getElementsByTagName('script')[0];
17
  s.parentNode.insertBefore(shr, s);
utilities.php CHANGED
@@ -7,6 +7,7 @@
7
 
8
  require_once(SHAREAHOLIC_DIR . '/curl.php');
9
  require_once(SHAREAHOLIC_DIR . '/six_to_seven.php');
 
10
 
11
  /**
12
  * This class is just a holder for general functions that have
@@ -78,6 +79,7 @@ class ShareaholicUtilities {
78
  return array(
79
  'disable_tracking' => 'off',
80
  'disable_admin_bar_menu' => 'off',
 
81
  'api_key' => '',
82
  'verification_key' => '',
83
  );
@@ -561,8 +563,17 @@ class ShareaholicUtilities {
561
  if (!self::is_locked('get_or_create_api_key')) {
562
  self::set_lock('get_or_create_api_key');
563
 
 
 
564
  delete_option('shareaholic_settings');
565
 
 
 
 
 
 
 
 
566
  $verification_key = md5(mt_rand());
567
 
568
  $turned_on_share_buttons_locations = array(
@@ -652,6 +663,7 @@ class ShareaholicUtilities {
652
  );
653
 
654
  ShareaholicUtilities::turn_on_locations($turn_on, $turn_off);
 
655
  } else {
656
  ShareaholicUtilities::log_bad_response('FailedToCreateApiKey', $response);
657
  }
@@ -971,6 +983,69 @@ class ShareaholicUtilities {
971
  }
972
  }
973
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
974
  /**
975
  * This is a wrapper for the Recommendations API
976
  *
@@ -978,7 +1053,16 @@ class ShareaholicUtilities {
978
  public static function recommendations_status_check() {
979
  if (self::get_option('api_key') != NULL){
980
  $recommendations_url = Shareaholic::REC_API_URL . "/v3/recommend?url=" . urlencode(get_bloginfo('url')) . "&internal=6&sponsored=3&apiKey=" . self::get_option('api_key');
981
- $response = ShareaholicCurl::get($recommendations_url);
 
 
 
 
 
 
 
 
 
982
  if(is_array($response) && array_key_exists('response', $response)) {
983
  $body = $response['response'];
984
  if (is_array($body) && $body['code'] == 200) {
@@ -992,4 +1076,3 @@ class ShareaholicUtilities {
992
  }
993
  }
994
  }
995
- ?>
7
 
8
  require_once(SHAREAHOLIC_DIR . '/curl.php');
9
  require_once(SHAREAHOLIC_DIR . '/six_to_seven.php');
10
+ require_once(SHAREAHOLIC_DIR . '/lib/social-share-counts/seq_share_count.php');
11
 
12
  /**
13
  * This class is just a holder for general functions that have
79
  return array(
80
  'disable_tracking' => 'off',
81
  'disable_admin_bar_menu' => 'off',
82
+ 'disable_internal_share_counts_api' => 'off',
83
  'api_key' => '',
84
  'verification_key' => '',
85
  );
563
  if (!self::is_locked('get_or_create_api_key')) {
564
  self::set_lock('get_or_create_api_key');
565
 
566
+ $old_settings = self::get_settings();
567
+
568
  delete_option('shareaholic_settings');
569
 
570
+ // restore any old settings that should be preserved between resets
571
+ if (isset($old_settings['share_counts_connect_check'])) {
572
+ self::update_options(array(
573
+ 'share_counts_connect_check' => $old_settings['share_counts_connect_check'],
574
+ ));
575
+ }
576
+
577
  $verification_key = md5(mt_rand());
578
 
579
  $turned_on_share_buttons_locations = array(
663
  );
664
 
665
  ShareaholicUtilities::turn_on_locations($turn_on, $turn_off);
666
+
667
  } else {
668
  ShareaholicUtilities::log_bad_response('FailedToCreateApiKey', $response);
669
  }
983
  }
984
  }
985
 
986
+ /**
987
+ * Share Counts API Connectivity check
988
+ *
989
+ */
990
+ public static function share_counts_api_connectivity_check() {
991
+
992
+ // if we already checked and it is successful, then do not call the API again
993
+ $share_counts_connect_check = self::get_option('share_counts_connect_check');
994
+ if (isset($share_counts_connect_check) && $share_counts_connect_check == 'SUCCESS') {
995
+ return $share_counts_connect_check;
996
+ }
997
+
998
+ $services_config = ShareaholicSeqShareCount::get_services_config();
999
+ $services = array_keys($services_config);
1000
+ $param_string = implode('&services[]=', $services);
1001
+ $share_counts_api_url = admin_url('admin-ajax.php') . '?action=shareaholic_share_counts_api&url=https%3A%2F%2Fblog.shareaholic.com%2F&services[]=' . $param_string;
1002
+ $cache_key = 'share_counts_api_connectivity_check';
1003
+
1004
+ $response = get_transient($cache_key);
1005
+ if (!$response) {
1006
+ $response = ShareaholicCurl::get($share_counts_api_url);
1007
+ }
1008
+
1009
+ $response_status = self::get_share_counts_api_status($response);
1010
+ // if this was the first time we are doing this and it failed, disable
1011
+ // the share counts API
1012
+ if (empty($share_counts_connect_check) && $response_status == 'FAIL') {
1013
+ self::update_options(array('disable_internal_share_counts_api' => 'on'));
1014
+ }
1015
+
1016
+ if ($response_status == 'SUCCESS') {
1017
+ set_transient( $cache_key, $response, SHARE_COUNTS_CHECK_CACHE_LENGTH );
1018
+ }
1019
+
1020
+ self::update_options(array('share_counts_connect_check' => $response_status));
1021
+ return $response_status;
1022
+ }
1023
+
1024
+ /**
1025
+ * Check the share counts API for empty response or missing services
1026
+ */
1027
+ public static function get_share_counts_api_status($response) {
1028
+ if (!$response || !isset($response['body']) || !is_array($response['body']) || !isset($response['body']['data'])) {
1029
+ return 'FAIL';
1030
+ }
1031
+
1032
+ // Did it return at least 8 services?
1033
+ $has_majority_services = count(array_keys($response['body']['data'])) >= 8 ? true : false;
1034
+ $has_important_services = true;
1035
+ // Does it have counts for twtr, fb, linkedin, pinterest, and delicious?
1036
+ foreach (array('twitter', 'facebook', 'linkedin', 'pinterest', 'delicious') as $service) {
1037
+ if (!isset($response['body']['data'][$service]) || !is_numeric($response['body']['data'][$service])) {
1038
+ $has_important_services = false;
1039
+ }
1040
+ }
1041
+
1042
+ if (!$has_majority_services || !$has_important_services) {
1043
+ return 'FAIL';
1044
+ }
1045
+
1046
+ return 'SUCCESS';
1047
+ }
1048
+
1049
  /**
1050
  * This is a wrapper for the Recommendations API
1051
  *
1053
  public static function recommendations_status_check() {
1054
  if (self::get_option('api_key') != NULL){
1055
  $recommendations_url = Shareaholic::REC_API_URL . "/v3/recommend?url=" . urlencode(get_bloginfo('url')) . "&internal=6&sponsored=3&apiKey=" . self::get_option('api_key');
1056
+ $cache_key = 'recommendations_status_check-' . md5( $recommendations_url );
1057
+
1058
+ $response = get_transient($cache_key);
1059
+ if (!$response){
1060
+ $response = ShareaholicCurl::get($recommendations_url);
1061
+ if( !is_wp_error( $response ) ) {
1062
+ set_transient( $cache_key, $response, RECOMMENDATIONS_STATUS_CHECK_CACHE_LENGTH );
1063
+ }
1064
+ }
1065
+
1066
  if(is_array($response) && array_key_exists('response', $response)) {
1067
  $body = $response['response'];
1068
  if (is_array($body) && $body['code'] == 200) {
1076
  }
1077
  }
1078
  }