Instagram Feed - Version 2.5.3

Version Description

  • Fix: Fixed an issue caused by an unannounced Instagram API change affecting thumbnails in certain video posts which don't have image data available in the API.
  • Fix: Added oEmbed account info to the plugin "System Info" to make debugging easier.
Download this release

Release Info

Developer smashballoon
Plugin Icon 128x128 Instagram Feed
Version 2.5.3
Comparing to
See all releases

Code changes from version 2.5.2 to 2.5.3

README.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: smashballoon, craig-at-smash-balloon
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
  Requires at least: 3.4
5
  Tested up to: 5.5
6
- Stable tag: 2.5.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -331,6 +331,10 @@ We understand that sometimes you need help, have issues or just have questions.
331
  * Plus more customization options added all the time!
332
 
333
  == Changelog ==
 
 
 
 
334
  = 2.5.2 =
335
  * Fix: Fixed an issue with an Instagram API change causing some images not to display if the image resizing feature was disabled.
336
 
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
  Requires at least: 3.4
5
  Tested up to: 5.5
6
+ Stable tag: 2.5.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
331
  * Plus more customization options added all the time!
332
 
333
  == Changelog ==
334
+ = 2.5.3 =
335
+ * Fix: Fixed an issue caused by an unannounced Instagram API change affecting thumbnails in certain video posts which don't have image data available in the API.
336
+ * Fix: Added oEmbed account info to the plugin "System Info" to make debugging easier.
337
+
338
  = 2.5.2 =
339
  * Fix: Fixed an issue with an Instagram API change causing some images not to display if the image resizing feature was disabled.
340
 
img/thumb-placeholder.png ADDED
Binary file
inc/admin/main.php CHANGED
@@ -3198,13 +3198,13 @@ endif;
3198
  $error_page = $sb_instagram_posts_manager->get_error_page();
3199
  if ( $error_page ) {
3200
  echo 'Feed with error: ' . esc_url( get_the_permalink( $error_page ) ). "\n";
3201
- }
3202
- $ajax_statuses = $sb_instagram_posts_manager->get_ajax_status();
3203
- if ( ! $ajax_statuses['successful'] ) {
3204
- ?>
3205
- ## AJAX Status ##
3206
- <?php
3207
- echo 'test not successful';
3208
  }
3209
  ?>
3210
  </textarea>
3198
  $error_page = $sb_instagram_posts_manager->get_error_page();
3199
  if ( $error_page ) {
3200
  echo 'Feed with error: ' . esc_url( get_the_permalink( $error_page ) ). "\n";
3201
+ }?>
3202
+
3203
+ ## oEmbed: ##
3204
+ <?php
3205
+ $oembed_token_settings = get_option( 'sbi_oembed_token', array() );
3206
+ foreach( $oembed_token_settings as $key => $value ) {
3207
+ echo $key . ': ' . esc_attr( $value ) . "\n";
3208
  }
3209
  ?>
3210
  </textarea>
inc/class-sb-instagram-parse.php CHANGED
@@ -102,27 +102,59 @@ class SB_Instagram_Parse
102
  */
103
  public static function get_media_url( $post, $resolution = 'lightbox' ) {
104
  $account_type = isset( $post['images'] ) ? 'personal' : 'business';
 
105
 
106
  if ( $account_type === 'personal' ) {
107
  return $post['images']['standard_resolution']['url'];
108
  } else {
109
- if ($post['media_type'] === 'CAROUSEL_ALBUM' || $post['media_type'] === 'VIDEO') {
 
 
110
  if ( isset( $post['thumbnail_url'] ) ) {
111
  return $post['thumbnail_url'];
112
- } elseif ( $post['media_type'] === 'CAROUSEL_ALBUM' && isset( $post['media_url'] ) ) {
113
  return $post['media_url'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  } else {
 
 
 
 
115
  $permalink = SB_Instagram_Parse::fix_permalink( SB_Instagram_Parse::get_permalink( $post ) );
 
 
 
 
 
 
 
 
 
116
 
117
- return $permalink . 'media/?size=l';
118
  }
119
  } else {
120
  if ( isset( $post['media_url'] ) ) {
121
  return $post['media_url'];
122
  }
123
- $permalink = SB_Instagram_Parse::fix_permalink( SB_Instagram_Parse::get_permalink( $post ) );
124
 
125
- return $permalink . 'media/?size=l';
126
  }
127
  }
128
 
102
  */
103
  public static function get_media_url( $post, $resolution = 'lightbox' ) {
104
  $account_type = isset( $post['images'] ) ? 'personal' : 'business';
105
+ $media_type = isset( $post['media_type'] ) ? $post['media_type'] : 'none';
106
 
107
  if ( $account_type === 'personal' ) {
108
  return $post['images']['standard_resolution']['url'];
109
  } else {
110
+ if ( $media_type === 'CAROUSEL_ALBUM'
111
+ || $media_type === 'VIDEO'
112
+ || $media_type === 'OEMBED' ) {
113
  if ( isset( $post['thumbnail_url'] ) ) {
114
  return $post['thumbnail_url'];
115
+ } elseif ( $media_type === 'CAROUSEL_ALBUM' && isset( $post['media_url'] ) ) {
116
  return $post['media_url'];
117
+ } elseif ( isset( $post['children'] ) ) {
118
+ $i = 0;
119
+ $full_size = '';
120
+ foreach ( $post['children']['data'] as $carousel_item ) {
121
+ if ( $carousel_item['media_type'] === 'IMAGE' && empty( $full_size ) ) {
122
+ if ( isset( $carousel_item['media_url'] ) ) {
123
+ $full_size = $carousel_item['media_url'];
124
+ }
125
+ } elseif ( $carousel_item['media_type'] === 'VIDEO' && empty( $full_size ) ) {
126
+ if ( isset( $carousel_item['thumbnail_url'] ) ) {
127
+ $full_size = $carousel_item['thumbnail_url'];
128
+ }
129
+ }
130
+
131
+ $i++;
132
+ }
133
+ return $full_size;
134
  } else {
135
+ if ( ! class_exists( 'SB_Instagram_Single' ) ) {
136
+ return trailingslashit( SBI_PLUGIN_URL ) . 'img/thumb-placeholder.png';
137
+ }
138
+ //attempt to get
139
  $permalink = SB_Instagram_Parse::fix_permalink( SB_Instagram_Parse::get_permalink( $post ) );
140
+ $single = new SB_Instagram_Single( $permalink );
141
+ $single->init();
142
+ $post = $single->get_post();
143
+
144
+ if ( isset( $post['thumbnail_url'] ) ) {
145
+ return $post['thumbnail_url'];
146
+ } elseif ( isset( $post['media_url'] ) && strpos( $post['media_url'], '.mp4' ) === false ) {
147
+ return $post['media_url'];
148
+ }
149
 
150
+ return trailingslashit( SBI_PLUGIN_URL ) . 'img/thumb-placeholder.png';
151
  }
152
  } else {
153
  if ( isset( $post['media_url'] ) ) {
154
  return $post['media_url'];
155
  }
 
156
 
157
+ return trailingslashit( SBI_PLUGIN_URL ) . 'img/thumb-placeholder.png';
158
  }
159
  }
160
 
inc/class-sb-instagram-post.php CHANGED
@@ -217,6 +217,9 @@ class SB_Instagram_Post
217
  } else {
218
  $file_name = isset( $image_source_set[ $image_size ] ) ? $image_source_set[ $image_size ] : SB_Instagram_Parse::get_media_url( $this->instagram_api_data, 'lightbox' );
219
  }
 
 
 
220
  if ( ! empty( $file_name ) ) {
221
 
222
  $sizes = array(
217
  } else {
218
  $file_name = isset( $image_source_set[ $image_size ] ) ? $image_source_set[ $image_size ] : SB_Instagram_Parse::get_media_url( $this->instagram_api_data, 'lightbox' );
219
  }
220
+ if ( strpos( $file_name, 'placeholder' ) !== false ) {
221
+ $file_name = '';
222
+ }
223
  if ( ! empty( $file_name ) ) {
224
 
225
  $sizes = array(
inc/class-sb-instagram-single.php ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Single
4
+ *
5
+ * Uses oEmbeds to get data about single Instagram posts
6
+ *
7
+ * @since 2.5.3/5.8.3
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ die( '-1' );
12
+ }
13
+
14
+ class SB_Instagram_Single
15
+ {
16
+ /**
17
+ * @var string
18
+ */
19
+ private $permalink;
20
+
21
+ /**
22
+ * @var string
23
+ */
24
+ private $permalink_id;
25
+
26
+ /**
27
+ * @var array
28
+ */
29
+ private $post;
30
+
31
+ /**
32
+ * SB_Instagram_Single constructor.
33
+ *
34
+ * @param $permalink_or_permalink_id string
35
+ */
36
+ public function __construct( $permalink_or_permalink_id ) {
37
+ if ( strpos( $permalink_or_permalink_id, 'http' ) !== false ) {
38
+ $this->permalink = $permalink_or_permalink_id;
39
+ $exploded_permalink = explode( '/', $permalink_or_permalink_id );
40
+ $permalink_id = $exploded_permalink[4];
41
+
42
+ $this->permalink_id = $permalink_id;
43
+ } else {
44
+ $this->permalink_id = $permalink_or_permalink_id;
45
+ $this->permalink = 'https://www.instagram.com/p/' . $this->permalink_id;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Sets post data from cache or fetches new data
51
+ * if it doesn't exist or hasn't been updated recently
52
+ *
53
+ * @since 2.5.3/5.8.3
54
+ */
55
+ public function init() {
56
+ $this->post = $this->maybe_saved_data();
57
+
58
+ if ( empty( $this->post )
59
+ || ! $this->was_recently_updated() ) {
60
+
61
+ if ( ! $this->should_delay_oembed_request() ) {
62
+
63
+ $data = $this->fetch();
64
+ if ( ! empty( $data ) ) {
65
+ $data = $this->parse_and_restructure( $data );
66
+ $this->post = $data;
67
+ $this->update_last_update_timestamp();
68
+ $this->update_single_cache();
69
+ } elseif ( $data === false ) {
70
+ $this->add_oembed_request_delay();
71
+ }
72
+
73
+ }
74
+
75
+ }
76
+ }
77
+
78
+ /**
79
+ * @return array
80
+ *
81
+ * @since 2.5.3/5.8.3
82
+ */
83
+ public function get_post() {
84
+ return $this->post;
85
+ }
86
+
87
+ /**
88
+ * Image URLs expire so this will compare when the data
89
+ * was last updated from the API
90
+ *
91
+ * @return bool
92
+ *
93
+ * @since 2.5.3/5.8.3
94
+ */
95
+ public function was_recently_updated() {
96
+ if ( ! isset( $this->post['last_update'] ) ) {
97
+ return false;
98
+ }
99
+
100
+ return (time() - 14 * DAY_IN_SECONDS) < $this->post['last_update'];
101
+ }
102
+
103
+
104
+ /**
105
+ * Makes an HTTP request for fresh data from the oembed
106
+ * endpoint. Returns false if no new data or there isn't
107
+ * a business access token found.
108
+ *
109
+ * @return bool|mixed|null
110
+ *
111
+ * @since 2.5.3/5.8.3
112
+ */
113
+ public function fetch() {
114
+ // need a connected business account for this to work
115
+ $access_token = SB_Instagram_Oembed::last_access_token();
116
+
117
+ if ( empty( $access_token ) ) {
118
+ return false;
119
+ }
120
+
121
+ $url = SB_Instagram_Oembed::oembed_url();
122
+
123
+ $fetch_url = add_query_arg( array(
124
+ 'url' => $this->permalink,
125
+ 'access_token' => $access_token ), $url );
126
+
127
+ $result = wp_remote_get( esc_url_raw( $fetch_url ) );
128
+
129
+ $data = false;
130
+ if ( ! is_wp_error( $result ) ) {
131
+ $data = isset( $result['body'] ) ? json_decode( $result['body'], true ) : false;
132
+
133
+ if ( $data && isset( $data['error'] ) ) {
134
+ $this->add_oembed_request_delay();
135
+ $data = false;
136
+ }
137
+ }
138
+
139
+ return $data;
140
+ }
141
+
142
+ /**
143
+ * If there was a problem with the last oEmbed request, the plugin
144
+ * waits 5 minutes to try again to prevent burning out the access token
145
+ * or causing Instagram to throttle HTTP requests from the server
146
+ *
147
+ * @return bool
148
+ *
149
+ * @since 2.5.3/5.8.3
150
+ */
151
+ public function should_delay_oembed_request() {
152
+ return (get_transient( 'sbi_delay_oembeds_' . $this->permalink_id ) !== false);
153
+ }
154
+
155
+ /**
156
+ * If there's an error, API requests are delayed 5 minutes
157
+ * for the specific permalink/post
158
+ *
159
+ * @since 2.5.3/5.8.3
160
+ */
161
+ public function add_oembed_request_delay() {
162
+ set_transient( 'sbi_delay_oembeds_' . $this->permalink_id, true, 300 );
163
+ }
164
+
165
+ /**
166
+ * Track last API request due to some data expiring and
167
+ * needing to be refreshed
168
+ *
169
+ * @since 2.5.3/5.8.3
170
+ */
171
+ private function update_last_update_timestamp() {
172
+ $this->post['last_update'] = time();
173
+ }
174
+
175
+ /**
176
+ * Data retrieved with this method has it's own cache
177
+ *
178
+ * @since 2.5.3/5.8.3
179
+ */
180
+ private function update_single_cache() {
181
+ $stored_option = get_option( 'sbi_single_cache', array() );
182
+
183
+ $new = array( $this->permalink_id => $this->post );
184
+ $stored_option = array_merge( $new, $stored_option );
185
+ // only latest 400 posts
186
+ $stored_option = array_slice( $stored_option, 0, 400 );
187
+
188
+ update_option( 'sbi_single_cache', $stored_option, false );
189
+ }
190
+
191
+ /**
192
+ * Data is restructured to look like regular API data
193
+ * for ease of use with other plugin features
194
+ *
195
+ * @param $data array
196
+ *
197
+ * @return array
198
+ *
199
+ * @since 2.5.3/5.8.3
200
+ */
201
+ private function parse_and_restructure( $data ) {
202
+ // TODO: parse all of the available data for this post, currently just thumbnail
203
+
204
+ $return = array(
205
+ 'thumbnail_url' => '',
206
+ 'id'=> $this->permalink_id,
207
+ 'media_type' => 'OEMBED'
208
+ );
209
+
210
+ if ( ! empty( $data['thumbnail_url'] ) ) {
211
+ $return['thumbnail_url'] = $data['thumbnail_url'];
212
+ }
213
+
214
+ apply_filters( 'sbi_single_parse_and_restructure', $return );
215
+
216
+ return $return;
217
+ }
218
+
219
+ /**
220
+ * Returns whatever data exists or empty array
221
+ *
222
+ * @return array
223
+ *
224
+ * @since 2.5.3/5.8.3
225
+ */
226
+ private function maybe_saved_data() {
227
+ $stored_option = get_option( 'sbi_single_cache', array() );
228
+
229
+ $data = array();
230
+ if ( ! empty( $stored_option[ $this->permalink_id ] ) ) {
231
+ return $stored_option[ $this->permalink_id ];
232
+ } else {
233
+ $settings = get_option( 'sb_instagram_settings', array() );//
234
+
235
+ $resize_disabled = isset( $settings['sb_instagram_disable_resize'] ) && $settings['sb_instagram_disable_resize'] === 'on';
236
+
237
+ if ( ! $resize_disabled ) {
238
+ global $wpdb;
239
+
240
+ $posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
241
+
242
+ $results = $wpdb->get_col( $wpdb->prepare(
243
+ "SELECT json_data FROM $posts_table_name
244
+ WHERE instagram_id = %s
245
+ LIMIT 1", $this->permalink_id ) );
246
+ if ( isset( $results[0] ) ) {
247
+ $data = json_decode( $results[0], true );
248
+ }
249
+
250
+ }
251
+ }
252
+
253
+ return $data;
254
+ }
255
+ }
instagram-feed.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Smash Balloon Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
  Description: Display beautifully clean, customizable, and responsive Instagram feeds.
6
- Version: 2.5.2
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
@@ -23,7 +23,7 @@ along with this program; if not, write to the Free Software
23
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
  */
25
  if ( ! defined( 'SBIVER' ) ) {
26
- define( 'SBIVER', '2.5.2' );
27
  }
28
  // Db version.
29
  if ( ! defined( 'SBI_DBVERSION' ) ) {
@@ -103,6 +103,7 @@ if ( function_exists( 'sb_instagram_feed_init' ) ) {
103
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-post-set.php';
104
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-posts-manager.php';
105
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-settings.php';
 
106
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-token-refresher.php';
107
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/blocks/class-sbi-blocks.php';
108
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/class-sbi-tracking.php';
@@ -633,6 +634,8 @@ if ( function_exists( 'sb_instagram_feed_init' ) ) {
633
  delete_option( 'sbi_oembed_token' );
634
  delete_option( 'sbi_rating_notice' );
635
  delete_option( 'sbi_refresh_report' );
 
 
636
 
637
  global $wp_roles;
638
  $wp_roles->remove_cap( 'administrator', 'manage_instagram_feed_options' );
3
  Plugin Name: Smash Balloon Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
  Description: Display beautifully clean, customizable, and responsive Instagram feeds.
6
+ Version: 2.5.3
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
23
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
  */
25
  if ( ! defined( 'SBIVER' ) ) {
26
+ define( 'SBIVER', '2.5.3' );
27
  }
28
  // Db version.
29
  if ( ! defined( 'SBI_DBVERSION' ) ) {
103
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-post-set.php';
104
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-posts-manager.php';
105
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-settings.php';
106
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-single.php';
107
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-token-refresher.php';
108
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/blocks/class-sbi-blocks.php';
109
  require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/class-sbi-tracking.php';
634
  delete_option( 'sbi_oembed_token' );
635
  delete_option( 'sbi_rating_notice' );
636
  delete_option( 'sbi_refresh_report' );
637
+ delete_option( 'sbi_single_cache' );
638
+
639
 
640
  global $wp_roles;
641
  $wp_roles->remove_cap( 'administrator', 'manage_instagram_feed_options' );