Instagram Slider Widget - Version 1.0.4

Version Description

  • Added Option to insert images into media library
  • Fixed error caused by missing json_last_error() function ( php older than 5.3 only )
Download this release

Release Info

Developer jetonr
Plugin Icon 128x128 Instagram Slider Widget
Version 1.0.4
Comparing to
See all releases

Code changes from version 1.0.1 to 1.0.4

assets/css/instag-slider.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Flexislider Default Settings */
2
+ .pllexislider { margin: 0; padding: 0; }
3
+ .pllexislider .slides > li {display: none; -webkit-backface-visibility: hidden;} /* Hide the slides before the JS is loaded. Avoids image jumping */
4
+ .pllexislider .slides img {width: 100%; display: block;}
5
+ .pllexislider .slides:after { display: block; clear: both; visibility: hidden; line-height: 0; height: 0;}
6
+ .flex-pauseplay span { text-transform: capitalize; }
7
+ .pllexislider, .pllexislider .slides li, .pllexislider .slides > li > a { height: 100%; }
8
+
9
+ /* no list style */
10
+ .instag .no-bullet, .pllexislider .no-bullet { list-style:none; padding: 0; margin:0; }
11
+
12
+ /* Flexi Slider Template */
13
+ .pllexislider { margin: 0; position: relative; }
14
+ .flex-viewport { max-height: 2000px; -webkit-transition: all 1s ease; -moz-transition: all 1s ease; -o-transition: all 1s ease; transition: all 1s ease; }
15
+ .loading .flex-viewport { max-height: 300px; }
16
+ .pllexislider .slides { zoom: 1; }
17
+
18
+ /* Thumbnails Template */
19
+ .instag ul.thumbnails > li { margin:0 auto; display: inline-block; *display:inline; float: none; width:24% !important; }
20
+ .instag ul.thumbnails img { width: 100%; }
21
+
22
+ /* Control Nav */
23
+ .pllexislider .flex-control-nav { z-index:2; position: absolute; top: 0.8em; right:0.8em; text-align: center; }
24
+ .pllexislider .flex-control-nav li { margin: 0 3px; display: inline-block; zoom: 1; *display: inline; }
25
+ .pllexislider .flex-control-paging li a { width: 13px; border: none; height: 13px; display: block; background: #fff; background: rgba(255,255,255,255,0.5); cursor: pointer; text-indent: -9999px; -webkit-border-radius: 20px; -moz-border-radius: 20px; -o-border-radius: 20px; border-radius: 20px; -webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); -moz-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); -o-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); box-shadow: inset 0 0 2px rgba(0,0,0,0.3); }
26
+ .pllexislider .flex-control-paging li a:hover { background: #fff; background: rgba(255,255,255,0.7); }
27
+ .pllexislider .flex-control-paging li a.flex-active { background: #fff; background: rgba(255,255,255,0.9); cursor: default; }
28
+
29
+ /* Description and Time */
30
+ .pllexislider ul li .instadescription p { margin-top:5px; margin-bottom: 5px; display: block; }
31
+ .pllexislider ul li .instatime { margin-top:5px; width: 40%; float:right; text-align: right; }
32
+
{js → assets/js}/jquery.flexslider-min.js RENAMED
File without changes
css/instag-slider.css DELETED
@@ -1,31 +0,0 @@
1
- /* Flexislider Default Settings */
2
- .pllexislider { margin: 0; padding: 0; }
3
- .pllexislider .slides > li {display: none; -webkit-backface-visibility: hidden;} /* Hide the slides before the JS is loaded. Avoids image jumping */
4
- .pllexislider .slides img {width: 100%; display: block;}
5
- .pllexislider .slides:after { display: block; clear: both; visibility: hidden; line-height: 0; height: 0;}
6
- .flex-pauseplay span {text-transform: capitalize;}
7
- .pllexislider, .pllexislider .slides li, .pllexislider .slides > li > a { height: 100%; }
8
-
9
- /* no list style */
10
- .no-bullet { list-style:none; margin:0; }
11
-
12
- /* Flexi Slider Template */
13
- .pllexislider { margin: 0; position: relative; }
14
- .flex-viewport { max-height: 2000px; -webkit-transition: all 1s ease; -moz-transition: all 1s ease; -o-transition: all 1s ease; transition: all 1s ease; }
15
- .loading .flex-viewport { max-height: 300px; }
16
- .pllexislider .slides { zoom: 1; }
17
-
18
- /* Thumbnails Template */
19
- .thumbnails > li { margin:0 auto; display: inline-block; *display:inline; float: none; width:24%;}
20
-
21
- /* Control Nav */
22
- .pllexislider .flex-control-nav { z-index:2; position: absolute; top: 0.8em; right:0.8em; text-align: center;}
23
- .pllexislider .flex-control-nav li {margin: 0 3px; display: inline-block; zoom: 1; *display: inline;}
24
- .pllexislider .flex-control-paging li a {width: 13px; border: none; height: 13px; display: block; background: #fff; background: rgba(255,255,255,255,0.5); cursor: pointer; text-indent: -9999px; -webkit-border-radius: 20px; -moz-border-radius: 20px; -o-border-radius: 20px; border-radius: 20px; -webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); -moz-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); -o-box-shadow: inset 0 0 2px rgba(0,0,0,0.3); box-shadow: inset 0 0 2px rgba(0,0,0,0.3); }
25
- .pllexislider .flex-control-paging li a:hover { background: #fff; background: rgba(255,255,255,0.7); }
26
- .pllexislider .flex-control-paging li a.flex-active { background: #fff; background: rgba(255,255,255,0.9); cursor: default; }
27
-
28
- /* Description and Time */
29
- .instadescription p { margin-top:5px; margin-bottom: 5px; display: block;}
30
- .instatime { margin-top:5px; width: 40%; float:right; text-align: right; }
31
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/functions.php DELETED
@@ -1,177 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
-
4
- if ( ! function_exists( 'instag_images_data' ) ) :
5
- /**
6
- * Stores the fetched data from instagram in WordPress DB using transients
7
- *
8
- * @return array of localy saved instagram data
9
- */
10
- function instag_images_data( $username, $cache_hours, $nr_images ) {
11
-
12
- $opt_name = 'jr_insta_'.md5( $username );
13
- $instaData = get_transient( $opt_name );
14
- $user_opt = get_option( $opt_name );
15
-
16
- if (
17
- false === $instaData
18
- || $user_opt['username'] != $username
19
- || $user_opt['cache_hours'] != $cache_hours
20
- || $user_opt['nr_images'] != $nr_images
21
- )
22
- {
23
- $instaData = array();
24
- $insta_url = 'http://instagram.com/';
25
- $user_profile = $insta_url.$username;
26
- $json = wp_remote_get( $user_profile, array( 'sslverify' => false, 'timeout'=> 60 ) );
27
- $user_options = compact('username', 'cache_hours', 'nr_images');
28
- update_option($opt_name, $user_options);
29
- if ( $json['response']['code'] == 200 ) {
30
-
31
- $json = $json['body'];
32
- $json = strstr( $json, '{"entry_data"' );
33
- $json = strstr( $json, '</script>', true );
34
- $json = rtrim( $json, ';' );
35
- ( $results = json_decode( $json, true ) ) && json_last_error() == JSON_ERROR_NONE;
36
-
37
- if ( ( $results ) && is_array( $results ) ) {
38
- foreach( $results['entry_data']['UserProfile'][0]['userMedia'] as $current => $result ) {
39
-
40
- if( $current >= $nr_images ) break;
41
- $caption = $result['caption'];
42
- $image = $result['images']['standard_resolution'];
43
- $id = $result['id'];
44
- $image = $image['url'];
45
- $link = $result['link'];
46
- $created_time = $caption['created_time'];
47
- $text = utf8_4byte_to_3byte($caption['text']);
48
-
49
- $filename_data= explode('.',$image);
50
-
51
- if ( is_array( $filename_data ) ) {
52
-
53
- $fileformat = end( $filename_data );
54
-
55
- if ( $fileformat !== false ){
56
-
57
- $image = download_insta_image( $image, md5( $id ) . '.' . $fileformat );
58
- array_push( $instaData, array(
59
- 'id' => $id,
60
- 'user_name' => $username,
61
- 'user_url' => $user_profile,
62
- 'created_time'=> $created_time,
63
- 'text' => $text,
64
- 'image' => $image,
65
- 'link' => $link
66
- ));
67
-
68
- } // end -> if $fileformat !== false
69
-
70
- } // end -> is_array( $filename_data )
71
-
72
- } // end -> foreach
73
-
74
- } // end -> ( $results ) && is_array( $results ) )
75
-
76
- } // end -> $json['response']['code'] === 200 )
77
-
78
- if ( $instaData ) {
79
- set_transient( $opt_name, $instaData, $cache_hours * 60 * 60 );
80
- } // end -> true $instaData
81
-
82
- } // end -> false === $instaData
83
-
84
- return $instaData;
85
- }
86
- endif; // insta_images
87
-
88
- if ( ! function_exists( 'download_insta_image' ) ) :
89
- /**
90
- * Save Instagram images to upload folder and ads to media.
91
- * If the upload fails it returns the remote image url.
92
- *
93
- * @return url to image
94
- */
95
- function download_insta_image( $url , $file ){
96
-
97
- $local_file = JR_INSTAGWP_UPLOAD_PATH . $file;
98
-
99
- if ( file_exists( $local_file ) ) {
100
- return JR_INSTAGWP_UPLODAD_URL . $file;
101
- }
102
-
103
- $get = wp_remote_get( $url, array( 'sslverify' => false ) );
104
- $body = wp_remote_retrieve_body( $get );
105
- $upload = wp_upload_bits( $file, '', $body );
106
-
107
- if ( $upload ) {
108
- return $upload['url'];
109
- }
110
-
111
- return $url;
112
- }
113
- endif; // download_insta_image
114
-
115
- if ( ! function_exists( 'utf8_4byte_to_3byte' ) ) :
116
- /**
117
- * Sanitize 4-byte UTF8 chars; no full utf8mb4 support in drupal7+mysql stack.
118
- * This solution runs in O(n) time BUT assumes that all incoming input is
119
- * strictly UTF8.
120
- *
121
- * @return the sanitized input
122
- */
123
- function utf8_4byte_to_3byte($input) {
124
-
125
- if (!empty($input)) {
126
- $utf8_2byte = 0xC0 /*1100 0000*/; $utf8_2byte_bmask = 0xE0 /*1110 0000*/;
127
- $utf8_3byte = 0xE0 /*1110 0000*/; $utf8_3byte_bmask = 0XF0 /*1111 0000*/;
128
- $utf8_4byte = 0xF0 /*1111 0000*/; $utf8_4byte_bmask = 0xF8 /*1111 1000*/;
129
-
130
- $sanitized = "";
131
- $len = strlen($input);
132
- for ($i = 0; $i < $len; ++$i) {
133
- $mb_char = $input[$i]; // Potentially a multibyte sequence
134
- $byte = ord($mb_char);
135
- if (($byte & $utf8_2byte_bmask) == $utf8_2byte) {
136
- $mb_char .= $input[++$i];
137
- }
138
- else if (($byte & $utf8_3byte_bmask) == $utf8_3byte) {
139
- $mb_char .= $input[++$i];
140
- $mb_char .= $input[++$i];
141
- }
142
- else if (($byte & $utf8_4byte_bmask) == $utf8_4byte) {
143
- // Replace with ? to avoid MySQL exception
144
- $mb_char = '?';
145
- $i += 3;
146
- }
147
-
148
- $sanitized .= $mb_char;
149
- }
150
-
151
- $input= $sanitized;
152
- }
153
-
154
- return $input;
155
- }
156
- endif; // utf8_4byte_to_3byte
157
-
158
- if ( ! function_exists( 'instag_templates' ) ) :
159
- /**
160
- * Helper Function to insert Templates for widget
161
- *
162
- * @include file templates
163
- */
164
- function instag_templates( $template, $data_arr ){
165
-
166
- $filename = JR_INSTAGWP_PATH_TEMPLATE . $template . '.php';
167
-
168
- if(file_exists( $filename )){
169
-
170
- include $filename;
171
-
172
- } else {
173
-
174
- echo __( sprintf('Template not found<br>%s' , $filename), 'example' );
175
- }
176
- }
177
- endif; // instag_templates
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
instaram_slider.php CHANGED
@@ -2,74 +2,124 @@
2
  /*
3
  Plugin Name: Instagram Slider Widget
4
  Plugin URI: http://jrwebstudio.com/instagram-slider/
5
- Version: 1.0.1
6
  Description: Instagram Slider Widget is a responsive slider widget that shows 20 latest images from a public instagram user.
7
  Author: jetonr
8
  Author URI: http://jrwebstudio.com/
9
  License: GPLv2 or later
10
  */
11
 
12
- /* Define Constants for this widget */
13
- define('JR_INSTAGWP_PATH_BASE' , dirname(__FILE__) . DIRECTORY_SEPARATOR);
14
- define('JR_INSTAGWP_PATH_TEMPLATE' , JR_INSTAGWP_PATH_BASE . 'templates/');
15
- define('JR_INSTAGWP_PATH_INC' , JR_INSTAGWP_PATH_BASE . 'inc/');
16
- define('JR_INSTAGWP_URL' , plugins_url( '/' , __FILE__ ));
17
- define('JR_INSTAGWP_WP_VERSION' , get_bloginfo('version'));
18
- define('JR_INSTAGWP_WP_MIN_VERSION' , 3.5);
19
 
20
- $upload_dir = wp_upload_dir();
21
- define('JR_INSTAGWP_UPLOAD_PATH' , $upload_dir['path'] . '/');
22
- define('JR_INSTAGWP_UPLODAD_URL' , $upload_dir['baseurl'] . $upload_dir['subdir'] . '/');
 
23
 
24
- // Require functions need for this widget
25
- require_once ( JR_INSTAGWP_PATH_INC . 'functions.php' );
 
 
 
 
26
 
27
- /* Enqueue Frontend Plugin Styles & Scripts */
28
- function jr_insta_slider_enqueue() {
29
-
30
- // Register and enqueue Styles
31
- wp_enqueue_style( 'instag-slider', JR_INSTAGWP_URL . 'css/instag-slider.css' );
 
32
 
33
- // Register and enqueue Scripts
34
- wp_enqueue_script(
35
- 'jquery-flexi-slider',
36
- JR_INSTAGWP_URL . 'js/jquery.flexslider-min.js',
37
- array( 'jquery' ),
38
- false,
39
- true
40
- );
41
-
42
- }
43
- add_action( 'wp_enqueue_scripts', 'jr_insta_slider_enqueue' );
44
-
45
- /* Register widget on windgets init */
46
- add_action( 'widgets_init', 'jr_insta_slider_register' );
47
- function jr_insta_slider_register() {
48
- register_widget( 'JR_InstagramSlider' );
49
- }
50
 
51
- class JR_InstagramSlider extends WP_Widget {
 
52
 
53
- public function __construct() {
54
- parent::__construct(
55
- 'jr_insta_slider', //-----> Widget ID
56
- __( 'Instagram Slider', 'jrinstaslider' ), //--> Widget Name
57
- array( //-----> Widget Options Array
58
- 'classname' => 'jr-insta-slider',
59
- 'description' => __( 'A widget that displays a slider with instagram images ', 'jrinstaslider' ),
60
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  );
62
  }
63
 
64
- function widget( $args, $instance ) {
 
 
 
 
 
65
  extract( $args );
66
 
67
  //Our variables from the widget settings.
68
  $title = apply_filters('widget_title', $instance['title'] );
69
  $username = $instance['username'];
 
 
70
  $images_nr = $instance['images_number'];
71
  $refresh_hour = $instance['refresh_hour'];
72
  $template = $instance['template'];
 
73
 
74
  echo $before_widget;
75
 
@@ -78,46 +128,69 @@ class JR_InstagramSlider extends WP_Widget {
78
  echo $before_title . $title . $after_title;
79
  }
80
  // Get instagram data
81
- $insta_data = instag_images_data($username, $refresh_hour, $images_nr );
82
 
 
 
 
83
  //include the template based on user choice
84
- instag_templates( $template, $insta_data );
85
 
86
  echo $after_widget;
87
  }
88
 
89
- //Update the widget
90
-
91
- function update( $new_instance, $old_instance ) {
 
 
 
 
 
 
92
  $instance = $old_instance;
93
 
94
  //Strip tags from title and name to remove HTML
95
  $instance['title'] = strip_tags( $new_instance['title'] );
96
  $instance['username'] = $new_instance['username'];
 
 
 
97
  $instance['images_number'] = $new_instance['images_number'];
98
  $instance['refresh_hour'] = $new_instance['refresh_hour'];
99
- $instance['template'] = $new_instance['template'];
100
 
101
  return $instance;
102
  }
103
 
104
-
105
- function form( $instance ) {
 
 
 
 
106
 
107
  //Set up some default widget settings.
108
- $defaults = array( 'title' => __('Instagram Slider', 'jrinstaslider'), 'username' => __('', 'jrinstaslider'), 'images_number' => 5, 'refresh_hour' => 5, 'template' => 'slider' );
 
 
 
 
 
 
 
 
 
109
  $instance = wp_parse_args( (array) $instance, $defaults ); ?>
110
 
111
  <p>
112
  <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e('Title:', 'jrinstaslider'); ?></label>
113
  <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" />
114
  </p>
115
-
116
  <p>
117
  <label for="<?php echo $this->get_field_id( 'username' ); ?>"><?php _e('Instagram Username:', 'jrinstaslider'); ?></label>
118
  <input class="widefat" id="<?php echo $this->get_field_id( 'username' ); ?>" name="<?php echo $this->get_field_name( 'username' ); ?>" value="<?php echo $instance['username']; ?>" />
119
  </p>
120
-
121
  <p>
122
  <label for="<?php echo $this->get_field_id( 'template' ); ?>"><?php _e( 'Images Layout', 'jrinstaslider' ); ?>
123
  <select class="widefat" name="<?php echo $this->get_field_name( 'template' ); ?>">
@@ -126,21 +199,344 @@ class JR_InstagramSlider extends WP_Widget {
126
  </select>
127
  </label>
128
  </p>
129
-
 
 
 
 
 
 
 
 
130
  <p>
131
  <label for="<?php echo $this->get_field_id( 'images_number' ); ?>"><?php _e('Number of Images to Show:', 'jrinstaslider'); ?>
132
  <input class="small-text" id="<?php echo $this->get_field_id( 'images_number' ); ?>" name="<?php echo $this->get_field_name( 'images_number' ); ?>" value="<?php echo $instance['images_number']; ?>" />
133
  <small><?php _e('( max 20 )', 'jrinstaslider'); ?></small>
134
  </label>
135
  </p>
136
-
137
  <p>
138
  <label for="<?php echo $this->get_field_id( 'refresh_hour' ); ?>"><?php _e('Check for new images every:', 'jrinstaslider'); ?>
139
  <input class="small-text" id="<?php echo $this->get_field_id( 'refresh_hour' ); ?>" name="<?php echo $this->get_field_name( 'refresh_hour' ); ?>" value="<?php echo $instance['refresh_hour']; ?>" />
140
  <small><?php _e('hours', 'jrinstaslider'); ?></small>
141
  </label>
142
  </p>
143
-
 
 
 
144
  <?php
145
  }
146
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  /*
3
  Plugin Name: Instagram Slider Widget
4
  Plugin URI: http://jrwebstudio.com/instagram-slider/
5
+ Version: 1.0.4
6
  Description: Instagram Slider Widget is a responsive slider widget that shows 20 latest images from a public instagram user.
7
  Author: jetonr
8
  Author URI: http://jrwebstudio.com/
9
  License: GPLv2 or later
10
  */
11
 
12
+ /**
13
+ * After the plugins have loaded initalise a single instance of JR_InstagramSlider
14
+ */
15
+ add_action( 'plugins_loaded', array( 'JR_InstagramSlider', 'get_instance' ) );
 
 
 
16
 
17
+ /**
18
+ * JR_InstagramSlider Class
19
+ */
20
+ class JR_InstagramSlider extends WP_Widget {
21
 
22
+ /**
23
+ * Plugin version, used for cache-busting of style and script file references.
24
+ *
25
+ * @var string
26
+ */
27
+ const VERSION = '1.0.4';
28
 
29
+ /**
30
+ * Instance of this class.
31
+ *
32
+ * @var object
33
+ */
34
+ protected static $instance = null;
35
 
36
+ /**
37
+ * Initialize the plugin by registering widget and loading public scripts
38
+ *
39
+ */
40
+ public function __construct() {
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ // Register Widget On Widgets Init
43
+ add_action( 'widgets_init', array( $this, 'register_widget' ) );
44
 
45
+ // Enqueue Plugin Styles and scripts
46
+ add_action( 'wp_enqueue_scripts', array( $this, 'public_enqueue' ) );
47
+
48
+
49
+ $widget_options = array(
50
+ 'classname' => 'jr-insta-slider',
51
+ 'description' => __( 'A widget that displays a slider with instagram images ', 'jrinstaslider' )
52
+ );
53
+
54
+ parent::__construct( 'jr_insta_slider', __('Instagram Slider', 'jrinstaslider'), $widget_options );
55
+ }
56
+
57
+ /**
58
+ * Return an instance of this class.
59
+ *
60
+ * @return object A single instance of this class.
61
+ */
62
+ public static function get_instance() {
63
+
64
+ // If the single instance hasn't been set, set it now.
65
+ if ( null == self::$instance ) {
66
+ self::$instance = new self;
67
+ }
68
+
69
+ return self::$instance;
70
+ }
71
+
72
+ /**
73
+ * Register widget on windgets init
74
+ *
75
+ * @return void
76
+ */
77
+ public function register_widget() {
78
+ register_widget( __CLASS__ );
79
+ }
80
+
81
+ /**
82
+ * Enqueue public-facing Scripts and style sheet.
83
+ *
84
+ * @return void
85
+ */
86
+ public function public_enqueue() {
87
+
88
+ // Enqueue Styles
89
+ wp_enqueue_style(
90
+ 'instag-slider',
91
+ plugins_url( 'assets/css/instag-slider.css', __FILE__ ),
92
+ array(),
93
+ self::VERSION
94
+ );
95
+
96
+ // Enqueue Scripts
97
+ wp_enqueue_script(
98
+ 'jquery-flexi-slider',
99
+ plugins_url( 'assets/js/jquery.flexslider-min.js', __FILE__ ),
100
+ array( 'jquery' ),
101
+ '2.2',
102
+ true
103
  );
104
  }
105
 
106
+ /**
107
+ * The Public view of the Widget
108
+ *
109
+ * @return mixed
110
+ */
111
+ public function widget( $args, $instance ) {
112
  extract( $args );
113
 
114
  //Our variables from the widget settings.
115
  $title = apply_filters('widget_title', $instance['title'] );
116
  $username = $instance['username'];
117
+ $link_to = $instance['images_link'];
118
+ $randomise = isset( $instance['randomise'] ) ? true : false;
119
  $images_nr = $instance['images_number'];
120
  $refresh_hour = $instance['refresh_hour'];
121
  $template = $instance['template'];
122
+ $attachment = isset( $instance['attachment'] ) ? true : false;
123
 
124
  echo $before_widget;
125
 
128
  echo $before_title . $title . $after_title;
129
  }
130
  // Get instagram data
131
+ $insta_data = $this->instagram_data( $username, $refresh_hour, $images_nr, $attachment );
132
 
133
+ // Randomise Images
134
+ $insta_data = $this->randomise( $insta_data, $randomise );
135
+
136
  //include the template based on user choice
137
+ $this->template( $template, $insta_data, $link_to );
138
 
139
  echo $after_widget;
140
  }
141
 
142
+ /**
143
+ * Update the widget settings
144
+ *
145
+ * @param array $new_instance New instance values
146
+ * @param array $old_instance Old instance values
147
+ *
148
+ * @return array
149
+ */
150
+ public function update( $new_instance, $old_instance ) {
151
  $instance = $old_instance;
152
 
153
  //Strip tags from title and name to remove HTML
154
  $instance['title'] = strip_tags( $new_instance['title'] );
155
  $instance['username'] = $new_instance['username'];
156
+ $instance['template'] = $new_instance['template'];
157
+ $instance['images_link'] = $new_instance['images_link'];
158
+ $instance['randomise'] = $new_instance['randomise'];
159
  $instance['images_number'] = $new_instance['images_number'];
160
  $instance['refresh_hour'] = $new_instance['refresh_hour'];
161
+ $instance['attachment'] = $new_instance['attachment'];
162
 
163
  return $instance;
164
  }
165
 
166
+ /**
167
+ * Widget Settings Form
168
+ *
169
+ * @return mixed
170
+ */
171
+ public function form( $instance ) {
172
 
173
  //Set up some default widget settings.
174
+ $defaults = array(
175
+ 'title' => __('Instagram Slider', 'jrinstaslider'),
176
+ 'username' => __('', 'jrinstaslider'),
177
+ 'template' => 'slider',
178
+ 'images_link' => 'image_url',
179
+ 'randomise' => 0,
180
+ 'images_number' => 5,
181
+ 'refresh_hour' => 5,
182
+ 'attachment' => 0,
183
+ );
184
  $instance = wp_parse_args( (array) $instance, $defaults ); ?>
185
 
186
  <p>
187
  <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e('Title:', 'jrinstaslider'); ?></label>
188
  <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" />
189
  </p>
 
190
  <p>
191
  <label for="<?php echo $this->get_field_id( 'username' ); ?>"><?php _e('Instagram Username:', 'jrinstaslider'); ?></label>
192
  <input class="widefat" id="<?php echo $this->get_field_id( 'username' ); ?>" name="<?php echo $this->get_field_name( 'username' ); ?>" value="<?php echo $instance['username']; ?>" />
193
  </p>
 
194
  <p>
195
  <label for="<?php echo $this->get_field_id( 'template' ); ?>"><?php _e( 'Images Layout', 'jrinstaslider' ); ?>
196
  <select class="widefat" name="<?php echo $this->get_field_name( 'template' ); ?>">
199
  </select>
200
  </label>
201
  </p>
202
+ <p>
203
+ <?php _e('Link Images To:', 'jrinstaslider'); ?><br>
204
+ <label><input type="radio" id="<?php echo $this->get_field_id( 'images_link' ); ?>" name="<?php echo $this->get_field_name( 'images_link' ); ?>" value="image_url" <?php checked( 'image_url', $instance['images_link'] ); ?> /> <?php _e('Instagram Image URL', 'jrinstaslider'); ?></label><br />
205
+ <label><input type="radio" id="<?php echo $this->get_field_id( 'images_link' ); ?>" name="<?php echo $this->get_field_name( 'images_link' ); ?>" value="user_url" <?php checked( 'user_url', $instance['images_link'] ); ?> /> <?php _e('Instagram Profile URL', 'jrinstaslider'); ?></label><br />
206
+ </p>
207
+ <p>
208
+ <label for="<?php echo $this->get_field_id( 'randomise' ); ?>"><?php _e( 'Randomise Images:', 'jrinstaslider' ); ?></label>
209
+ <input class="widefat" id="<?php echo $this->get_field_id( 'randomise' ); ?>" name="<?php echo $this->get_field_name( 'randomise' ); ?>" type="checkbox" value="1" <?php checked( '1', $instance['randomise'] ); ?> />
210
+ </p>
211
  <p>
212
  <label for="<?php echo $this->get_field_id( 'images_number' ); ?>"><?php _e('Number of Images to Show:', 'jrinstaslider'); ?>
213
  <input class="small-text" id="<?php echo $this->get_field_id( 'images_number' ); ?>" name="<?php echo $this->get_field_name( 'images_number' ); ?>" value="<?php echo $instance['images_number']; ?>" />
214
  <small><?php _e('( max 20 )', 'jrinstaslider'); ?></small>
215
  </label>
216
  </p>
 
217
  <p>
218
  <label for="<?php echo $this->get_field_id( 'refresh_hour' ); ?>"><?php _e('Check for new images every:', 'jrinstaslider'); ?>
219
  <input class="small-text" id="<?php echo $this->get_field_id( 'refresh_hour' ); ?>" name="<?php echo $this->get_field_name( 'refresh_hour' ); ?>" value="<?php echo $instance['refresh_hour']; ?>" />
220
  <small><?php _e('hours', 'jrinstaslider'); ?></small>
221
  </label>
222
  </p>
223
+ <p>
224
+ <label for="<?php echo $this->get_field_id( 'attachment' ); ?>"><?php _e( 'Insert images into Media Library:', 'jrinstaslider' ); ?></label>
225
+ <input class="widefat" id="<?php echo $this->get_field_id( 'attachment' ); ?>" name="<?php echo $this->get_field_name( 'attachment' ); ?>" type="checkbox" value="1" <?php checked( '1', $instance['attachment'] ); ?> />
226
+ </p>
227
  <?php
228
  }
229
+
230
+ /**
231
+ * Randomises an array using php shuffle() function
232
+ *
233
+ * @param array $data Instagram data array
234
+ * @param bolean $randomise True or false to randomise
235
+ *
236
+ * @return array of randomised data
237
+ */
238
+ private function randomise( $data, $randomise = false ) {
239
+
240
+ if ( true == $randomise ) {
241
+ shuffle( $data );
242
+ }
243
+ return $data;
244
+ }
245
+
246
+ /**
247
+ * Stores the fetched data from instagram in WordPress DB using transients
248
+ *
249
+ * @param string $username Instagram Username to fetch images from
250
+ * @param string $cache_hours Cache hours for transient
251
+ * @param string $nr_images Nr of images to fetch from instagram
252
+ *
253
+ * @return array of localy saved instagram data
254
+ */
255
+ private function instagram_data( $username, $cache_hours, $nr_images, $media_library = false ) {
256
+
257
+ $opt_name = 'jr_insta_'.md5( $username );
258
+ $instaData = get_transient( $opt_name );
259
+ $user_opt = get_option( $opt_name );
260
+
261
+ if (
262
+ false === $instaData
263
+ || $user_opt['username'] != $username
264
+ || $user_opt['cache_hours'] != $cache_hours
265
+ || $user_opt['nr_images'] != $nr_images
266
+ )
267
+ {
268
+ $instaData = array();
269
+ $insta_url = 'http://instagram.com/';
270
+ $user_profile = $insta_url.$username;
271
+ $json = wp_remote_get( $user_profile, array( 'sslverify' => false, 'timeout'=> 60 ) );
272
+ $user_options = compact('username', 'cache_hours', 'nr_images');
273
+
274
+ update_option( $opt_name, $user_options );
275
+
276
+ if ( $json['response']['code'] == 200 ) {
277
+
278
+ $json = $json['body'];
279
+ $json = strstr( $json, '{"entry_data"' );
280
+
281
+ // Compatibility for version of php where strstr() doesnt accept third parameter
282
+ if ( version_compare( phpversion(), '5.3.10', '<' ) ) {
283
+ $json = substr( $json, 0, strpos($json, '</script>' ) );
284
+ } else {
285
+ $json = strstr( $json, '</script>', true );
286
+ }
287
+
288
+ $json = rtrim( $json, ';' );
289
+
290
+ // Function json_last_error() is not available before PHP * 5.3.0 version
291
+ if ( function_exists( 'json_last_error' ) ) {
292
+
293
+ ( $results = json_decode( $json, true ) ) && json_last_error() == JSON_ERROR_NONE;
294
+
295
+ } else {
296
+
297
+ $results = json_decode( $json, true );
298
+ }
299
+
300
+ if ( ( $results ) && is_array( $results ) ) {
301
+ foreach( $results['entry_data']['UserProfile'][0]['userMedia'] as $current => $result ) {
302
+
303
+ if( $current >= $nr_images ) break;
304
+ $caption = $result['caption'];
305
+ $image = $result['images']['standard_resolution'];
306
+ $id = $result['id'];
307
+ $image = $image['url'];
308
+ $link = $result['link'];
309
+ $created_time = $caption['created_time'];
310
+ $text = $this->utf8_4byte_to_3byte($caption['text']);
311
+ $upload_dir = wp_upload_dir();
312
+ $filename_data= explode( '.', $image );
313
+
314
+ if ( is_array( $filename_data ) ) {
315
+
316
+ $fileformat = end( $filename_data );
317
+
318
+ if ( $fileformat !== false ){
319
+
320
+
321
+ $image = $this->download_insta_image( $image, md5( $id ) . '.' . $fileformat );
322
+
323
+ array_push( $instaData, array(
324
+ 'id' => $id,
325
+ 'user_name' => $username,
326
+ 'user_url' => $user_profile,
327
+ 'created_time' => $created_time,
328
+ 'text' => $text,
329
+ 'image' => $image,
330
+ 'image_path' => $upload_dir['path'] . '/' . md5( $id ) . '.' . $fileformat,
331
+ 'link' => $link
332
+ ));
333
+
334
+ } // end -> if $fileformat !== false
335
+
336
+ } // end -> is_array( $filename_data )
337
+
338
+ } // end -> foreach
339
+
340
+ } // end -> ( $results ) && is_array( $results ) )
341
+
342
+ } // end -> $json['response']['code'] === 200 )
343
+
344
+ if ( $instaData ) {
345
+ set_transient( $opt_name, $instaData, $cache_hours * 60 * 60 );
346
+ } // end -> true $instaData
347
+
348
+ } // end -> false === $instaData
349
+
350
+ // Insert into Media Library
351
+ if ( true == $media_library ) {
352
+
353
+ $media_library = array();
354
+
355
+ foreach ( $instaData as $media_item ) {
356
+
357
+ $media_library['title'] = $media_item['text'];
358
+ $media_library['path'] = $media_item['image_path'];
359
+ $media_library['src'] = $media_item['image'];
360
+
361
+ $this->insert_into_media( $media_library );
362
+ }
363
+ }
364
+
365
+ return $instaData;
366
+ }
367
+
368
+ /**
369
+ * Function to display Templates for widget
370
+ *
371
+ * @param string $template The input to be sanitised
372
+ * @param array $data_arr The input to be sanitised
373
+ * @param string $link_to The input to be sanitised
374
+ *
375
+ * @include file templates
376
+ *
377
+ * return void
378
+ */
379
+ private function template( $template, $data_arr, $link_to ){
380
+
381
+ $filename = plugin_dir_path( __FILE__ ) . "views/" . $template . '.php';
382
+
383
+ if( file_exists( $filename ) ){
384
+
385
+ include $filename;
386
+
387
+ } else {
388
+
389
+ echo __( sprintf( 'Template not found<br>%s' , $filename), 'jrinstaslider' );
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Save Instagram images to upload folder and ads to media.
395
+ * If the upload fails it returns the remote image url.
396
+ *
397
+ * @param string $url Url of image to download
398
+ * @param string $file File path for image
399
+ *
400
+ * @return string $url Url to image
401
+ */
402
+ private function download_insta_image( $url, $file ){
403
+
404
+ $upload_dir = wp_upload_dir();
405
+ $local_file = $upload_dir['path'] . '/' . $file;
406
+
407
+ if ( file_exists( $local_file ) ) {
408
+ return $upload_dir['baseurl'] . $upload_dir['subdir'] . '/' . $file;
409
+ }
410
+
411
+ $get = wp_remote_get( $url, array( 'sslverify' => false ) );
412
+ $body = wp_remote_retrieve_body( $get );
413
+ $upload = wp_upload_bits( $file, '', $body );
414
+
415
+ if ( false === $upload['error'] ) {
416
+
417
+ return $upload['url'];
418
+ }
419
+
420
+ return $url;
421
+ }
422
+
423
+ /**
424
+ * Insert Images to media library.
425
+ *
426
+ * @param array $attachment_data Data for attachemnt
427
+ *
428
+ * @return void
429
+ */
430
+ private function insert_into_media( $attachment_data = array() ) {
431
+
432
+ if ( ! $this->get_attachment_id_from_src( $attachment_data['src'] ) ) {
433
+
434
+ // Check the type of tile. We'll use this as the 'post_mime_type'.
435
+ $filetype = wp_check_filetype( $attachment_data['path'], null );
436
+ $attch_title = trim( preg_replace( '/([@]{1})([a-zA-Z0-9\_]+)|#(\w*[a-zA-Z_]+\w*)|\?/i', '', $attachment_data['title'] ) );
437
+
438
+ if ( '' == $attch_title ) {
439
+ $attch_title = basename( $attachment_data['path'] );
440
+ }
441
+
442
+ // Prepare an array of post data for the attachment.
443
+ $attachment = array(
444
+ 'guid' => $attachment_data['src'],
445
+ 'post_mime_type' => $filetype['type'],
446
+ 'post_title' => $attch_title,
447
+ 'post_content' => '',
448
+ 'post_status' => 'inherit'
449
+ );
450
+
451
+ // Insert the attachment.
452
+ $attach_id = wp_insert_attachment( $attachment, $attachment_data['path'] );
453
+
454
+ // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
455
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
456
+
457
+ // Generate the metadata for the attachment, and update the database record.
458
+ $attach_data = wp_generate_attachment_metadata( $attach_id, $attachment_data['path']);
459
+ wp_update_attachment_metadata( $attach_id, $attach_data );
460
+ }
461
+
462
+ }
463
+
464
+ /**
465
+ * Get Attachment Id from image source
466
+ *
467
+ * @param string $image_src Url of image to get id from
468
+ *
469
+ * @return string $id Returns attachement id
470
+ */
471
+ private function get_attachment_id_from_src( $url ) {
472
+
473
+ // Split the $url into two parts with the wp-content directory as the separator.
474
+ $parse_url = explode( parse_url( WP_CONTENT_URL, PHP_URL_PATH ), $url );
475
+
476
+ // Get the host of the current site and the host of the $url, ignoring www.
477
+ $this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
478
+ $file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
479
+
480
+ // Return false if there aren't any $url parts or if the current host and $url host do not match.
481
+ if ( ! isset( $parse_url[1] ) || empty( $parse_url[1] ) || ( $this_host != $file_host ) ) {
482
+ return false;
483
+ }
484
+
485
+ // Now we're going to quickly search the DB for any attachment GUID with a partial path match.
486
+ // Example: /uploads/2013/05/test-image.jpg
487
+ global $wpdb;
488
+
489
+ $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}posts WHERE guid RLIKE %s;", $parse_url[1] ) );
490
+
491
+ // Returns attachment if isset.
492
+ if ( isset( $attachment[0] ) ) {
493
+ return $attachment[0];
494
+ }
495
+
496
+ return false;
497
+ }
498
+
499
+ /**
500
+ * Sanitize 4-byte UTF8 chars; no full utf8mb4 support in drupal7+mysql stack.
501
+ * This solution runs in O(n) time BUT assumes that all incoming input is
502
+ * strictly UTF8.
503
+ *
504
+ * @param string $input The input to be sanitised
505
+ *
506
+ * @return the sanitized input
507
+ */
508
+ private function utf8_4byte_to_3byte( $input ) {
509
+
510
+ if (!empty($input)) {
511
+ $utf8_2byte = 0xC0 /*1100 0000*/; $utf8_2byte_bmask = 0xE0 /*1110 0000*/;
512
+ $utf8_3byte = 0xE0 /*1110 0000*/; $utf8_3byte_bmask = 0XF0 /*1111 0000*/;
513
+ $utf8_4byte = 0xF0 /*1111 0000*/; $utf8_4byte_bmask = 0xF8 /*1111 1000*/;
514
+
515
+ $sanitized = "";
516
+ $len = strlen($input);
517
+ for ($i = 0; $i < $len; ++$i) {
518
+ $mb_char = $input[$i]; // Potentially a multibyte sequence
519
+ $byte = ord($mb_char);
520
+ if (($byte & $utf8_2byte_bmask) == $utf8_2byte) {
521
+ $mb_char .= $input[++$i];
522
+ }
523
+ else if (($byte & $utf8_3byte_bmask) == $utf8_3byte) {
524
+ $mb_char .= $input[++$i];
525
+ $mb_char .= $input[++$i];
526
+ }
527
+ else if (($byte & $utf8_4byte_bmask) == $utf8_4byte) {
528
+ // Replace with ? to avoid MySQL exception
529
+ $mb_char = '?';
530
+ $i += 3;
531
+ }
532
+
533
+ $sanitized .= $mb_char;
534
+ }
535
+
536
+ $input= $sanitized;
537
+ }
538
+
539
+ return $input;
540
+ }
541
+
542
+ } // end of class JR_InstagramSlider
readme.txt CHANGED
@@ -15,6 +15,9 @@ Instagram Slider Widget is a responsive slider widget that shows 20 latest image
15
  * Images are stored in your wordpress upload folder.
16
  * Display Images in Slider or Thumbnails
17
  * No Api Key Needed
 
 
 
18
  * For more info visit http://jrwebstudio.com/
19
 
20
  == Installation ==
@@ -29,6 +32,19 @@ Instagram Slider Widget is a responsive slider widget that shows 20 latest image
29
  3. Backend Configuration
30
 
31
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  = 1.0.1 =
33
  * Removed preg_match
34
  * Using exact array index
15
  * Images are stored in your wordpress upload folder.
16
  * Display Images in Slider or Thumbnails
17
  * No Api Key Needed
18
+ * Link images to user profile or image url
19
+ * Option to Randomise order of instagram images
20
+ * Option to insert images into WordPress Media Library
21
  * For more info visit http://jrwebstudio.com/
22
 
23
  == Installation ==
32
  3. Backend Configuration
33
 
34
  == Changelog ==
35
+ = 1.0.4 =
36
+ * Added Option to insert images into media library
37
+ * Fixed error caused by missing json_last_error() function ( php older than 5.3 only )
38
+
39
+ = 1.0.3 =
40
+ * Added Option to link images to User Profile or Image Url
41
+ * Code Cleanup
42
+
43
+ = 1.0.2 =
44
+ * Compatibility for php older than 5.3
45
+ * Stlying fix for thumbnail layout
46
+ * Added Option to Randomise Images
47
+
48
  = 1.0.1 =
49
  * Removed preg_match
50
  * Using exact array index
{templates → views}/slider.php RENAMED
@@ -14,6 +14,11 @@ jQuery(document).ready(function($) {
14
  foreach ( $data as $k => $v) {
15
  $$k = $v;
16
  }
 
 
 
 
 
17
  echo '<li>'. "\n";
18
  echo '<a target="_blank" href="'.$link.'"><img src="'.$image.'" alt="'.$text.'"></a>' . "\n";
19
  if ( $created_time ) {
14
  foreach ( $data as $k => $v) {
15
  $$k = $v;
16
  }
17
+
18
+ if ( $link_to && ( 'user_url' == $link_to ) ) {
19
+ $link = $user_url;
20
+ }
21
+
22
  echo '<li>'. "\n";
23
  echo '<a target="_blank" href="'.$link.'"><img src="'.$image.'" alt="'.$text.'"></a>' . "\n";
24
  if ( $created_time ) {
{templates → views}/thumbs.php RENAMED
@@ -2,11 +2,16 @@
2
  <div class="instag">
3
  <ul class="thumbnails no-bullet">
4
  <?php
5
- if ( isset($data_arr) && is_array($data_arr) ) {
6
- foreach ($data_arr as $data) {
7
- foreach ( $data as $k => $v) {
8
  $$k = $v;
9
  }
 
 
 
 
 
10
  echo '<li>'. "\n";
11
  echo '<a target="_blank" href="'.$link.'"><img src="'.$image.'" alt="'.$text.'"></a>' . "\n";
12
  echo '</li>' . "\n";
2
  <div class="instag">
3
  <ul class="thumbnails no-bullet">
4
  <?php
5
+ if ( isset( $data_arr ) && is_array( $data_arr ) ) {
6
+ foreach ( $data_arr as $data ) {
7
+ foreach ( $data as $k => $v ) {
8
  $$k = $v;
9
  }
10
+
11
+ if ( $link_to && 'user_url' == $link_to ) {
12
+ $link = $user_url;
13
+ }
14
+
15
  echo '<li>'. "\n";
16
  echo '<a target="_blank" href="'.$link.'"><img src="'.$image.'" alt="'.$text.'"></a>' . "\n";
17
  echo '</li>' . "\n";