Instagram Widget by WPZOOM - Version 2.0.0

Version Description

  • We've made our plugin better and more user-friendly!
  • New: Gutenberg block
  • New: Create multiple feeds with different configurations
  • New: Embed your Instagram feeds using a shortcode anywhere you want
  • New: Customize the colors
  • New: Full-width layout
  • New: Connect multiple Instagram accounts [PRO only]
  • New: Masonry Layout [PRO only]
  • New: Load More button [PRO only]
Download this release

Release Info

Developer WPZOOM
Plugin Icon 128x128 Instagram Widget by WPZOOM
Version 2.0.0
Comparing to
See all releases

Code changes from version 1.9.5 to 2.0.0

Files changed (64) hide show
  1. .vscode/settings.json +2 -0
  2. assets/backend/img/user-avatar.jpg +0 -0
  3. class-wpzoom-instagram-block.php +157 -0
  4. class-wpzoom-instagram-image-uploader.php +17 -7
  5. class-wpzoom-instagram-widget-after-setup.php +90 -0
  6. class-wpzoom-instagram-widget-api.php +170 -339
  7. class-wpzoom-instagram-widget-display.php +802 -0
  8. class-wpzoom-instagram-widget-settings.php +2243 -47
  9. class-wpzoom-instagram-widget.php +745 -744
  10. css/admin-instagram-widget.css +0 -144
  11. dist/images/backend/user-avatar.jpg +0 -0
  12. {images → dist/images/frontend}/wpzoom-instagram-icons.svg +0 -0
  13. dist/scripts/backend/block.asset.php +1 -0
  14. dist/scripts/backend/block.js +2 -0
  15. dist/scripts/backend/index.asset.php +1 -0
  16. dist/scripts/backend/index.js +1 -0
  17. dist/scripts/frontend/block.asset.php +1 -0
  18. dist/scripts/frontend/block.js +1 -0
  19. dist/scripts/frontend/index.asset.php +1 -0
  20. dist/scripts/frontend/index.js +1 -0
  21. dist/scripts/frontend/preview.asset.php +1 -0
  22. dist/scripts/frontend/preview.js +1 -0
  23. dist/scripts/library/lazy.js +1 -0
  24. dist/scripts/library/magnific-popup.js +1 -0
  25. dist/scripts/library/swiper.js +1 -0
  26. dist/styles/backend/index-rtl.css +1 -0
  27. dist/styles/backend/index.asset.php +1 -0
  28. dist/styles/backend/index.css +1 -0
  29. dist/styles/frontend/block-rtl.css +1 -0
  30. dist/styles/frontend/block.asset.php +1 -0
  31. dist/styles/frontend/block.css +1 -0
  32. dist/styles/frontend/index-rtl.css +1 -0
  33. dist/styles/frontend/index.asset.php +1 -0
  34. dist/styles/frontend/index.css +1 -0
  35. dist/styles/frontend/preview-rtl.css +1 -0
  36. dist/styles/frontend/preview.asset.php +1 -0
  37. dist/styles/frontend/preview.css +1 -0
  38. {assets/frontend/magnific-popup → dist/styles/library}/magnific-popup.css +0 -0
  39. {assets/frontend/swiper → dist/styles/library}/swiper.css +0 -0
  40. images/wpzoom.png +0 -0
  41. instagram-widget-by-wpzoom.php +13 -8
  42. js/admin-instagram-widget.js +0 -169
  43. js/instagram-widget.js +0 -210
  44. languages/instagram-widget-by-wpzoom.pot +182 -290
  45. postcss.config.js +67 -0
  46. readme.txt +43 -14
  47. src/images/backend/user-avatar.jpg +0 -0
  48. src/images/frontend/wpzoom-instagram-icons.svg +9 -0
  49. src/scripts/backend/block.js +165 -0
  50. src/scripts/backend/custom-server-side-render/custom-server-side-render.js +208 -0
  51. src/scripts/backend/custom-server-side-render/index.js +50 -0
  52. src/scripts/backend/index.js +700 -0
  53. src/scripts/frontend/block.js +79 -0
  54. src/scripts/frontend/index.js +215 -0
  55. src/scripts/frontend/preview.js +11 -0
  56. js/jquery.lazy.min.js → src/scripts/library/lazy.js +0 -0
  57. assets/frontend/magnific-popup/jquery.magnific-popup.min.js → src/scripts/library/magnific-popup.js +0 -0
  58. {assets/frontend/swiper → src/scripts/library}/swiper.js +0 -0
  59. src/styles/backend/index.scss +2549 -0
  60. src/styles/frontend/block.scss +865 -0
  61. css/instagram-widget.css → src/styles/frontend/index.scss +372 -50
  62. src/styles/frontend/preview.scss +107 -0
  63. src/styles/library/magnific-popup.css +351 -0
  64. src/styles/library/swiper.css +13 -0
.vscode/settings.json ADDED
@@ -0,0 +1,2 @@
 
 
1
+ {
2
+ }
assets/backend/img/user-avatar.jpg DELETED
Binary file
class-wpzoom-instagram-block.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Exit if accessed directly.
4
+ */
5
+ defined( 'ABSPATH' ) or die;
6
+
7
+ /**
8
+ * WPZOOM Instagram Block class
9
+ *
10
+ * @package Wpzoom_Instagram_Block
11
+ */
12
+ class Wpzoom_Instagram_Block {
13
+ /**
14
+ * @var WPZOOM_Instagram_Widget_Settings The reference to *Singleton* instance of this class
15
+ *
16
+ * @since 1.8.4
17
+ */
18
+ private static $instance;
19
+
20
+ /**
21
+ * @var Wpzoom_Instagram_Widget_Display
22
+ */
23
+ protected $display;
24
+
25
+ /**
26
+ * Returns the *Singleton* instance of this class.
27
+ *
28
+ * @return WPZOOM_Instagram_Widget_Settings The *Singleton* instance.
29
+ */
30
+ public static function get_instance() {
31
+ if ( null === self::$instance ) {
32
+ self::$instance = new self();
33
+ }
34
+
35
+ return self::$instance;
36
+ }
37
+
38
+ /**
39
+ * Constructor.
40
+ */
41
+ public function __construct() {
42
+ $this->display = Wpzoom_Instagram_Widget_Display::getInstance();
43
+
44
+ add_action( 'init', array( $this, 'init' ) );
45
+ add_filter( 'block_categories_all', array( $this, 'block_categories' ), 10, 2 );
46
+ }
47
+
48
+ /**
49
+ * Initialize the block.
50
+ */
51
+ public function init() {
52
+ $script_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/scripts/backend/block.asset.php' );
53
+ $style_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/styles/frontend/block.asset.php' );
54
+
55
+ wp_register_script(
56
+ 'wpz-insta_block-backend-script',
57
+ plugins_url( 'dist/scripts/backend/block.js', __FILE__ ),
58
+ $script_asset_file['dependencies'],
59
+ $script_asset_file['version']
60
+ );
61
+
62
+ wp_register_script(
63
+ 'magnific-popup',
64
+ plugins_url( 'dist/scripts/library/magnific-popup.js', __FILE__ ),
65
+ array( 'jquery', 'underscore', 'wp-util' ),
66
+ filemtime( plugin_dir_path( __FILE__ ) . 'dist/scripts/library/magnific-popup.js' ),
67
+ true
68
+ );
69
+
70
+ wp_register_script(
71
+ 'swiper-js',
72
+ plugins_url( 'dist/scripts/library/swiper.js', __FILE__ ),
73
+ array(),
74
+ '7.0.0-alpha.21'
75
+ );
76
+
77
+ wp_register_script(
78
+ 'wpz-insta_block-frontend-script',
79
+ plugins_url( 'dist/scripts/frontend/block.js', __FILE__ ),
80
+ array( 'jquery', 'underscore', 'magnific-popup', 'swiper-js' ),
81
+ $script_asset_file['version']
82
+ );
83
+
84
+ wp_register_style(
85
+ 'magnific-popup',
86
+ plugins_url( 'dist/styles/library/magnific-popup.css', __FILE__ ),
87
+ array( 'dashicons' ),
88
+ WPZOOM_INSTAGRAM_VERSION
89
+ );
90
+
91
+ wp_enqueue_style(
92
+ 'swiper-css',
93
+ plugins_url( 'dist/styles/library/swiper.css', __FILE__ ),
94
+ array(),
95
+ '7.0.0-alpha.21'
96
+ );
97
+
98
+ wp_register_style(
99
+ 'wpz-insta_block-frontend-style',
100
+ plugins_url( 'dist/styles/frontend/block.css', __FILE__ ),
101
+ array( 'magnific-popup', 'swiper-css' ),
102
+ $style_asset_file['version']
103
+ );
104
+
105
+ register_block_type(
106
+ 'wpzoom/instagram-block',
107
+ array(
108
+ 'api_version' => 2,
109
+ 'category' => 'wpzoom-blocks',
110
+ 'editor_script' => 'wpz-insta_block-backend-script',
111
+ 'script' => 'wpz-insta_block-frontend-script',
112
+ 'style' => 'wpz-insta_block-frontend-style',
113
+ 'render_callback' => array( $this, 'render' ),
114
+ 'attributes' => array(
115
+ 'feed' => array(
116
+ 'type' => 'integer',
117
+ 'default' => -1,
118
+ ),
119
+ ),
120
+ )
121
+ );
122
+ }
123
+
124
+ /**
125
+ * Add the WPZOOM block category if needed.
126
+ */
127
+ public function block_categories( $categories ) {
128
+ if ( empty( $categories ) || ( ! empty( $categories ) && is_array( $categories ) && ! in_array( 'wpzoom-blocks', wp_list_pluck( $categories, 'slug' ) ) ) ) {
129
+ $categories = array_merge(
130
+ $categories,
131
+ array(
132
+ array(
133
+ 'slug' => 'wpzoom-blocks',
134
+ 'title' => esc_html__( 'WPZOOM - Blocks', 'instagram-widget-by-wpzoom' ),
135
+ ),
136
+ )
137
+ );
138
+ }
139
+
140
+ return $categories;
141
+ }
142
+
143
+ /**
144
+ * Render the block content.
145
+ */
146
+ public function render( $block_attributes, $content ) {
147
+ $feed_id = isset( $block_attributes['feed'] ) ? intval( $block_attributes['feed'] ) : -1;
148
+
149
+ if ( $feed_id > -1 ) {
150
+ return $this->display->output_feed( $feed_id, false );
151
+ } else {
152
+ return wp_kses_post( __( '<p class="error"><strong>Please select a feed to display...</strong></p>', 'instagram-widget-by-wpzoom' ) );
153
+ }
154
+ }
155
+ }
156
+
157
+ Wpzoom_Instagram_Block::get_instance();
class-wpzoom-instagram-image-uploader.php CHANGED
@@ -66,6 +66,13 @@ class WPZOOM_Instagram_Image_Uploader {
66
 
67
  $image_src = wp_get_attachment_image_src( $attachment_id, self::get_image_size_name( $media_size ) );
68
 
 
 
 
 
 
 
 
69
  return ! empty( $image_src ) ? $image_src[0] : $media_url;
70
  }
71
 
@@ -98,17 +105,20 @@ class WPZOOM_Instagram_Image_Uploader {
98
  * @return float|int
99
  */
100
  function get_transient_lifetime() {
101
- $options = WPZOOM_Instagram_Widget_Settings::get_instance()->get_settings();
 
102
 
103
  $values = array(
104
- 'minutes' => MINUTE_IN_SECONDS,
105
- 'hours' => HOUR_IN_SECONDS,
106
- 'days' => DAY_IN_SECONDS,
 
 
107
  );
108
  $keys = array_keys( $values );
109
- $type = in_array( $options['transient-lifetime-type'], $keys ) ? $values[ $options['transient-lifetime-type'] ] : $values['minutes'];
110
 
111
- return $type * $options['transient-lifetime-value'];
112
  }
113
 
114
  /**
@@ -349,7 +359,7 @@ class WPZOOM_Instagram_Image_Uploader {
349
  *
350
  * @return int|string
351
  */
352
- protected function get_best_size( $desired_width, $image_resolution = 'default_algorithm' ) {
353
  $size = 'thumbnail';
354
 
355
  $sizes = array(
66
 
67
  $image_src = wp_get_attachment_image_src( $attachment_id, self::get_image_size_name( $media_size ) );
68
 
69
+ return ! empty( $image_src ) ? $image_src[0] : $media_url;
70
+ } else {
71
+ $attachment_id = self::upload_image( $media_url, $media_id );
72
+ self::$instance->set_images_to_transient( $attachment_id, $media_id );
73
+
74
+ $image_src = wp_get_attachment_image_src( $attachment_id, self::get_image_size_name( $media_size ) );
75
+
76
  return ! empty( $image_src ) ? $image_src[0] : $media_url;
77
  }
78
 
105
  * @return float|int
106
  */
107
  function get_transient_lifetime() {
108
+ $interval = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'check-new-posts-interval-number' );
109
+ $interval_suffix = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'check-new-posts-interval-suffix' );
110
 
111
  $values = array(
112
+ MINUTE_IN_SECONDS,
113
+ HOUR_IN_SECONDS,
114
+ DAY_IN_SECONDS,
115
+ WEEK_IN_SECONDS,
116
+ MONTH_IN_SECONDS,
117
  );
118
  $keys = array_keys( $values );
119
+ $type = in_array( $interval_suffix, $keys ) ? $values[ $interval_suffix ] : $values[2];
120
 
121
+ return $type * $interval;
122
  }
123
 
124
  /**
359
  *
360
  * @return int|string
361
  */
362
+ protected function get_best_size( $desired_width, $image_resolution = 'low_resolution' ) {
363
  $size = 'thumbnail';
364
 
365
  $sizes = array(
class-wpzoom-instagram-widget-after-setup.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Exit if accessed directly.
4
+ */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ class Wpzoom_Instagram_Widget_After_Setup {
10
+
11
+ /**
12
+ * @var Wpzoom_Instagram_Widget_After_Setup The reference to *Singleton* instance of this class
13
+ *
14
+ * @since 1.8.4
15
+ */
16
+ private static $instance;
17
+
18
+ /**
19
+ * Returns the *Singleton* instance of this class.
20
+ *
21
+ * @return Wpzoom_Instagram_Widget_After_Setup The *Singleton* instance.
22
+ */
23
+ public static function get_instance() {
24
+ if ( null === self::$instance ) {
25
+ self::$instance = new self();
26
+ }
27
+
28
+ return self::$instance;
29
+ }
30
+
31
+ /**
32
+ * Construct.
33
+ */
34
+ public function __construct() {
35
+
36
+ add_action( 'init', array( $this, 'init' ) );
37
+ }
38
+
39
+ public function init() {
40
+
41
+ //Run only once
42
+ if ( get_option( 'wpzoom_run_only_once_01' ) ) {
43
+ return;
44
+ }
45
+
46
+ $getOldSettings = get_option( 'wpzoom-instagram-widget-settings' );
47
+
48
+ if( is_array( $getOldSettings ) && !empty( $getOldSettings ) ) {
49
+
50
+ $token = isset( $getOldSettings['basic-access-token'] ) ? $getOldSettings['basic-access-token'] : '';
51
+ $user_name = isset( $getOldSettings['user-info-fullname'] ) ? $getOldSettings['user-info-fullname'] : '';
52
+ $user_bio = isset( $getOldSettings['user-info-biography'] ) ? $getOldSettings['user-info-biography'] : '';
53
+ $user_image = isset( $getOldSettings['user-info-avatar'] ) ? $getOldSettings['user-info-avatar'] : '';
54
+
55
+ if ( ! empty( $token ) ) {
56
+ $info = Wpzoom_Instagram_Widget_API::get_basic_user_info_from_token( $token );
57
+
58
+ if ( false !== $info && is_object( $info ) && property_exists( $info, 'username' ) && property_exists( $info, 'account_type' ) ) {
59
+ $user = wp_strip_all_tags( $info->username );
60
+ $insert_post = wp_insert_post( array(
61
+ 'post_title' => $user,
62
+ 'post_type' => 'wpz-insta_user',
63
+ 'post_status' => 'publish',
64
+ 'post_content' => $user_bio
65
+ ), true );
66
+
67
+ if ( ! is_wp_error( $insert_post ) ) {
68
+ update_post_meta( $insert_post, '_wpz-insta_token', $token );
69
+ update_post_meta( $insert_post, '_wpz-insta_token_expire', strtotime( '+60 days' ) );
70
+ update_post_meta( $insert_post, '_wpz-insta_account-type', sanitize_text_field( $info->account_type ) );
71
+
72
+ update_post_meta( $insert_post, '_wpz-insta_user_name', sanitize_text_field( $user_name ) );
73
+ update_post_meta( $insert_post, '_thumbnail_id', $user_image );
74
+
75
+ if ( property_exists( $info, 'profile_picture' ) && ! empty( $info->profile_picture ) ) {
76
+ WPZOOM_Instagram_Widget_Settings()->generate_featured_image( $info->profile_picture, $insert_post, $user );
77
+ }
78
+ }
79
+
80
+ }
81
+ }
82
+ }
83
+
84
+ add_option( 'wpzoom_run_only_once_01', true );
85
+
86
+ }
87
+
88
+ }
89
+
90
+ Wpzoom_Instagram_Widget_After_Setup::get_instance();
class-wpzoom-instagram-widget-api.php CHANGED
@@ -44,16 +44,8 @@ class Wpzoom_Instagram_Widget_API {
44
  * Class constructor
45
  */
46
  protected function __construct() {
47
- $options = WPZOOM_Instagram_Widget_Settings::get_instance()->get_settings();
48
-
49
- $this->request_type = ! empty( $options['request-type'] ) ? $options['request-type'] : '';
50
- $this->access_token = ! empty( $options['basic-access-token'] ) ? $options['basic-access-token'] : '';
51
-
52
- $this->username = ! empty( $options['username'] ) ? $options['username'] : '';
53
- $this->transient_lifetime_type = ! empty( $options['transient-lifetime-type'] ) ? $options['transient-lifetime-type'] : 'days';
54
- $this->transient_lifetime_value = ! empty( $options['transient-lifetime-value'] ) ? $options['transient-lifetime-value'] : 1;
55
- $this->is_forced_timeout = ! empty( $options['is-forced-timeout'] ) ? wp_validate_boolean( $options['is-forced-timeout'] ) : false;
56
- $this->request_timeout_value = ! empty( $options['request-timeout-value'] ) ? $options['request-timeout-value'] : 15;
57
 
58
  if ( $this->is_forced_timeout && ! empty( $this->request_timeout_value ) ) {
59
  $this->headers['timeout'] = $this->request_timeout_value;
@@ -84,6 +76,18 @@ class Wpzoom_Instagram_Widget_API {
84
  return self::$instance;
85
  }
86
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  * Register custom cron intervals
89
  *
@@ -96,7 +100,7 @@ class Wpzoom_Instagram_Widget_API {
96
  if ( ! empty( $this->access_token ) ) {
97
  $schedules['before_access_token_expires'] = array(
98
  'interval' => 5097600, // 59 days.
99
- 'display' => __( 'Before Access Token Expires', 'instagram-widget-by-wpzoom' ),
100
  );
101
  }
102
  return $schedules;
@@ -119,68 +123,74 @@ class Wpzoom_Instagram_Widget_API {
119
  * @return boolean
120
  */
121
  public function execute_cron() {
122
- global $current_user;
123
-
124
- if ( ! empty( $this->access_token ) ) {
125
- $stored_data = WPZOOM_Instagram_Widget_Settings::get_instance()->get_settings();
126
- $request_url = add_query_arg(
127
- array(
128
- 'grant_type' => 'ig_refresh_token',
129
- 'access_token' => $this->access_token,
130
- ),
131
- 'https://graph.instagram.com/refresh_access_token'
132
- );
133
-
134
- $response = wp_safe_remote_get( $request_url, $this->headers );
135
- $response_code = wp_remote_retrieve_response_code( $response );
136
-
137
- if ( ! is_wp_error( $response ) ) {
138
- $body = wp_remote_retrieve_body( $response );
139
- $data = json_decode( $body );
140
- }
141
-
142
- if ( 200 === $response_code ) {
143
- $date_format = get_option( 'date_format' );
144
- $time_format = get_option( 'time_format' );
145
- $notice_message = sprintf( __( 'Instagram Access Token was refreshed automatically on %1$s at %2$s', 'instagram-widget-by-wpzoom' ), date( $date_format ), date( $time_format ) );
146
-
147
- $stored_data['basic-access-token'] = $data->access_token;
148
- $stored_data['refresh-access-token'] = $notice_message;
149
- } else {
150
- if ( ! isset( $data->error ) ) {
151
- error_log( __( 'Something wrong! Doesn\'t isset $data->error.', 'instagram-widget-by-wpzoom' ) );
152
- return false;
153
- } else {
154
- error_log( $data->error->error_user_msg );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
-
157
- $notice_message = '';
158
- $user_id = $current_user->ID;
159
- $hide_notices_url = wpzoom_instagram_get_notice_dismiss_url();
160
- $settings_url = admin_url( 'options-general.php?page=wpzoom-instagram-widget' );
161
-
162
- if ( 190 === $data->error->code ) {
163
- // Error validating access token: Session has expired.
164
- $notice_message = $data->error->message;
165
- $notice_message .= '<a style="text-decoration: none" class="notice-dismiss" href="' . $hide_notices_url . '"></a>';
166
- } elseif ( 10 === $data->error->code && ! self::is_access_token_valid( $this->access_token ) ) {
167
- // Application does not have permission for this action.
168
- // User need to generate new Access Token manually.
169
- $notice_message = '<strong>' . __( 'Your Access Token for Instagram Widget has expired!', 'instagram-widget-by-wpzoom' ) . '</strong><br/>';
170
- $notice_message .= sprintf( __( 'We cannot update access tokens automatically for Instagram private accounts. You need manually to generate a new access token, reauthorize here: %1$s.', 'instagram-widget-by-wpzoom' ), '<a href="' . esc_url( $settings_url ) . '">' . __( 'Instagram Widget Settings', 'instagram-widget-by-wpzoom' ) . '</a>' ) . '&nbsp;';
171
- $notice_message .= '<a style="text-decoration: none" class="notice-dismiss" href="' . $hide_notices_url . '"></a>';
172
- }
173
-
174
- $stored_data['admin-notice-message'] = $notice_message;
175
-
176
- // Update user meta to display admin notice.
177
- update_user_meta( $user_id, 'wpzoom_instagram_admin_notice', false );
178
  }
179
-
180
- return update_option( WPZOOM_Instagram_Widget_Settings::get_instance()->get_option_name(), $stored_data );
181
  }
182
-
183
- return false;
184
  }
185
 
186
  public static function reset_cache( $sanitized_data ) {
@@ -209,37 +219,40 @@ class Wpzoom_Instagram_Widget_API {
209
  'image-resolution',
210
  'username',
211
  'disable-video-thumbs',
 
 
212
  )
213
  );
214
 
215
  $image_limit = $sliced['image-limit'];
216
  $image_width = $sliced['image-width'];
217
- $image_resolution = ! empty( $sliced['image-resolution'] ) ? $sliced['image-resolution'] : 'default_algorithm';
218
  $injected_username = ! empty( $sliced['username'] ) ? $sliced['username'] : '';
219
  $disable_video_thumbs = ! empty( $sliced['disable-video-thumbs'] );
 
 
220
 
221
  $transient = 'zoom_instagram_is_configured';
222
 
223
- $injected_username = trim( $injected_username );
224
-
225
- if ( ! empty( $injected_username ) && 'without-access-token' === $this->request_type ) {
226
- $injected_username = str_replace( '@', '', $injected_username );
227
- $transient = $transient . '_' . $injected_username;
228
  }
229
 
230
- $data = json_decode( get_transient( $transient ) );
231
- if ( false !== $data && is_object( $data ) && ! empty( $data->data ) ) {
232
- return $this->processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs );
233
- }
234
 
235
- $is_external_username = ! empty( $this->username ) || ! empty( $injected_username );
236
- $external_username = ! empty( $injected_username ) ? $injected_username : $this->username;
 
 
 
 
237
 
238
  if ( ! empty( $this->access_token ) ) {
239
  $request_url = add_query_arg(
240
  array(
241
  'fields' => 'media_url,media_type,caption,username,permalink,thumbnail_url,timestamp,children{media_url,media_type,thumbnail_url}',
242
  'access_token' => $this->access_token,
 
243
  ),
244
  'https://graph.instagram.com/me/media'
245
  );
@@ -247,7 +260,9 @@ class Wpzoom_Instagram_Widget_API {
247
  $response = wp_safe_remote_get( $request_url, $this->headers );
248
 
249
  if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
250
- set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
 
 
251
 
252
  $error_data = $this->get_error( 'items-with-token-invalid-response' );
253
  $this->errors->add( $error_data['code'], $error_data['message'] );
@@ -255,25 +270,23 @@ class Wpzoom_Instagram_Widget_API {
255
  return false;
256
  }
257
 
258
- $data = json_decode( wp_remote_retrieve_body( $response ) );
259
-
260
- $data = $this->convert_items_to_old_structure( $data );
261
- }
262
 
263
- if ( 'without-access-token' === $this->request_type && ! empty( $is_external_username ) ) {
264
- $data = $this->get_items_without_token( $external_username );
265
 
266
- if ( is_wp_error( $data ) ) {
267
- set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
268
-
269
- return false;
270
  }
271
  }
272
 
273
  if ( ! empty( $data->data ) ) {
274
- set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime() );
 
 
275
  } else {
276
- set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
 
 
277
 
278
  $error_data = $this->get_error( 'items-with-token-invalid-data-structure' );
279
  $this->errors->add( $error_data['code'], $error_data['message'] );
@@ -281,10 +294,10 @@ class Wpzoom_Instagram_Widget_API {
281
  return false;
282
  }
283
 
284
- return $this->processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs );
285
  }
286
 
287
- public function processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs = false ) {
288
  $result = array();
289
  $username = '';
290
  $defaults = array(
@@ -301,7 +314,7 @@ class Wpzoom_Instagram_Widget_API {
301
  );
302
 
303
  if ( empty( $image_resolution ) ) {
304
- $image_resolution = 'default_algorithm';
305
  }
306
 
307
  foreach ( $data->data as $key => $item ) {
@@ -320,7 +333,7 @@ class Wpzoom_Instagram_Widget_API {
320
  continue;
321
  }
322
 
323
- $best_size = $this->get_best_size( $image_width, $image_resolution );
324
  $image_url = $item->images->{$best_size}->url;
325
 
326
  $regexPattern = '/-\d+[Xx]\d+\./';
@@ -348,6 +361,10 @@ class Wpzoom_Instagram_Widget_API {
348
  'username' => $username,
349
  );
350
 
 
 
 
 
351
  return $result;
352
  }
353
 
@@ -356,7 +373,7 @@ class Wpzoom_Instagram_Widget_API {
356
  *
357
  * @return string Image size for Instagram API
358
  */
359
- protected function get_best_size( $desired_width, $image_resolution = 'default_algorithm' ) {
360
  $size = 'thumbnail';
361
  $sizes = array(
362
  'thumbnail' => 150,
@@ -402,60 +419,63 @@ class Wpzoom_Instagram_Widget_API {
402
  return array(
403
  'user-info-without-token' => array(
404
  'code' => 'user-info-without-token',
405
- 'message' => __( 'Empty json user info from Public Feed.', 'instagram-widget-by-wpzoom' ),
406
  ),
407
  'response-data-without-token-from-json-invalid-response' => array(
408
  'code' => 'response-data-without-token-from-json-invalid-response',
409
- 'message' => __( 'The request from the Public Feed failed. Invalid server response from Public JSON API url.', 'instagram-widget-by-wpzoom' ),
410
  ),
411
  'response-data-without-token-from-json-invalid-json-format' => array(
412
  'code' => 'response-data-without-token-from-json-invalid-json-format',
413
- 'message' => __( 'The request from the Public Feed failed. Invalid JSON format from Public JSON API url.', 'instagram-widget-by-wpzoom' ),
414
  ),
415
  'response-data-without-token-from-html-invalid-response' => array(
416
  'code' => 'response-data-without-token-from-html-invalid-response',
417
- 'message' => __( 'The request from the Public Feed failed. Check username.', 'instagram-widget-by-wpzoom' ),
418
  ),
419
  'response-data-without-token-from-html-invalid-json-format' => array(
420
  'code' => 'response-data-without-token-from-html-invalid-json-format',
421
- 'message' => __( 'The request from the Public Feed failed. Invalid JSON format from parsed html body.', 'instagram-widget-by-wpzoom' ),
422
  ),
423
  'items-without-token-invalid-response' => array(
424
  'code' => 'items-without-token-invalid-response',
425
- 'message' => __( 'Get items from the Public Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
426
  ),
427
  'items-without-token-invalid-json-structure' => array(
428
  'code' => 'items-without-token-invalid-json-structure',
429
- 'message' => __( 'Get items from the Public Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
430
  ),
431
  'items-with-token-invalid-response' => array(
432
  'code' => 'items-with-token-invalid-response',
433
- 'message' => __( 'Geting items from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
434
  ),
435
  'items-with-token-invalid-data-structure' => array(
436
  'code' => 'items-with-token-invalid-data-structure',
437
- 'message' => __( 'Get items from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
438
  ),
439
  'user-with-token-invalid-response' => array(
440
  'code' => 'user-with-token-invalid-response',
441
- 'message' => __( 'Get user data from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
442
  ),
443
  'user-with-token-invalid-data-structure' => array(
444
  'code' => 'user-with-token-invalid-data-structure',
445
- 'message' => __( 'Get user data from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
446
  ),
447
 
448
  );
449
  }
450
 
451
- function convert_items_to_old_structure( $data ) {
452
  $converted = new stdClass();
453
  $converted->data = array();
 
454
 
455
  foreach ( $data->data as $key => $item ) {
 
 
456
  $converted->data[] = (object) array(
457
  'id' => $item->id,
458
- 'media_url' => ( 'VIDEO' === $item->media_type ) ? $item->thumbnail_url : $item->media_url,
459
  'user' => (object) array(
460
  'id' => null,
461
  'fullname' => null,
@@ -464,17 +484,17 @@ class Wpzoom_Instagram_Widget_API {
464
  ),
465
  'images' => (object) array(
466
  'thumbnail' => (object) array(
467
- 'url' => $this->image_uploader->get_image( 'thumbnail', $item->media_url, $item->id ),
468
  'width' => 150,
469
  'height' => 150,
470
  ),
471
  'low_resolution' => (object) array(
472
- 'url' => $this->image_uploader->get_image( 'low_resolution', $item->media_url, $item->id ),
473
  'width' => 320,
474
  'height' => 320,
475
  ),
476
  'standard_resolution' => (object) array(
477
- 'url' => $this->image_uploader->get_image( 'standard_resolution', $item->media_url, $item->id ),
478
  'width' => 640,
479
  'height' => 640,
480
  ),
@@ -495,168 +515,21 @@ class Wpzoom_Instagram_Widget_API {
495
  return $converted;
496
  }
497
 
498
- function get_items_without_token( $user ) {
499
- $result = $this->get_response_without_token( $user );
500
-
501
- if ( is_wp_error( $result ) ) {
502
- $error_data = $this->get_error( 'items-without-token-invalid-response' );
503
- $this->errors->add( $error_data['code'], $error_data['message'] );
504
-
505
- return new WP_Error( $error_data['code'], $error_data['message'] );
506
- }
507
-
508
- if ( isset( $result->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges ) ) {
509
- $edges = $result->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges;
510
- } elseif ( isset( $result->graphql->user->edge_owner_to_timeline_media->edges ) ) {
511
- $edges = $result->graphql->user->edge_owner_to_timeline_media->edges;
512
- } else {
513
- $error_data = $this->get_error( 'items-without-token-invalid-json-structure' );
514
- $this->errors->add( $error_data['code'], $error_data['message'] );
515
-
516
- return new WP_Error( $error_data['code'], $error_data['message'] );
517
- }
518
-
519
- $converted = new stdClass();
520
- $converted->data = array();
521
- foreach ( $edges as $edge ) {
522
- $node = $edge->node;
523
-
524
- $converted->data[] = (object) array(
525
- 'user' => (object) array(
526
- 'id' => $node->owner->id,
527
- 'fullname' => '',
528
- 'profile_picture' => '',
529
- 'username' => $node->owner->username,
530
- ),
531
- 'images' => (object) array(
532
- 'thumbnail' => (object) array(
533
- 'url' => $node->thumbnail_resources[0]->src,
534
- 'width' => $node->thumbnail_resources[0]->config_width,
535
- 'height' => $node->thumbnail_resources[0]->config_height,
536
- ),
537
- 'low_resolution' => (object) array(
538
- 'url' => $node->thumbnail_resources[2]->src,
539
- 'width' => $node->thumbnail_resources[2]->config_width,
540
- 'height' => $node->thumbnail_resources[2]->config_height,
541
- ),
542
- 'standard_resolution' => (object) array(
543
- 'url' => $node->thumbnail_resources[4]->src,
544
- 'width' => $node->thumbnail_resources[4]->config_width,
545
- 'height' => $node->thumbnail_resources[4]->config_height,
546
- ),
547
- ),
548
- 'type' => $this->get_media_type_without_token( $node->__typename ),
549
- 'likes' => isset( $node->edge_liked_by ) ? $node->edge_liked_by : 0,
550
- 'comments' => isset( $node->edge_media_to_comment ) ? $node->edge_media_to_comment : 0,
551
- 'created_time' => $node->taken_at_timestamp,
552
- 'link' => sprintf( 'https://www.instagram.com/p/%s/', $node->shortcode ),
553
- 'caption' => (object) array(
554
- 'text' => isset( $node->edge_media_to_caption->edges[0]->node->text ) ? $node->edge_media_to_caption->edges[0]->node->text : '',
555
- ),
556
- );
557
- }
558
-
559
- return $converted;
560
- }
561
-
562
- function get_response_without_token( $user ) {
563
- $user = trim( $user );
564
- $url = 'https://instagram.com/' . str_replace( '@', '', $user );
565
-
566
- $request = wp_safe_remote_get( $url, $this->headers );
567
-
568
- if ( is_wp_error( $request ) || 200 != wp_remote_retrieve_response_code( $request ) ) {
569
- $error_data = $this->get_error( 'response-data-without-token-from-html-invalid-response' );
570
- $this->errors->add( $error_data['code'], $error_data['message'] );
571
-
572
- $result = $this->get_response_without_token_from_json( $user );
573
-
574
- if ( is_wp_error( $result ) ) {
575
- return new WP_Error( 'invalid_response', __( 'Invalid response from Instagram', 'instagram-widget-by-wpzoom' ) );
576
- } else {
577
- return $result;
578
- }
579
- }
580
-
581
- $body = wp_remote_retrieve_body( $request );
582
-
583
- $doc = new DOMDocument();
584
-
585
- @$doc->loadHTML( $body );
586
-
587
- $script_tags = $doc->getElementsByTagName( 'script' );
588
-
589
- $json = '';
590
-
591
- foreach ( $script_tags as $script_tag ) {
592
- if ( strpos( $script_tag->nodeValue, 'window._sharedData = ' ) !== false ) {
593
- $json = $script_tag->nodeValue;
594
- break;
595
- }
596
- }
597
-
598
- $json = str_replace( array( 'window._sharedData = ', '};' ), array( '', '}' ), $json );
599
- $result = json_decode( $json );
600
-
601
- if ( empty( $result ) ) {
602
- $error_data = $this->get_error( 'response-data-without-token-from-html-invalid-json-format' );
603
- $this->errors->add( $error_data['code'], $error_data['message'] );
604
-
605
- $result = $this->get_response_without_token_from_json( $user );
606
-
607
- if ( is_wp_error( $result ) ) {
608
- return new WP_Error( 'empty-json', __( 'Empty json decoded data.', 'instagram-widget-by-wpzoom' ) );
609
- }
610
- }
611
-
612
- return $result;
613
- }
614
-
615
- function get_response_without_token_from_json( $user ) {
616
- $user = trim( $user );
617
- $url = 'https://instagram.com/' . str_replace( '@', '', $user ) . '/?__a=1';
618
-
619
- $request = wp_safe_remote_get( $url, $this->headers );
620
-
621
- if ( is_wp_error( $request ) || 200 != wp_remote_retrieve_response_code( $request ) ) {
622
- $error_data = $this->get_error( 'response-data-without-token-from-json-invalid-response' );
623
- $this->errors->add( $error_data['code'], $error_data['message'] );
624
-
625
- return new WP_Error( $error_data['code'], $error_data['message'] );
626
- }
627
-
628
- $result = json_decode( wp_remote_retrieve_body( $request ) );
629
-
630
- if ( empty( $result ) ) {
631
- $error_data = $this->get_error( 'response-data-without-token-from-json-invalid-json-format' );
632
- $this->errors->add( $error_data['code'], $error_data['message'] );
633
-
634
- return new WP_Error( $error_data['code'], $error_data['message'] );
635
- }
636
-
637
- return $result;
638
- }
639
-
640
- function get_media_type_without_token( $media_type ) {
641
- $media_types = array(
642
- 'GraphImage' => 'IMAGE',
643
- 'GraphSidecar' => 'CAROUSEL_ALBUM',
644
- 'GraphVideo' => 'VIDEO',
645
- );
646
-
647
- return array_key_exists( $media_type, $media_types ) ? $media_types[ $media_type ] : array_shift( $media_types );
648
- }
649
-
650
  function get_transient_lifetime() {
 
 
 
651
  $values = array(
652
- 'minutes' => MINUTE_IN_SECONDS,
653
- 'hours' => HOUR_IN_SECONDS,
654
- 'days' => DAY_IN_SECONDS,
 
 
655
  );
656
  $keys = array_keys( $values );
657
- $type = in_array( $this->transient_lifetime_type, $keys ) ? $values[ $this->transient_lifetime_type ] : $values['minutes'];
658
 
659
- return $type * $this->transient_lifetime_value;
660
  }
661
 
662
  public function get_user_info( $injected_username = '' ) {
@@ -664,18 +537,10 @@ class Wpzoom_Instagram_Widget_API {
664
 
665
  $injected_username = rtrim( $injected_username );
666
 
667
- if ( ! empty( $injected_username ) && 'without-access-token' === $this->request_type ) {
668
- $injected_username = str_replace( '@', '', $injected_username );
669
- $transient = $transient . '_' . $injected_username;
670
- }
671
-
672
  if ( false !== ( $data = json_decode( get_transient( $transient ) ) ) && is_object( $data ) && ! empty( $data->data ) ) {
673
  return $data;
674
  }
675
 
676
- $is_external_username = ! empty( $this->username ) || ! empty( $injected_username );
677
- $external_username = ! empty( $injected_username ) ? $injected_username : $this->username;
678
-
679
  if ( ! empty( $this->access_token ) ) {
680
  $request_url = add_query_arg(
681
  array(
@@ -700,16 +565,6 @@ class Wpzoom_Instagram_Widget_API {
700
  $data = $this->convert_user_info_to_old_structure( $data );
701
  }
702
 
703
- if ( 'without-access-token' === $this->request_type && ! empty( $is_external_username ) ) {
704
- $data = $this->get_user_info_without_token( $external_username );
705
-
706
- if ( is_wp_error( $data ) ) {
707
- set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
708
-
709
- return false;
710
- }
711
- }
712
-
713
  if ( ! empty( $data->data ) ) {
714
  set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime() );
715
  } else {
@@ -724,6 +579,28 @@ class Wpzoom_Instagram_Widget_API {
724
  return $data;
725
  }
726
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  function convert_user_info_to_old_structure( $user_info ) {
728
  $converted = new stdClass();
729
 
@@ -762,48 +639,6 @@ class Wpzoom_Instagram_Widget_API {
762
  return $converted;
763
  }
764
 
765
-
766
- function get_user_info_without_token( $user ) {
767
- $response = $this->get_response_without_token( $user );
768
-
769
- if ( is_wp_error( $response ) ) {
770
- $error_data = $this->get_error( 'user-info-without-token' );
771
- $this->errors->add( $error_data['code'], $error_data['message'] );
772
-
773
- return new WP_Error( $error_data['code'], $error_data['message'] );
774
- }
775
-
776
- if ( isset( $response->entry_data->ProfilePage[0]->graphql->user ) ) {
777
- $user_info = $response->entry_data->ProfilePage[0]->graphql->user;
778
- } elseif ( isset( $response->graphql->user ) ) {
779
- $user_info = $response->graphql->user;
780
- } else {
781
- $error_data = $this->get_error( 'user-info-without-token' );
782
- $this->errors->add( $error_data['code'], $error_data['message'] );
783
-
784
- return new WP_Error( $error_data['code'], $error_data['message'] );
785
- }
786
-
787
- $converted = new stdClass();
788
-
789
- $converted->data = (object) array(
790
- 'bio' => ! empty( $user_info->biography ) ? $user_info->biography : '',
791
- 'counts' => (object) array(
792
- 'followed_by' => ! empty( $user_info->edge_followed_by->count ) ? $user_info->edge_followed_by->count : 0,
793
- 'follows' => ! empty( $user_info->edge_follow->count ) ? $user_info->edge_follow->count : 0,
794
- 'media' => ! empty( $user_info->edge_owner_to_timeline_media->count ) ? $user_info->edge_owner_to_timeline_media->count : 0,
795
- ),
796
- 'full_name' => ! empty( $user_info->full_name ) ? $user_info->full_name : '',
797
- 'id' => ! empty( $user_info->id ) ? $user_info->id : '',
798
- 'is_business' => ! empty( $user_info->is_business_account ) ? $user_info->is_business_account : '',
799
- 'profile_picture' => ! empty( $user_info->profile_pic_url ) ? $user_info->profile_pic_url : '',
800
- 'username' => ! empty( $user_info->username ) ? $user_info->username : '',
801
- 'website' => ! empty( $user_info->external_url ) ? $user_info->external_url : '',
802
- );
803
-
804
- return $converted;
805
- }
806
-
807
  public function is_configured() {
808
  $transient = 'zoom_instagram_is_configured';
809
 
@@ -821,11 +656,7 @@ class Wpzoom_Instagram_Widget_API {
821
  }
822
  }
823
 
824
- if ( empty( $this->username ) ) {
825
- $condition = $this->is_access_token_valid( $this->access_token, $this->request_type );
826
- } else {
827
- $condition = true;
828
- }
829
 
830
  if ( true === $condition ) {
831
  set_transient( $transient, wp_json_encode( 'yes' ), DAY_IN_SECONDS );
@@ -841,7 +672,7 @@ class Wpzoom_Instagram_Widget_API {
841
  /**
842
  * Check if given access token is valid for Instagram Api.
843
  */
844
- public static function is_access_token_valid( $access_token, $request_type = '' ) {
845
  if ( empty( $access_token ) ) {
846
  return false;
847
  }
44
  * Class constructor
45
  */
46
  protected function __construct() {
47
+ $this->is_forced_timeout = (bool) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'enable-request-timeout' );
48
+ $this->request_timeout_value = 15;
 
 
 
 
 
 
 
 
49
 
50
  if ( $this->is_forced_timeout && ! empty( $this->request_timeout_value ) ) {
51
  $this->headers['timeout'] = $this->request_timeout_value;
76
  return self::$instance;
77
  }
78
 
79
+ /**
80
+ * Manually set the access token.
81
+ *
82
+ * @since 2.0.0
83
+ *
84
+ * @param string $token The access token to set.
85
+ * @return void
86
+ */
87
+ public function set_access_token( $token ) {
88
+ $this->access_token = $token;
89
+ }
90
+
91
  /**
92
  * Register custom cron intervals
93
  *
100
  if ( ! empty( $this->access_token ) ) {
101
  $schedules['before_access_token_expires'] = array(
102
  'interval' => 5097600, // 59 days.
103
+ 'display' => esc_attr__( 'Before Access Token Expires', 'instagram-widget-by-wpzoom' ),
104
  );
105
  }
106
  return $schedules;
123
  * @return boolean
124
  */
125
  public function execute_cron() {
126
+ $all_users = get_posts( array(
127
+ 'numberposts' => -1,
128
+ 'post_type' => 'wpz-insta_user',
129
+ ) );
130
+
131
+ if ( ! empty( $all_users ) && is_array( $all_users ) ) {
132
+ foreach ( $all_users as $user ) {
133
+ if ( $user instanceof WP_Post ) {
134
+ $user_name = get_the_title( $user );
135
+ $user_display = sprintf( '@%s', $user_name );
136
+ $token = get_post_meta( $user->ID, '_wpz-insta_token', true );
137
+
138
+ if ( false !== $token && ! empty( $token ) ) {
139
+ $request_url = add_query_arg(
140
+ array(
141
+ 'grant_type' => 'ig_refresh_token',
142
+ 'access_token' => $token,
143
+ ),
144
+ 'https://graph.instagram.com/refresh_access_token'
145
+ );
146
+
147
+ $response = wp_safe_remote_get( $request_url, $this->headers );
148
+ $response_code = wp_remote_retrieve_response_code( $response );
149
+
150
+ if ( ! is_wp_error( $response ) ) {
151
+ $body = wp_remote_retrieve_body( $response );
152
+ $data = json_decode( $body );
153
+ }
154
+
155
+ if ( 200 === $response_code ) {
156
+ $date_format = get_option( 'date_format' );
157
+ $time_format = get_option( 'time_format' );
158
+ $notice_status = 'success';
159
+ $notice_message = sprintf( __( '<strong>WPZOOM Instagram Widget:</strong> The Instagram Access Token was refreshed automatically on %1$s at %2$s for the account <em>%3$s</em>.', 'instagram-widget-by-wpzoom' ), date( $date_format ), date( $time_format ), esc_html( $user_display ) );
160
+
161
+ update_post_meta( $user->ID, '_wpz-insta_token', $data->access_token );
162
+ update_post_meta( $user->ID, '_wpz-insta_token_expire', strtotime( '+60 days' ) );
163
+ } else {
164
+ if ( ! isset( $data->error ) ) {
165
+ error_log( __( 'Something wrong! Doesn\'t isset $data->error.', 'instagram-widget-by-wpzoom' ) );
166
+ return false;
167
+ } else {
168
+ error_log( $data->error->error_user_msg );
169
+ }
170
+
171
+ $notice_status = 'error';
172
+ $notice_message = '';
173
+ $settings_url = admin_url( 'edit.php?post_type=wpz-insta_user' );
174
+
175
+ if ( 190 === $data->error->code ) {
176
+ // Error validating access token: Session has expired.
177
+ $notice_message = wp_kses_post( __( '<strong>WPZOOM Instagram Widget:</strong> ', 'instagram-widget-by-wpzoom' ) ) . $data->error->message;
178
+ } elseif ( 10 === $data->error->code && ! self::is_access_token_valid( $token ) ) {
179
+ // Application does not have permission for this action.
180
+ // User need to generate new Access Token manually.
181
+ $notice_message = sprintf( __( '<strong>WPZOOM Instagram Widget:</strong> The Access Token for the account <em>%1$s</em> has expired!<br/>', 'instagram-widget-by-wpzoom' ), $user_display );
182
+ $notice_message .= sprintf( __( 'We cannot update access tokens automatically for Instagram private accounts. You need to manually generate a new access token, reauthorize here: %1$s', 'instagram-widget-by-wpzoom' ), '<a href="' . esc_url( $settings_url ) . '">' . __( 'Instagram Widget Settings', 'instagram-widget-by-wpzoom' ) . '</a>' );
183
+ }
184
+ }
185
+
186
+ update_option(
187
+ '_wpz-insta_cron-result',
188
+ array( $user->ID => array( 'status' => $notice_status, 'message' => $notice_message ) ) + (array) get_option( '_wpz-insta_cron-result', array() )
189
+ );
190
+ }
191
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  }
 
 
193
  }
 
 
194
  }
195
 
196
  public static function reset_cache( $sanitized_data ) {
219
  'image-resolution',
220
  'username',
221
  'disable-video-thumbs',
222
+ 'include-pagination',
223
+ 'bypass-transient',
224
  )
225
  );
226
 
227
  $image_limit = $sliced['image-limit'];
228
  $image_width = $sliced['image-width'];
229
+ $image_resolution = ! empty( $sliced['image-resolution'] ) ? $sliced['image-resolution'] : 'low_resolution';
230
  $injected_username = ! empty( $sliced['username'] ) ? $sliced['username'] : '';
231
  $disable_video_thumbs = ! empty( $sliced['disable-video-thumbs'] );
232
+ $include_pagination = ! empty( $sliced['include-pagination'] );
233
+ $bypass_transient = ! empty( $sliced['bypass-transient'] );
234
 
235
  $transient = 'zoom_instagram_is_configured';
236
 
237
+ if ( ! empty( $this->access_token ) ) {
238
+ $transient = $transient . '_' . $this->access_token;
 
 
 
239
  }
240
 
241
+ $injected_username = trim( $injected_username );
 
 
 
242
 
243
+ if ( ! $bypass_transient ) {
244
+ $data = json_decode( get_transient( $transient ) );
245
+ if ( false !== $data && is_object( $data ) && ! empty( $data->data ) ) {
246
+ return self::processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs, $include_pagination );
247
+ }
248
+ }
249
 
250
  if ( ! empty( $this->access_token ) ) {
251
  $request_url = add_query_arg(
252
  array(
253
  'fields' => 'media_url,media_type,caption,username,permalink,thumbnail_url,timestamp,children{media_url,media_type,thumbnail_url}',
254
  'access_token' => $this->access_token,
255
+ 'limit' => $image_limit,
256
  ),
257
  'https://graph.instagram.com/me/media'
258
  );
260
  $response = wp_safe_remote_get( $request_url, $this->headers );
261
 
262
  if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
263
+ if ( ! $bypass_transient ) {
264
+ set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
265
+ }
266
 
267
  $error_data = $this->get_error( 'items-with-token-invalid-response' );
268
  $this->errors->add( $error_data['code'], $error_data['message'] );
270
  return false;
271
  }
272
 
273
+ $raw_data = json_decode( wp_remote_retrieve_body( $response ) );
 
 
 
274
 
275
+ $data = self::convert_items_to_old_structure( $raw_data, $bypass_transient );
 
276
 
277
+ if ( $include_pagination && property_exists( $raw_data, 'paging' ) ) {
278
+ $data->paging = $raw_data->paging;
 
 
279
  }
280
  }
281
 
282
  if ( ! empty( $data->data ) ) {
283
+ if ( ! $bypass_transient ) {
284
+ set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime() );
285
+ }
286
  } else {
287
+ if ( ! $bypass_transient ) {
288
+ set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS );
289
+ }
290
 
291
  $error_data = $this->get_error( 'items-with-token-invalid-data-structure' );
292
  $this->errors->add( $error_data['code'], $error_data['message'] );
294
  return false;
295
  }
296
 
297
+ return self::processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs, $include_pagination );
298
  }
299
 
300
+ public static function processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs = false, $include_pagination = false ) {
301
  $result = array();
302
  $username = '';
303
  $defaults = array(
314
  );
315
 
316
  if ( empty( $image_resolution ) ) {
317
+ $image_resolution = 'low_resolution';
318
  }
319
 
320
  foreach ( $data->data as $key => $item ) {
333
  continue;
334
  }
335
 
336
+ $best_size = self::get_best_size( $image_width, $image_resolution );
337
  $image_url = $item->images->{$best_size}->url;
338
 
339
  $regexPattern = '/-\d+[Xx]\d+\./';
361
  'username' => $username,
362
  );
363
 
364
+ if ( $include_pagination && property_exists( $data, 'paging' ) ) {
365
+ $result['paging'] = $data->paging;
366
+ }
367
+
368
  return $result;
369
  }
370
 
373
  *
374
  * @return string Image size for Instagram API
375
  */
376
+ public static function get_best_size( $desired_width, $image_resolution = 'low_resolution' ) {
377
  $size = 'thumbnail';
378
  $sizes = array(
379
  'thumbnail' => 150,
419
  return array(
420
  'user-info-without-token' => array(
421
  'code' => 'user-info-without-token',
422
+ 'message' => esc_html__( 'Empty json user info from Public Feed.', 'instagram-widget-by-wpzoom' ),
423
  ),
424
  'response-data-without-token-from-json-invalid-response' => array(
425
  'code' => 'response-data-without-token-from-json-invalid-response',
426
+ 'message' => esc_html__( 'The request from the Public Feed failed. Invalid server response from Public JSON API url.', 'instagram-widget-by-wpzoom' ),
427
  ),
428
  'response-data-without-token-from-json-invalid-json-format' => array(
429
  'code' => 'response-data-without-token-from-json-invalid-json-format',
430
+ 'message' => esc_html__( 'The request from the Public Feed failed. Invalid JSON format from Public JSON API url.', 'instagram-widget-by-wpzoom' ),
431
  ),
432
  'response-data-without-token-from-html-invalid-response' => array(
433
  'code' => 'response-data-without-token-from-html-invalid-response',
434
+ 'message' => esc_html__( 'The request from the Public Feed failed. Check username.', 'instagram-widget-by-wpzoom' ),
435
  ),
436
  'response-data-without-token-from-html-invalid-json-format' => array(
437
  'code' => 'response-data-without-token-from-html-invalid-json-format',
438
+ 'message' => esc_html__( 'The request from the Public Feed failed. Invalid JSON format from parsed html body.', 'instagram-widget-by-wpzoom' ),
439
  ),
440
  'items-without-token-invalid-response' => array(
441
  'code' => 'items-without-token-invalid-response',
442
+ 'message' => esc_html__( 'Get items from the Public Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
443
  ),
444
  'items-without-token-invalid-json-structure' => array(
445
  'code' => 'items-without-token-invalid-json-structure',
446
+ 'message' => esc_html__( 'Get items from the Public Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
447
  ),
448
  'items-with-token-invalid-response' => array(
449
  'code' => 'items-with-token-invalid-response',
450
+ 'message' => esc_html__( 'Geting items from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
451
  ),
452
  'items-with-token-invalid-data-structure' => array(
453
  'code' => 'items-with-token-invalid-data-structure',
454
+ 'message' => esc_html__( 'Get items from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
455
  ),
456
  'user-with-token-invalid-response' => array(
457
  'code' => 'user-with-token-invalid-response',
458
+ 'message' => esc_html__( 'Get user data from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ),
459
  ),
460
  'user-with-token-invalid-data-structure' => array(
461
  'code' => 'user-with-token-invalid-data-structure',
462
+ 'message' => esc_html__( 'Get user data from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ),
463
  ),
464
 
465
  );
466
  }
467
 
468
+ public static function convert_items_to_old_structure( $data, $preview = false ) {
469
  $converted = new stdClass();
470
  $converted->data = array();
471
+ $image_uploader = WPZOOM_Instagram_Image_Uploader::getInstance();
472
 
473
  foreach ( $data->data as $key => $item ) {
474
+ $media_url = 'VIDEO' === $item->media_type && property_exists( $item, 'thumbnail_url' ) && ! empty( $item->thumbnail_url ) ? $item->thumbnail_url : $item->media_url;
475
+
476
  $converted->data[] = (object) array(
477
  'id' => $item->id,
478
+ 'media_url' => $media_url,
479
  'user' => (object) array(
480
  'id' => null,
481
  'fullname' => null,
484
  ),
485
  'images' => (object) array(
486
  'thumbnail' => (object) array(
487
+ 'url' => $preview ? $media_url : $image_uploader->get_image( 'thumbnail', $media_url, $item->id ),
488
  'width' => 150,
489
  'height' => 150,
490
  ),
491
  'low_resolution' => (object) array(
492
+ 'url' => $preview ? $media_url : $image_uploader->get_image( 'low_resolution', $media_url, $item->id ),
493
  'width' => 320,
494
  'height' => 320,
495
  ),
496
  'standard_resolution' => (object) array(
497
+ 'url' => $preview ? $media_url : $image_uploader->get_image( 'standard_resolution', $media_url, $item->id ),
498
  'width' => 640,
499
  'height' => 640,
500
  ),
515
  return $converted;
516
  }
517
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  function get_transient_lifetime() {
519
+ $interval = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'check-new-posts-interval-number' );
520
+ $interval_suffix = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'check-new-posts-interval-suffix' );
521
+
522
  $values = array(
523
+ MINUTE_IN_SECONDS,
524
+ HOUR_IN_SECONDS,
525
+ DAY_IN_SECONDS,
526
+ WEEK_IN_SECONDS,
527
+ MONTH_IN_SECONDS,
528
  );
529
  $keys = array_keys( $values );
530
+ $type = in_array( $interval_suffix, $keys ) ? $values[ $interval_suffix ] : $values[2];
531
 
532
+ return $type * $interval;
533
  }
534
 
535
  public function get_user_info( $injected_username = '' ) {
537
 
538
  $injected_username = rtrim( $injected_username );
539
 
 
 
 
 
 
540
  if ( false !== ( $data = json_decode( get_transient( $transient ) ) ) && is_object( $data ) && ! empty( $data->data ) ) {
541
  return $data;
542
  }
543
 
 
 
 
544
  if ( ! empty( $this->access_token ) ) {
545
  $request_url = add_query_arg(
546
  array(
565
  $data = $this->convert_user_info_to_old_structure( $data );
566
  }
567
 
 
 
 
 
 
 
 
 
 
 
568
  if ( ! empty( $data->data ) ) {
569
  set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime() );
570
  } else {
579
  return $data;
580
  }
581
 
582
+ public static function get_basic_user_info_from_token( $access_token ) {
583
+ $output = false;
584
+
585
+ if ( ! empty( $access_token ) ) {
586
+ $request_url = add_query_arg(
587
+ array(
588
+ 'access_token' => $access_token,
589
+ 'fields' => 'account_type,username,profile_picture',
590
+ ),
591
+ 'https://graph.instagram.com/me'
592
+ );
593
+
594
+ $response = wp_safe_remote_get( $request_url );
595
+
596
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
597
+ $output = json_decode( wp_remote_retrieve_body( $response ) );
598
+ }
599
+ }
600
+
601
+ return $output;
602
+ }
603
+
604
  function convert_user_info_to_old_structure( $user_info ) {
605
  $converted = new stdClass();
606
 
639
  return $converted;
640
  }
641
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
642
  public function is_configured() {
643
  $transient = 'zoom_instagram_is_configured';
644
 
656
  }
657
  }
658
 
659
+ $condition = $this->is_access_token_valid( $this->access_token );
 
 
 
 
660
 
661
  if ( true === $condition ) {
662
  set_transient( $transient, wp_json_encode( 'yes' ), DAY_IN_SECONDS );
672
  /**
673
  * Check if given access token is valid for Instagram Api.
674
  */
675
+ public static function is_access_token_valid( $access_token ) {
676
  if ( empty( $access_token ) ) {
677
  return false;
678
  }
class-wpzoom-instagram-widget-display.php ADDED
@@ -0,0 +1,802 @@