Instagram Feed - Version 2.0

Version Description

  • MAJOR UDPATE
  • New: We've rebuilt the plugin from the ground up with a focus on performance and reliability. Your feeds are now loaded from the server using PHP removing the reliance on AJAX.
  • New: Local copies of images are now automatically stored on your server and used in your feed. You can disable this feature in the "Advanced" section of the "Customize" tab. Use the "Favor Local Images" setting on the "Customize" tab, "Advanced" sub-tab to have the plugin use local images whenever available, thus removing reliance on the Instagram CDN.
  • New: You can now set the plugin to check for new Instagram posts in the background rather than when the page loads by using the new "Background caching" option which utilizes the WordPress "cron" feature. Enable this using the "Check for new posts" setting on the "Configure" tab.
  • New: If you have a business account for Instagram, you can now connect to the new Instagram API. You can continue to use your connected personal account and do not need to connect a business account.
Download this release

Release Info

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

Code changes from version 1.12.2 to 2.0

README.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Smash Balloon Social Photo Feed ===
2
  Contributors: smashballoon, craig-at-smash-balloon
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
- Requires at least: 3.0
5
  Tested up to: 5.2
6
- Stable tag: 1.12.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -324,6 +324,13 @@ We understand that sometimes you need help, have issues or just have questions.
324
  * Plus more customization options added all the time!
325
 
326
  == Changelog ==
 
 
 
 
 
 
 
327
  = 1.12.2 =
328
  * Fix: Fixed error from Instagram when connecting a personal account.
329
 
1
  === Smash Balloon Social Photo Feed ===
2
  Contributors: smashballoon, craig-at-smash-balloon
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
+ Requires at least: 3.4
5
  Tested up to: 5.2
6
+ Stable tag: 2.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
324
  * Plus more customization options added all the time!
325
 
326
  == Changelog ==
327
+ = 2.0 =
328
+ * **MAJOR UDPATE**
329
+ * New: We've rebuilt the plugin from the ground up with a focus on performance and reliability. Your feeds are now loaded from the server using PHP removing the reliance on AJAX.
330
+ * New: Local copies of images are now automatically stored on your server and used in your feed. You can disable this feature in the "Advanced" section of the "Customize" tab. Use the "Favor Local Images" setting on the "Customize" tab, "Advanced" sub-tab to have the plugin use local images whenever available, thus removing reliance on the Instagram CDN.
331
+ * New: You can now set the plugin to check for new Instagram posts in the background rather than when the page loads by using the new "Background caching" option which utilizes the WordPress "cron" feature. Enable this using the "Check for new posts" setting on the "Configure" tab.
332
+ * New: If you have a business account for Instagram, you can now connect to the new Instagram API. You can continue to use your connected personal account and do not need to connect a business account.
333
+
334
  = 1.12.2 =
335
  * Fix: Fixed error from Instagram when connecting a personal account.
336
 
css/sb-instagram-admin.css CHANGED
@@ -123,7 +123,7 @@
123
  }
124
 
125
  #sbi_admin .sbi_radio_label{
126
- width: 90px;
127
  padding-top: 5px;
128
 
129
  display: -moz-inline-stack;
@@ -156,6 +156,28 @@
156
  -webkit-border-radius: 2px;
157
  border-radius: 2px;
158
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  /* License */
161
  #sbi_admin .sbi_license_status{
@@ -179,6 +201,13 @@
179
  width: 100%;
180
  clear: left;
181
  }
 
 
 
 
 
 
 
182
  #sbi_admin .sbi_pro,
183
  #sbi_admin .sbi_pro label,
184
  #sbi_admin .sbi_pro input,
@@ -381,7 +410,7 @@
381
  -webkit-border-radius: 4px;
382
  border-radius: 4px;
383
  }
384
- .sbi_review_notice .ctf-notice-text{
385
  float: left;
386
  clear: none;
387
  width: 100%;
@@ -410,7 +439,9 @@
410
  .sbi_review_notice .links a:first-child{
411
  /*padding-left: 0;*/
412
  }
413
- .sbi_review_notice .sbi_notice_close{
 
 
414
  position: absolute;
415
  top: 0;
416
  right: 0;
@@ -581,7 +612,7 @@
581
  #sbi_admin .sbi_connected_account {
582
  position: relative;
583
  box-sizing: border-box;
584
- padding: 10px 35px 10px 10px;;
585
  border-radius: 5px;
586
  background: #fff;
587
  margin-bottom: 5px;
@@ -589,30 +620,37 @@
589
  clear: both;
590
  border: 1px solid #ddd;
591
  }
 
 
 
 
 
 
592
  #sbi_admin .sbi_connected_account .sbi_ca_avatar{
593
  margin-right: 15px;
594
  }
595
  #sbi_admin .sbi_connected_account .sbi_ca_username {
596
  margin-left: 0;
597
- margin-right: 15px;
598
  }
599
- #sbi_admin .sbi_ca_username {
600
- line-height: 38px;
601
- margin-left: 15px;
602
  float: left;
603
- font-size: 18px;
604
  }
 
 
 
 
 
 
 
 
 
605
  #sbi_admin .sbi_ca_actions {
606
  display: inline-block;
607
  }
608
  #sbi_admin .sbi_ca_actions .fa{
609
  margin-right: 5px;
610
  }
611
- #sbi_admin .sbi_delete_account .sbi_remove_text{
612
- display: inline-block;
613
- margin-left: 5px;
614
- padding: 5px 10px 5px 0;
615
- }
616
  #sbi_admin .sbi_ca_actions a.button-primary,
617
  #sbi_admin .sbi_ca_actions a.button-secondary,
618
  #sbi_admin .sbi_ca_accesstoken a.sbi_ca_token_shortcode {
@@ -714,7 +752,7 @@
714
  right: 10px;
715
  top: 10px;
716
 
717
- padding: 0;
718
  background: rgba(0,0,0,0.05);
719
  color: #666;
720
  border-radius: 50px;
@@ -726,8 +764,8 @@
726
  background: #333;
727
  color: #ddd;
728
  }
729
- #sbi_admin .sbi_delete_account .fa{
730
- padding: 5px 0 5px 10px;
731
  }
732
 
733
  .sbi_connected_accounts_wrap{
@@ -735,10 +773,10 @@
735
  }
736
  #sbi_admin .sbi_no_accounts{
737
  display: inline-block;
738
- padding: 6px 12px;
739
  border-radius: 8px;
740
  background: rgba(255,255,255,0.8);
741
- margin-bottom: 5px;
742
  }
743
  #sbi_admin #sbi_manual_submit:active{
744
  vertical-align: unset;
@@ -750,14 +788,88 @@
750
  padding-top: 5px;
751
  }
752
  #sbi_admin .sbi_user_feed_account_wrap:last-child{
753
- padding-bottom: 10px;
754
  }
755
  #sbi_admin .sbi_user_feed_account_wrap{
756
  padding-bottom: 5px;
 
757
  }
758
  #sbi_admin .sbi_user_feed_account_wrap span{
759
  font-size: 13px;
760
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
  /*#sbi_admin .sbi_remove_from_user_feed{
762
  background: #71ad26;
763
  color: #fff;
@@ -860,14 +972,13 @@
860
  }
861
  #sbi_config_info .sbi_config_modal{
862
  position: absolute;
863
- top: 180px;
864
  left: 50%;
865
- width: 350px;
866
 
867
- margin: 0 0 0 -195px;
868
  padding: 20px;
869
  background: #fff;
870
- text-align: center;
871
 
872
  -webkit-box-shadow: 0 1px 20px rgba(0,0,0,0.2);
873
  box-shadow: 0 1px 20px rgba(0,0,0,0.2);
@@ -876,6 +987,16 @@
876
  -webkit-border-radius: 3px;
877
  border-radius: 3px;
878
  }
 
 
 
 
 
 
 
 
 
 
879
  .sb_get_token .submit {
880
  display: inline-block;
881
  margin: 0 0 0 10px;
@@ -923,6 +1044,38 @@
923
  color: #333;
924
  }
925
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
  /* Pro 3.0 Styles */
927
  .sbi_layout_cell {
928
  padding: 0;
@@ -1131,4 +1284,109 @@
1131
  top: -10px;
1132
  bottom: auto;
1133
  margin-left: -101px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1134
  }
123
  }
124
 
125
  #sbi_admin .sbi_radio_label{
126
+ width: 95px;
127
  padding-top: 5px;
128
 
129
  display: -moz-inline-stack;
156
  -webkit-border-radius: 2px;
157
  border-radius: 2px;
158
  }
159
+ /* Caching settings */
160
+ #sbi_admin #sbi-caching-time-settings{
161
+ display: inline-block;
162
+ }
163
+ #sbi_admin .sbi-caching-cron-options .submit{
164
+ display: inline-block;
165
+ margin: 0;
166
+ padding: 0;
167
+ }
168
+ #sbi_admin .sbi-caching-sched-notice{
169
+ font-size: 11px;
170
+ display: block;
171
+ width: 100%;
172
+ }
173
+ #sbi_admin .sbi-caching-sched-notice span{
174
+ color: green;
175
+ background: #e5eae1;
176
+ padding: 5px 10px;
177
+ border-radius: 5px;
178
+ border: 1px solid #ccd3c6;
179
+ display: inline-block;
180
+ }
181
 
182
  /* License */
183
  #sbi_admin .sbi_license_status{
201
  width: 100%;
202
  clear: left;
203
  }
204
+ #sbi_admin .sbi_cron_cache_opts .sbi_row{
205
+ padding: 3px 0;
206
+ }
207
+ #sbi_admin .sbi_cron_cache_opts .sbi_row label {
208
+ display: inline-block;
209
+ margin: 5px 2px 0 0;
210
+ }
211
  #sbi_admin .sbi_pro,
212
  #sbi_admin .sbi_pro label,
213
  #sbi_admin .sbi_pro input,
410
  -webkit-border-radius: 4px;
411
  border-radius: 4px;
412
  }
413
+ .sbi_review_notice .sbi-notice-text{
414
  float: left;
415
  clear: none;
416
  width: 100%;
439
  .sbi_review_notice .links a:first-child{
440
  /*padding-left: 0;*/
441
  }
442
+ .sbi_review_notice .sbi_notice_close,
443
+ .sbi_review_notice .sbi_bfcm_sale_notice_close,
444
+ .sbi_review_notice .sbi_new_user_sale_notice_close {
445
  position: absolute;
446
  top: 0;
447
  right: 0;
612
  #sbi_admin .sbi_connected_account {
613
  position: relative;
614
  box-sizing: border-box;
615
+ padding: 10px 35px 10px 10px;
616
  border-radius: 5px;
617
  background: #fff;
618
  margin-bottom: 5px;
620
  clear: both;
621
  border: 1px solid #ddd;
622
  }
623
+ #sbi_admin .sbi_ca_username {
624
+ line-height: 1.4;
625
+ margin-left: 15px;
626
+ float: left;
627
+ font-size: 18px;
628
+ }
629
  #sbi_admin .sbi_connected_account .sbi_ca_avatar{
630
  margin-right: 15px;
631
  }
632
  #sbi_admin .sbi_connected_account .sbi_ca_username {
633
  margin-left: 0;
634
+ margin-right: 15px;
635
  }
636
+ #sbi_admin .sbi_connected_account .sbi_ca_username strong{
 
 
637
  float: left;
 
638
  }
639
+ #sbi_admin .sbi_connected_account .sbi_ca_username span{
640
+ font-size: 10px;
641
+ font-weight: normal;
642
+ text-transform: uppercase;
643
+ padding: 0;
644
+ margin: 0;
645
+ display: block;
646
+ }
647
+
648
  #sbi_admin .sbi_ca_actions {
649
  display: inline-block;
650
  }
651
  #sbi_admin .sbi_ca_actions .fa{
652
  margin-right: 5px;
653
  }
 
 
 
 
 
654
  #sbi_admin .sbi_ca_actions a.button-primary,
655
  #sbi_admin .sbi_ca_actions a.button-secondary,
656
  #sbi_admin .sbi_ca_accesstoken a.sbi_ca_token_shortcode {
752
  right: 10px;
753
  top: 10px;
754
 
755
+ padding: 5px 10px;
756
  background: rgba(0,0,0,0.05);
757
  color: #666;
758
  border-radius: 50px;
764
  background: #333;
765
  color: #ddd;
766
  }
767
+ #sbi_admin .sbi_delete_account .sbi_remove_text{
768
+ margin-left: 5px;
769
  }
770
 
771
  .sbi_connected_accounts_wrap{
773
  }
774
  #sbi_admin .sbi_no_accounts{
775
  display: inline-block;
776
+ padding: 4px 15px;
777
  border-radius: 8px;
778
  background: rgba(255,255,255,0.8);
779
+ margin-bottom: 3px;
780
  }
781
  #sbi_admin #sbi_manual_submit:active{
782
  vertical-align: unset;
788
  padding-top: 5px;
789
  }
790
  #sbi_admin .sbi_user_feed_account_wrap:last-child{
791
+ padding-bottom: 6px;
792
  }
793
  #sbi_admin .sbi_user_feed_account_wrap{
794
  padding-bottom: 5px;
795
+ padding-left: 2px;
796
  }
797
  #sbi_admin .sbi_user_feed_account_wrap span{
798
  font-size: 13px;
799
  }
800
+ #sbi_admin .sbi_manual_account_id_toggle label{
801
+ display: block;
802
+ margin: 10px 0 0 0;
803
+ font-size: 13px;
804
+ }
805
+ #sbi_admin .sbi_business_profile_tag{
806
+ display: none;
807
+ padding: 8px 10px;
808
+ background: rgba(0,0,0,0.05);
809
+ border-radius: 0 5px 5px 0;
810
+ margin: 0 0 0 -2px;
811
+ font-size: 13px;
812
+ height: 15px;
813
+ line-height: 15px;
814
+ box-shadow: inset 0 0 1px rgba(0,0,0,.5);
815
+ }
816
+ #sbi_admin .sbi_ca_info{
817
+ overflow: hidden;
818
+ }
819
+ #sbi_admin .sbi_ca_show_token{
820
+ display: inline-block;
821
+ padding: 10px 5px 0px 5px;
822
+ margin: 0;
823
+ font-size: 12px;
824
+ vertical-align: top;
825
+ }
826
+ #sbi_admin .sbi_ca_shortcode{
827
+ display: none;
828
+ padding: 0;
829
+ width: 100%;
830
+ float: left;
831
+ clear: both;
832
+ margin: 10px 0 0 0;
833
+ }
834
+ #sbi_admin .sbi_ca_shortcode p{
835
+ padding-bottom: 10px;
836
+ font-size: 13px;
837
+ }
838
+ #sbi_admin .sbi_ca_shortcode code{
839
+ margin-top: 5px;
840
+ display: inline-block;
841
+ }
842
+ #sbi_admin .sbi_user_feed_ids_wrap .sbi_ca_avatar{
843
+ width: 20px;
844
+ height: 20px;
845
+ position: relative;
846
+ top: 5px;
847
+ margin-right: 8px;
848
+ border-radius: 4px;
849
+ }
850
+
851
+
852
+ @media all and (max-width: 1200px){
853
+ #sbi_admin .sbi_delete_account .sbi_remove_text{
854
+ display: none;
855
+ }
856
+ #sbi_admin .sbi_ca_token_label{
857
+ display: none;
858
+ }
859
+ #sbi_admin .sbi_ca_token{
860
+ border-left: 1px solid #d6d6d6;
861
+ border-radius: 4px;
862
+ }
863
+ }
864
+ @media all and (max-width: 800px){
865
+ #sbi_admin .sbi_col.sbi_one {
866
+ width: 25%;
867
+ margin-right: 5%;
868
+ }
869
+ #sbi_admin .sbi_col.sbi_two{
870
+ width: 70%;
871
+ }
872
+ }
873
  /*#sbi_admin .sbi_remove_from_user_feed{
874
  background: #71ad26;
875
  color: #fff;
972
  }
973
  #sbi_config_info .sbi_config_modal{
974
  position: absolute;
975
+ top: 160px;
976
  left: 50%;
977
+ width: 450px;
978
 
979
+ margin: 0 0 0 -230px;
980
  padding: 20px;
981
  background: #fff;
 
982
 
983
  -webkit-box-shadow: 0 1px 20px rgba(0,0,0,0.2);
984
  box-shadow: 0 1px 20px rgba(0,0,0,0.2);
987
  -webkit-border-radius: 3px;
988
  border-radius: 3px;
989
  }
990
+ @media all and (max-width: 480px){
991
+ #sbi_config_info .sbi_config_modal{
992
+ max-width: 100%;
993
+ margin: 0 0 0 -50%;
994
+ box-sizing: border-box;
995
+ }
996
+ }
997
+ #sbi_config_info.sb_get_token .sbi_config_modal {
998
+ text-align: center;
999
+ }
1000
  .sb_get_token .submit {
1001
  display: inline-block;
1002
  margin: 0 0 0 10px;
1044
  color: #333;
1045
  }
1046
 
1047
+ /* New modal info */
1048
+ .sbi_config_modal p{
1049
+ font-size: 14px;
1050
+ line-height: 1.6;
1051
+ }
1052
+ .sbi_config_modal .sbi_login_button_row{
1053
+ display: block;
1054
+ padding: 3px 0;
1055
+ width: 90%;
1056
+ margin: 0 auto;
1057
+ text-align: center;
1058
+ }
1059
+ #sbi_admin .sbi_login_button_row label{
1060
+ top: -2px;
1061
+ left: 3px;
1062
+ }
1063
+ #sbi_admin .sbi_login_button_row label b{
1064
+ font-size: 14px;
1065
+ }
1066
+ #sbi_admin .sbi_login_button_row .sbi_tooltip{
1067
+ width: 90%;
1068
+ padding: 10px 5%;
1069
+ background: #eee;
1070
+ }
1071
+ #sbi_admin .sbi_config_modal .sbi_admin_btn{
1072
+ display: inline-block;
1073
+ float: none;
1074
+ margin: 20px 0 5px 0;
1075
+ padding: 0 21px;
1076
+ background-image: none;
1077
+ }
1078
+
1079
  /* Pro 3.0 Styles */
1080
  .sbi_layout_cell {
1081
  padding: 0;
1284
  top: -10px;
1285
  bottom: auto;
1286
  margin-left: -101px;
1287
+ }
1288
+
1289
+ /* Graph API pages */
1290
+ /* Instagram Business Managed page */
1291
+ #sbi_admin .sbi-managed-pages{
1292
+ margin: 0;
1293
+ width: 96%;
1294
+ clear: both;
1295
+ float: left;
1296
+ padding: 10px 2%;
1297
+ }
1298
+ #sbi_admin .sbi-scrollable-accounts {
1299
+ max-height: 360px;
1300
+ overflow-y: auto;
1301
+ overflow-x: hidden;
1302
+ }
1303
+ #sbi_admin .sbi-managed-page-intro{
1304
+ padding: 0 0 20px 0;
1305
+ margin: 0;
1306
+ }
1307
+ #sbi_admin .sbi-managed-page-select-all{
1308
+ padding: 0 0 5px 0;
1309
+ margin: 0 0 0 1px;
1310
+ }
1311
+ #sbi_admin .sbi-managed-page-select-all label{
1312
+ font-size: 12px;
1313
+ top: -2px;
1314
+ left: 3px;
1315
+ }
1316
+ #sbi_admin .sbi-managed-page{
1317
+ width: 102%;
1318
+ border: 1px solid transparent;
1319
+ padding: 5px 1%;
1320
+ margin: 0 -1%;
1321
+ background: #fff;
1322
+ box-sizing: border-box;
1323
+ position: relative;
1324
+ }
1325
+ #sbi_admin .sbi-managed-page:hover{
1326
+ background: #eee;
1327
+ }
1328
+ #sbi_admin .sbi-managed-page .sbi-page-avatar{
1329
+ float: left;
1330
+ width: 40px;
1331
+ height: 40px;
1332
+ margin-right: 10px;
1333
+ border-radius: 3px;
1334
+ }
1335
+ #sbi_admin .sbi-managed-page label{
1336
+ padding: 0;
1337
+ margin: 0;
1338
+ height: 40px;
1339
+ line-height: 1.3;
1340
+ display: block;
1341
+ }
1342
+ .sbi-add-checkbox {
1343
+ display: inline-block;
1344
+ float: left;
1345
+ }
1346
+ .sbi-managed-page-details {
1347
+ margin-left: 30px;
1348
+ }
1349
+ .sbi-add-checkbox input {
1350
+ position: absolute;
1351
+ top: 50%;
1352
+ left: 1%;
1353
+ margin-top: -10px;
1354
+ }
1355
+
1356
+ .sbi_review_notice .sbi_offer_btn{
1357
+ padding: 4px 12px 6px 12px;
1358
+ background: green;
1359
+ color: #fff;
1360
+ border-radius: 4px;
1361
+ display: inline-block;
1362
+ text-decoration: none;
1363
+ margin-left: 9px;
1364
+ }
1365
+ .sbi_review_notice .sbi_offer_btn:hover,
1366
+ .sbi_review_notice .sbi_offer_btn:focus{
1367
+ background: #049404;
1368
+ color: #fff;
1369
+ }
1370
+ .sbi_review_notice .sbi_other_notice{
1371
+ font-size: 13px;
1372
+ font-style: italic;
1373
+ margin-top: 5px !important;
1374
+ }
1375
+
1376
+ /* Admin footer share icons */
1377
+ #sbi_admin #sbi_admin_share_links{
1378
+ opacity: 0;
1379
+ display: inline-block;
1380
+ padding: 5px;
1381
+ border: 1px solid #ccc;
1382
+ background: rgba(255,255,255,0.5);
1383
+ border-radius: 3px;
1384
+ transition: opacity 0.5s;
1385
+ }
1386
+ #sbi_admin #sbi_admin_share_links.sbi_show{
1387
+ transition: opacity 0.5s;
1388
+ opacity: 1;
1389
+ }
1390
+ #sbi_admin #twitter-widget-0 {
1391
+ width: 65px !important;
1392
  }
css/sb-instagram.css CHANGED
@@ -4,68 +4,68 @@
4
 
5
  /* Feed container */
6
  #sb_instagram {
7
- width: 100%;
8
- margin: 0 auto;
9
- padding: 0;
10
- -webkit-box-sizing: border-box;
11
- -moz-box-sizing: border-box;
12
- box-sizing: border-box;
13
  }
14
  #sb_instagram:after{
15
- content: "";
16
- display: table;
17
- clear: both;
18
  }
19
 
20
  /*********************/
21
  /*** STYLE OPTIONS ***/
22
  /*********************/
23
  #sb_instagram.sbi_fixed_height{
24
- overflow: hidden;
25
- overflow-y: auto;
26
- -webkit-box-sizing: border-box;
27
- -moz-box-sizing: border-box;
28
- box-sizing: border-box;
29
  }
30
  #sb_instagram #sbi_images{
31
- width: 100%;
32
- float: left;
33
- line-height: 0;
34
 
35
- -webkit-box-sizing: border-box;
36
- -moz-box-sizing: border-box;
37
- box-sizing: border-box;
38
  }
39
 
40
  /* Items */
41
  #sb_instagram #sbi_images .sbi_item{
42
- display: -moz-inline-stack;
43
- display: inline-block;
44
- vertical-align: top;
45
- zoom: 1;
46
- *display: inline;
47
-
48
- max-height: 1000px;
49
- padding: inherit !important;
50
- margin: 0 !important;
51
- text-decoration: none;
52
- opacity: 1;
53
- overflow: hidden;
54
-
55
- -webkit-box-sizing: border-box;
56
- -moz-box-sizing: border-box;
57
- box-sizing: border-box;
58
-
59
- -webkit-transition: all 0.5s ease;
60
- -moz-transition: all 0.5s ease;
61
- -o-transition: all 0.5s ease;
62
- -ms-transition: all 0.5s ease;
63
- transition: all 0.5s ease;
64
  }
65
  /* Transition items in */
66
  #sb_instagram #sbi_images .sbi_item.sbi_transition{
67
- opacity: 0;
68
- max-height: 0;
69
  }
70
 
71
  /* Cols */
@@ -94,71 +94,74 @@
94
 
95
  /* Photos */
96
  #sb_instagram .sbi_photo_wrap{
97
- position: relative;
98
  }
99
  #sb_instagram .sbi_photo{
100
- display: block;
101
- text-decoration: none;
102
  }
103
  #sb_instagram .sbi_photo img{
104
- width: 100%;
105
- height: auto;
 
 
 
106
  }
107
  #sb_instagram a,
108
  #sb_instagram a:hover,
109
  #sb_instagram a:focus,
110
  #sb_instagram a:active{
111
- outline: none;
112
  }
113
  #sb_instagram img{
114
- display: block;
115
- padding: 0 !important;
116
- margin: 0 !important;
117
- max-width: 100% !important;
118
- opacity: 1 !important;
119
  }
120
  #sb_instagram .sbi_link{
121
- display: none;
122
- position: absolute;
123
- bottom: 0;
124
- right: 0;
125
-
126
- width: 100%;
127
- padding: 10px 0;
128
- background: rgba(0,0,0,0.5);
129
- text-align: center;
130
- color: #fff;
131
- font-size: 12px;
132
- line-height: 1.1;
133
  }
134
  #sb_instagram .sbi_link a{
135
- padding: 0 6px;
136
- text-decoration: none;
137
- color: #fff;
138
- font-size: 12px;
139
- line-height: 1.1;
140
-
141
- display: -moz-inline-stack;
142
- display: inline-block;
143
- vertical-align: top;
144
- zoom: 1;
145
- *display: inline;
146
  }
147
  #sb_instagram .sbi_link .sbi_lightbox_link{
148
- padding-bottom: 5px;
149
  }
150
  #sb_instagram .sbi_link a:hover,
151
  #sb_instagram .sbi_link a:focus{
152
- text-decoration: underline;
153
  }
154
  #sb_instagram .sbi_photo_wrap:hover .sbi_link,
155
  #sb_instagram .sbi_photo_wrap:focus .sbi_link{
156
- display: block;
157
  }
158
 
159
  /* Videos */
160
  #sb_instagram svg:not(:root).svg-inline--fa {
161
- height: 1em;
162
  }
163
 
164
  #sb_instagram .sbi_type_video .sbi_playbtn,
@@ -166,519 +169,555 @@
166
  .sbi_type_carousel .fa-clone,
167
  #sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,
168
  #sb_instagram .sbi_type_video .svg-inline--fa.fa-play{
169
- display: block !important;
170
- position: absolute;
171
- z-index: 1;
172
 
173
- color: #fff;
174
- color: rgba(255,255,255,0.9);
175
- font-style: normal !important;
176
- text-shadow: 0 0 8px rgba(0,0,0,0.8);
177
  }
178
  #sb_instagram .sbi_type_video .sbi_playbtn,
179
  #sb_instagram .sbi_type_carousel .sbi_playbtn {
180
- z-index: 2;
181
- top: 50%;
182
- left: 50%;
183
- margin-top: -24px;
184
- margin-left: -19px;
185
- padding: 0;
186
- font-size: 48px;
187
  }
188
  #sb_instagram .sbi_type_carousel .fa-clone{
189
- right: 12px;
190
- top: 12px;
191
- font-size: 24px;
192
- text-shadow: 0 0 8px rgba(0,0,0,0.3);
193
  }
194
  .sbi_type_carousel svg.fa-clone,
195
  #sb_instagram .sbi_type_video .svg-inline--fa.fa-play,
196
  #sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play{
197
- -webkit-filter: drop-shadow( 0px 0px 2px rgba(0,0,0,.4) );
198
- filter: drop-shadow( 0px 0px 2px rgba(0,0,0,.4) );
199
  }
200
 
201
  /* Loader */
202
  #sb_instagram .sbi_loader{
203
- width: 20px;
204
- height: 20px;
205
 
206
- position: relative;
207
- top: 50%;
208
- left: 50%;
209
- margin: -10px 0 0 -10px;
210
- background-color: #000;
211
- background-color: rgba(0,0,0,0.5);
212
 
213
- border-radius: 100%;
214
- -webkit-animation: sbi-sk-scaleout 1.0s infinite ease-in-out;
215
- animation: sbi-sk-scaleout 1.0s infinite ease-in-out;
216
  }
217
  /* Loader in button */
218
  #sb_instagram #sbi_load .sbi_loader{
219
- position: absolute;
220
- margin-top: -11px;
221
- background-color: #fff;
222
- opacity: 1;
223
  }
224
  @-webkit-keyframes sbi-sk-scaleout {
225
- 0% { -webkit-transform: scale(0) }
226
- 100% {
227
- -webkit-transform: scale(1.0);
228
- opacity: 0;
229
- }
230
  }
231
  @keyframes sbi-sk-scaleout {
232
- 0% {
233
- -webkit-transform: scale(0);
234
- -ms-transform: scale(0);
235
- transform: scale(0);
236
- } 100% {
237
- -webkit-transform: scale(1.0);
238
- -ms-transform: scale(1.0);
239
- transform: scale(1.0);
240
- opacity: 0;
241
- }
242
  }
243
 
244
  #sb_instagram .fa-spin,
245
  #sbi_lightbox .fa-spin{
246
- -webkit-animation: fa-spin 2s infinite linear;
247
- animation: fa-spin 2s infinite linear
248
  }
249
 
250
  #sb_instagram .fa-pulse,
251
  #sbi_lightbox .fa-pulse{
252
- -webkit-animation: fa-spin 1s infinite steps(8);
253
- animation: fa-spin 1s infinite steps(8)
254
  }
255
 
256
  @-webkit-keyframes fa-spin {
257
- 0% {
258
- -webkit-transform: rotate(0deg);
259
- transform: rotate(0deg)
260
- }
261
- 100% {
262
- -webkit-transform: rotate(359deg);
263
- transform: rotate(359deg)
264
- }
265
  }
266
 
267
  @keyframes fa-spin {
268
- 0% {
269
- -webkit-transform: rotate(0deg);
270
- transform: rotate(0deg)
271
- }
272
- 100% {
273
- -webkit-transform: rotate(359deg);
274
- transform: rotate(359deg)
275
- }
276
  }
 
 
277
 
278
  /* HEADER */
279
  #sb_instagram .sb_instagram_header{
280
- float: left;
281
- clear: both;
282
- margin: 0 0 15px 0;
283
- padding: 0;
284
- line-height: 1.2;
285
- width: 100%;
286
  }
287
  #sb_instagram .sb_instagram_header a{
288
- float: left;
289
- display: block;
290
- /*width: 100%;*/
291
- min-width: 100%\9;
292
- text-decoration: none;
293
- transition: color 0.5s ease;
294
  }
295
  /** Medium Header */
296
  /* Only use medium & large headers on devices above 480px */
297
  @media all and (min-width: 480px){
298
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img {
299
- width: 80px;
300
- height: 80px;
301
- border-radius: 40px;
302
- }
303
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img img {
304
- width: 80px;
305
- height: 80px;
306
- border-radius: 40px;
307
- }
308
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3 {
309
- font-size: 20px;
310
- }
311
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,
312
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio{
313
- font-size: 14px;
314
- }
315
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3,
316
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,
317
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio{
318
- margin-left: 95px !important;
319
- line-height: 1.4
320
- }
321
- #sb_instagram .sbi_medium .sbi_header_text h3{
322
- margin-right: -85px !important;
323
- }
324
- #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{
325
- margin-top: 4px !important;
326
- }
327
- #sb_instagram .sbi_medium .sbi_header_text.sbi_no_info h3{
328
- padding-top: 20px !important;
329
- }
330
- /** Large Header */
331
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_img {
332
- width: 120px;
333
- height: 120px;
334
- border-radius: 60px;
335
- }
336
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_img img {
337
- width: 120px;
338
- height: 120px;
339
- border-radius: 60px;
340
- }
341
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3 {
342
- font-size: 28px;
343
- }
344
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,
345
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio{
346
- font-size: 16px;
347
- }
348
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3,
349
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,
350
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio{
351
- margin-left: 140px !important;
352
- line-height: 1.5;
353
- }
354
- #sb_instagram .sbi_large .sbi_header_text h3{
355
- margin-right: -120px !important;
356
- }
357
- #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{
358
- margin-top: 12px !important;
359
- }
360
- #sb_instagram .sbi_large .sbi_header_text.sbi_no_info h3{
361
- padding-top: 32px !important;
362
- }
363
  }
364
 
365
  /* Header profile pic */
366
  #sb_instagram .sbi_header_img{
367
- float: left;
368
- position: relative;
369
- width: 50px;
370
- margin: 0 0 0 -100% !important;
371
- overflow: hidden;
372
-
373
- -moz-border-radius: 40px;
374
- -webkit-border-radius: 40px;
375
- border-radius: 40px;
376
  }
377
  #sb_instagram .sbi_header_img img{
378
- float: left;
379
- margin: 0 !important;
380
- padding: 0 !important;
381
- border: none !important;
382
 
383
- -moz-border-radius: 40px;
384
- -webkit-border-radius: 40px;
385
- border-radius: 40px;
386
  }
387
  /* Profile pic hover */
388
  /* Profile pic hover */
389
  #sb_instagram .sbi_header_img_hover{
390
- opacity: 0;
391
- position: absolute;
392
- width: 100%;
393
- top: 0;
394
- bottom: 0;
395
- left: 0;
396
- text-align: center;
397
- color: #fff;
398
- background: rgba(0,0,0,0.75);
399
- }
400
- #sb_instagram .sbi_header_img_hover i{
401
- position: absolute;
402
- top: 50%;
403
- left: 50%;
404
- margin-top: -12px;
405
- margin-left: -12px;
406
- width: 24px;
407
- height: 24px;
408
- overflow: hidden;
409
- background: url('../img/small-logo.png') no-repeat 0 0;
 
 
 
 
410
  }
411
  #sb_instagram .sbi_header_img_hover{
412
- transition: opacity 0.4s ease-in-out;
 
413
  }
414
  #sb_instagram .sb_instagram_header .sbi_fade_in{
415
- opacity: 1;
416
- transition: opacity 0.2s ease-in-out;
417
  }
418
  #sb_instagram .sbi_header_img_hover{
419
- position: absolute;
420
- width: 100%;
421
- top: 0;
422
- bottom: 0;
423
- left: 0;
424
- text-align: center;
425
- color: #fff;
426
- background: rgba(0,0,0,0.75);
427
-
428
- -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
429
- filter: alpha(opacity=0);
430
- -moz-opacity: 0;
431
- -khtml-opacity: 0;
432
- opacity: 0;
433
- border-radius: 40px;
434
- transition: opacity 0.2s;
435
  }
436
  /* Fade the Instagram icon in when hovering on the header */
437
  #sb_instagram .sb_instagram_header a:hover .sbi_header_img_hover,
438
  #sb_instagram .sb_instagram_header a:focus .sbi_header_img_hover{
439
- opacity: 1;
440
  }
441
  /* Header text */
442
  #sb_instagram .sbi_header_text{
443
- float: left;
444
- width: 100%;
445
- padding-top: 5px;
446
  }
447
  #sb_instagram .sb_instagram_header a{
448
- text-decoration: none;
449
  }
450
  #sb_instagram .sbi_header_text .sbi_bio,
451
  #sb_instagram .sbi_header_text h3{
452
- float: left;
453
- clear: both;
454
- width: auto;
455
- margin: 0 0 0 60px !important;
456
- padding: 0 !important;
457
  }
458
  #sb_instagram .sb_instagram_header h3{
459
- font-size: 16px;
460
- line-height: 1.3;
461
  }
462
  #sb_instagram .sb_instagram_header p{
463
- font-size: 13px;
464
- line-height: 1.3;
465
  }
466
  #sb_instagram .sb_instagram_header h3.sbi_no_bio{
467
- padding-top: 9px !important;
468
  }
469
  #sb_instagram .sbi_header_text img.emoji{
470
- margin-right: 3px !important;
471
  }
472
 
473
 
474
  /* Buttons */
475
  #sb_instagram #sbi_load{
476
- float: left;
477
- clear: both;
478
- width: 100%;
479
- text-align: center;
480
  }
481
  #sb_instagram #sbi_load .fa-spinner{
482
- display: none;
483
- position: absolute;
484
- top: 50%;
485
- left: 50%;
486
- margin: -8px 0 0 -7px;
487
- font-size: 15px;
488
  }
489
  #sb_instagram #sbi_load{
490
- opacity: 1;
491
- transition: all 0.5s ease-in;
492
  }
493
  #sb_instagram .sbi_load_btn .sbi_btn_text, #sb_instagram .sbi_load_btn .sbi_loader{
494
- opacity: 1;
495
- transition: all 0.1s ease-in;
496
  }
497
  #sb_instagram .sbi_hidden{
498
- opacity: 0 !important;
499
  }
500
  #sb_instagram #sbi_load .sbi_load_btn,
501
  #sb_instagram .sbi_follow_btn a{
502
- display: -moz-inline-stack;
503
- display: inline-block;
504
- vertical-align: top;
505
- zoom: 1;
506
- *display: inline;
507
-
508
- padding: 7px 14px;
509
- margin: 5px auto 0 auto;
510
- background: #333;
511
- color: #eee;
512
- border: none;
513
- color: #fff;
514
- text-decoration: none;
515
- font-size: 13px;
516
- line-height: 1.5;
517
-
518
- -moz-border-radius: 4px;
519
- -webkit-border-radius: 4px;
520
- border-radius: 4px;
521
-
522
- -webkit-box-sizing: border-box;
523
- -moz-box-sizing: border-box;
524
- box-sizing: border-box;
525
  }
526
  #sb_instagram #sbi_load .sbi_load_btn {
527
- position: relative;
528
  }
529
  /* Follow button */
530
  #sb_instagram .sbi_follow_btn{
531
- display: -moz-inline-stack;
532
- display: inline-block;
533
- vertical-align: top;
534
- zoom: 1;
535
- *display: inline;
536
- text-align: center;
537
  }
538
  #sb_instagram .sbi_follow_btn.sbi_top{
539
- display: block;
540
- margin-bottom: 5px;
541
  }
542
  #sb_instagram .sbi_follow_btn a{
543
- background: #408bd1;
544
- color: #fff;
545
  }
546
  #sb_instagram .sbi_follow_btn a,
547
  #sb_instagram .sbi_follow_btn a,
548
  #sb_instagram #sbi_load .sbi_load_btn{
549
- transition: all 0.1s ease-in;
550
  }
551
  /* Hover state for default colors */
552
  #sb_instagram #sbi_load .sbi_load_btn:hover{
553
- outline: none;
554
- box-shadow: inset 0 0 20px 20px rgba(255,255,255,0.25);
555
  }
556
  #sb_instagram .sbi_follow_btn a:hover,
557
  #sb_instagram .sbi_follow_btn a:focus{
558
- outline: none;
559
- box-shadow: inset 0 0 10px 20px #359dff;
560
  }
561
  /* If a custom color is applied then just use opacity for the hover effect */
562
  #sb_instagram .sbi_follow_btn.sbi_custom a:hover,
563
  #sb_instagram .sbi_follow_btn.sbi_custom a:focus,
564
  #sb_instagram #sbi_load .sbi_load_btn.sbi_custom:hover{
565
- box-shadow: inset 0 0 20px 20px rgba(255,255,255,0.15);
566
  }
567
  /* Active state */
568
  #sb_instagram .sbi_follow_btn a:active,
569
  #sb_instagram #sbi_load .sbi_load_btn:active{
570
- box-shadow: inset 0 0 10px 20px rgba(0,0,0,0.3);
571
  }
572
 
573
  #sb_instagram .sbi_follow_btn .fa,
574
  #sb_instagram .sbi_follow_btn svg{
575
- margin-bottom: -1px;
576
- margin-right: 7px;
577
- font-size: 15px;
578
  }
579
  #sb_instagram .sbi_follow_btn svg{
580
- vertical-align: -.125em;
581
  }
582
  #sb_instagram #sbi_load .sbi_follow_btn{
583
- margin-left: 5px;
584
  }
585
 
586
  /* Error messages */
587
  #sb_instagram .sb_instagram_error{
588
- width: 100%;
589
- text-align: center;
590
- line-height: 1.4;
591
  }
592
 
593
  /* Mod only error msgs */
594
  #sbi_mod_error{
595
- display: none;
596
- border: 1px solid #ddd;
597
- background: #eee;
598
- color: #333;
599
- margin: 0;
600
- padding: 10px 15px;
601
- font-size: 13px;
602
- text-align: center;
603
-
604
- -moz-border-radius: 4px;
605
- -webkit-border-radius: 4px;
606
- border-radius: 4px;
 
607
  }
608
  #sbi_mod_error p{
609
- padding: 5px 0 !important;
610
- margin: 0 !important;
611
- line-height: 1.3 !important;
612
  }
613
  #sbi_mod_error ol,
614
  #sbi_mod_error ul{
615
- padding: 5px 0 5px 20px !important;
616
- margin: 0 !important;
617
  }
618
  #sbi_mod_error li{
619
- padding: 1px 0 !important;
620
- margin: 0 !important;
621
  }
622
  #sbi_mod_error span{
623
- font-size: 12px;
624
  }
625
 
626
  /* Medium */
627
  #sb_instagram.sbi_medium .sbi_playbtn,
628
  #sb_instagram.sbi_medium .sbi_photo_wrap .svg-inline--fa.fa-play{
629
- margin-top: -12px;
630
- margin-left: -9px;
631
- font-size: 23px;
632
  }
633
  #sb_instagram.sbi_medium .sbi_type_carousel .sbi_photo_wrap .fa-clone{
634
- right: 8px;
635
- top: 8px;
636
- font-size: 18px;
637
  }
638
  /* Small */
639
  #sb_instagram.sbi_small .sbi_playbtn,
640
  #sb_instagram.sbi_small .sbi_photo_wrap .svg-inline--fa.fa-play{
641
- margin-top: -9px;
642
- margin-left: -7px;
643
- font-size: 18px;
644
  }
645
  #sb_instagram.sbi_small .sbi_type_carousel .sbi_photo_wrap .fa-clone{
646
- right: 5px;
647
- top: 5px;
648
- font-size: 12px;
649
  }
650
 
651
  /* Media queries */
652
  @media all and (max-width: 640px){
653
- /* Make 3-6 cols into 2 col */
654
- #sb_instagram.sbi_col_3 #sbi_images .sbi_item,
655
- #sb_instagram.sbi_col_4 #sbi_images .sbi_item,
656
- #sb_instagram.sbi_col_5 #sbi_images .sbi_item,
657
- #sb_instagram.sbi_col_6 #sbi_images .sbi_item{
658
- width: 50%;
659
- }
660
- /* Make 7-10 cols into 4 col */
661
- #sb_instagram.sbi_col_7 #sbi_images .sbi_item,
662
- #sb_instagram.sbi_col_8 #sbi_images .sbi_item,
663
- #sb_instagram.sbi_col_9 #sbi_images .sbi_item,
664
- #sb_instagram.sbi_col_10 #sbi_images .sbi_item{
665
- width: 25%;
666
- }
667
- /* On mobile make the min-width 100% */
668
- #sb_instagram.sbi_width_resp{
669
- width: 100% !important;
670
- }
671
  }
672
  @media all and (max-width: 480px){
673
- /* Make all cols into 1 col */
674
- #sb_instagram.sbi_col_3 #sbi_images .sbi_item,
675
- #sb_instagram.sbi_col_4 #sbi_images .sbi_item,
676
- #sb_instagram.sbi_col_5 #sbi_images .sbi_item,
677
- #sb_instagram.sbi_col_6 #sbi_images .sbi_item,
678
- #sb_instagram.sbi_col_7 #sbi_images .sbi_item,
679
- #sb_instagram.sbi_col_8 #sbi_images .sbi_item,
680
- #sb_instagram.sbi_col_9 #sbi_images .sbi_item,
681
- #sb_instagram.sbi_col_10 #sbi_images .sbi_item{
682
- width: 100%;
683
- }
684
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  /* Feed container */
6
  #sb_instagram {
7
+ width: 100%;
8
+ margin: 0 auto;
9
+ padding: 0;
10
+ -webkit-box-sizing: border-box;
11
+ -moz-box-sizing: border-box;
12
+ box-sizing: border-box;
13
  }
14
  #sb_instagram:after{
15
+ content: "";
16
+ display: table;
17
+ clear: both;
18
  }
19
 
20
  /*********************/
21
  /*** STYLE OPTIONS ***/
22
  /*********************/
23
  #sb_instagram.sbi_fixed_height{
24
+ overflow: hidden;
25
+ overflow-y: auto;
26
+ -webkit-box-sizing: border-box;
27
+ -moz-box-sizing: border-box;
28
+ box-sizing: border-box;
29
  }
30
  #sb_instagram #sbi_images{
31
+ width: 100%;
32
+ float: left;
33
+ line-height: 0;
34
 
35
+ -webkit-box-sizing: border-box;
36
+ -moz-box-sizing: border-box;
37
+ box-sizing: border-box;
38
  }
39
 
40
  /* Items */
41
  #sb_instagram #sbi_images .sbi_item{
42
+ display: -moz-inline-stack;
43
+ display: inline-block;
44
+ vertical-align: top;
45
+ zoom: 1;
46
+ *display: inline;
47
+
48
+ max-height: 1000px;
49
+ padding: inherit !important;
50
+ margin: 0 !important;
51
+ text-decoration: none;
52
+ opacity: 1;
53
+ overflow: hidden;
54
+
55
+ -webkit-box-sizing: border-box;
56
+ -moz-box-sizing: border-box;
57
+ box-sizing: border-box;
58
+
59
+ -webkit-transition: all 0.5s ease;
60
+ -moz-transition: all 0.5s ease;
61
+ -o-transition: all 0.5s ease;
62
+ -ms-transition: all 0.5s ease;
63
+ transition: all 0.5s ease;
64
  }
65
  /* Transition items in */
66
  #sb_instagram #sbi_images .sbi_item.sbi_transition{
67
+ opacity: 0;
68
+ max-height: 0;
69
  }
70
 
71
  /* Cols */
94
 
95
  /* Photos */
96
  #sb_instagram .sbi_photo_wrap{
97
+ position: relative;
98
  }
99
  #sb_instagram .sbi_photo{
100
+ display: block;
101
+ text-decoration: none;
102
  }
103
  #sb_instagram .sbi_photo img{
104
+ width: 100%;
105
+ height: auto;
106
+ }
107
+ #sb_instagram .sbi_no_js img{
108
+ display: none;
109
  }
110
  #sb_instagram a,
111
  #sb_instagram a:hover,
112
  #sb_instagram a:focus,
113
  #sb_instagram a:active{
114
+ outline: none;
115
  }
116
  #sb_instagram img{
117
+ display: block;
118
+ padding: 0 !important;
119
+ margin: 0 !important;
120
+ max-width: 100% !important;
121
+ opacity: 1 !important;
122
  }
123
  #sb_instagram .sbi_link{
124
+ display: none;
125
+ position: absolute;
126
+ bottom: 0;
127
+ right: 0;
128
+
129
+ width: 100%;
130
+ padding: 10px 0;
131
+ background: rgba(0,0,0,0.5);
132
+ text-align: center;
133
+ color: #fff;
134
+ font-size: 12px;
135
+ line-height: 1.1;
136
  }
137
  #sb_instagram .sbi_link a{
138
+ padding: 0 6px;
139
+ text-decoration: none;
140
+ color: #fff;
141
+ font-size: 12px;
142
+ line-height: 1.1;
143
+
144
+ display: -moz-inline-stack;
145
+ display: inline-block;
146
+ vertical-align: top;
147
+ zoom: 1;
148
+ *display: inline;
149
  }
150
  #sb_instagram .sbi_link .sbi_lightbox_link{
151
+ padding-bottom: 5px;
152
  }
153
  #sb_instagram .sbi_link a:hover,
154
  #sb_instagram .sbi_link a:focus{
155
+ text-decoration: underline;
156
  }
157
  #sb_instagram .sbi_photo_wrap:hover .sbi_link,
158
  #sb_instagram .sbi_photo_wrap:focus .sbi_link{
159
+ display: block;
160
  }
161
 
162
  /* Videos */
163
  #sb_instagram svg:not(:root).svg-inline--fa {
164
+ height: 1em;
165
  }
166
 
167
  #sb_instagram .sbi_type_video .sbi_playbtn,
169
  .sbi_type_carousel .fa-clone,
170
  #sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,
171
  #sb_instagram .sbi_type_video .svg-inline--fa.fa-play{
172
+ display: block !important;
173
+ position: absolute;
174
+ z-index: 1;
175
 
176
+ color: #fff;
177
+ color: rgba(255,255,255,0.9);
178
+ font-style: normal !important;
179
+ text-shadow: 0 0 8px rgba(0,0,0,0.8);
180
  }
181
  #sb_instagram .sbi_type_video .sbi_playbtn,
182
  #sb_instagram .sbi_type_carousel .sbi_playbtn {
183
+ z-index: 2;
184
+ top: 50%;
185
+ left: 50%;
186
+ margin-top: -24px;
187
+ margin-left: -19px;
188
+ padding: 0;
189
+ font-size: 48px;
190
  }
191
  #sb_instagram .sbi_type_carousel .fa-clone{
192
+ right: 12px;
193
+ top: 12px;
194
+ font-size: 24px;
195
+ text-shadow: 0 0 8px rgba(0,0,0,0.3);
196
  }
197
  .sbi_type_carousel svg.fa-clone,
198
  #sb_instagram .sbi_type_video .svg-inline--fa.fa-play,
199
  #sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play{
200
+ -webkit-filter: drop-shadow( 0px 0px 2px rgba(0,0,0,.4) );
201
+ filter: drop-shadow( 0px 0px 2px rgba(0,0,0,.4) );
202
  }
203
 
204
  /* Loader */
205
  #sb_instagram .sbi_loader{
206
+ width: 20px;
207
+ height: 20px;
208
 
209
+ position: relative;
210
+ top: 50%;
211
+ left: 50%;
212
+ margin: -10px 0 0 -10px;
213
+ background-color: #000;
214
+ background-color: rgba(0,0,0,0.5);
215
 
216
+ border-radius: 100%;
217
+ -webkit-animation: sbi-sk-scaleout 1.0s infinite ease-in-out;
218
+ animation: sbi-sk-scaleout 1.0s infinite ease-in-out;
219
  }
220
  /* Loader in button */
221
  #sb_instagram #sbi_load .sbi_loader{
222
+ position: absolute;
223
+ margin-top: -11px;
224
+ background-color: #fff;
225
+ opacity: 1;
226
  }
227
  @-webkit-keyframes sbi-sk-scaleout {
228
+ 0% { -webkit-transform: scale(0) }
229
+ 100% {
230
+ -webkit-transform: scale(1.0);
231
+ opacity: 0;
232
+ }
233
  }
234
  @keyframes sbi-sk-scaleout {
235
+ 0% {
236
+ -webkit-transform: scale(0);
237
+ -ms-transform: scale(0);
238
+ transform: scale(0);
239
+ } 100% {
240
+ -webkit-transform: scale(1.0);
241
+ -ms-transform: scale(1.0);
242
+ transform: scale(1.0);
243
+ opacity: 0;
244
+ }
245
  }
246
 
247
  #sb_instagram .fa-spin,
248
  #sbi_lightbox .fa-spin{
249
+ -webkit-animation: fa-spin 2s infinite linear;
250
+ animation: fa-spin 2s infinite linear
251
  }
252
 
253
  #sb_instagram .fa-pulse,
254
  #sbi_lightbox .fa-pulse{
255
+ -webkit-animation: fa-spin 1s infinite steps(8);
256
+ animation: fa-spin 1s infinite steps(8)
257
  }
258
 
259
  @-webkit-keyframes fa-spin {
260
+ 0% {
261
+ -webkit-transform: rotate(0deg);
262
+ transform: rotate(0deg)
263
+ }
264
+ 100% {
265
+ -webkit-transform: rotate(359deg);
266
+ transform: rotate(359deg)
267
+ }
268
  }
269
 
270
  @keyframes fa-spin {
271
+ 0% {
272
+ -webkit-transform: rotate(0deg);
273
+ transform: rotate(0deg)
274
+ }
275
+ 100% {
276
+ -webkit-transform: rotate(359deg);
277
+ transform: rotate(359deg)
278
+ }
279
  }
280
+ /* Screen reader */
281
+ .sbi-screenreader{text-indent: -9999px !important;display: block !important;width: 0 !important;height: 0 !important;line-height: 0 !important;}
282
 
283
  /* HEADER */
284
  #sb_instagram .sb_instagram_header{
285
+ float: left;
286
+ clear: both;
287
+ margin: 0 0 15px 0;
288
+ padding: 0;
289
+ line-height: 1.2;
290
+ width: 100%;
291
  }
292
  #sb_instagram .sb_instagram_header a{
293
+ float: left;
294
+ display: block;
295
+ /*width: 100%;*/
296
+ min-width: 100%\9;
297
+ text-decoration: none;
298
+ transition: color 0.5s ease;
299
  }
300
  /** Medium Header */
301
  /* Only use medium & large headers on devices above 480px */
302
  @media all and (min-width: 480px){
303
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img {
304
+ width: 80px;
305
+ height: 80px;
306
+ border-radius: 40px;
307
+ }
308
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img img {
309
+ width: 80px;
310
+ height: 80px;
311
+ border-radius: 40px;
312
+ }
313
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3 {
314
+ font-size: 20px;
315
+ }
316
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,
317
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio{
318
+ font-size: 14px;
319
+ }
320
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3,
321
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,
322
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio{
323
+ margin-left: 95px !important;
324
+ line-height: 1.4
325
+ }
326
+ #sb_instagram .sbi_medium .sbi_header_text h3{
327
+ margin-right: -85px !important;
328
+ }
329
+ #sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{
330
+ margin-top: 4px !important;
331
+ }
332
+ #sb_instagram .sbi_medium .sbi_header_text.sbi_no_info h3{
333
+ padding-top: 20px !important;
334
+ }
335
+ /** Large Header */
336
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_img {
337
+ width: 120px;
338
+ height: 120px;
339
+ border-radius: 60px;
340
+ }
341
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_img img {
342
+ width: 120px;
343
+ height: 120px;
344
+ border-radius: 60px;
345
+ }
346
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3 {
347
+ font-size: 28px;
348
+ }
349
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,
350
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio{
351
+ font-size: 16px;
352
+ }
353
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3,
354
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,
355
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio{
356
+ margin-left: 140px !important;
357
+ line-height: 1.5;
358
+ }
359
+ #sb_instagram .sbi_large .sbi_header_text h3{
360
+ margin-right: -120px !important;
361
+ }
362
+ #sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{
363
+ margin-top: 12px !important;
364
+ }
365
+ #sb_instagram .sbi_large .sbi_header_text.sbi_no_info h3{
366
+ padding-top: 32px !important;
367
+ }
368
  }
369
 
370
  /* Header profile pic */
371
  #sb_instagram .sbi_header_img{
372
+ float: left;
373
+ position: relative;
374
+ width: 50px;
375
+ margin: 0 0 0 -100% !important;
376
+ overflow: hidden;
377
+
378
+ -moz-border-radius: 40px;
379
+ -webkit-border-radius: 40px;
380
+ border-radius: 40px;
381
  }
382
  #sb_instagram .sbi_header_img img{
383
+ float: left;
384
+ margin: 0 !important;
385
+ padding: 0 !important;
386
+ border: none !important;
387
 
388
+ -moz-border-radius: 40px;
389
+ -webkit-border-radius: 40px;
390
+ border-radius: 40px;
391
  }
392
  /* Profile pic hover */
393
  /* Profile pic hover */
394
  #sb_instagram .sbi_header_img_hover{
395
+ opacity: 0;
396
+ position: absolute;
397
+ width: 100%;
398
+ top: 0;
399
+ bottom: 0;
400
+ left: 0;
401
+ text-align: center;
402
+ color: #fff;
403
+ background: rgba(0,0,0,0.75);
404
+ }
405
+
406
+ #sb_instagram .sbi_header_img_hover .sbi_new_logo{
407
+ position: absolute;
408
+ top: 50%;
409
+ left: 50%;
410
+ margin-top: -12px;
411
+ margin-left: -12px;
412
+ width: 24px;
413
+ height: 24px;
414
+ font-size: 24px;
415
+ }
416
+ #sb_instagram .sbi_header_img_hover i {
417
+ overflow: hidden;
418
+ background: url('../img/small-logo.png') no-repeat 0 0;
419
  }
420
  #sb_instagram .sbi_header_img_hover{
421
+ z-index: 2;
422
+ transition: opacity 0.4s ease-in-out;
423
  }
424
  #sb_instagram .sb_instagram_header .sbi_fade_in{
425
+ opacity: 1;
426
+ transition: opacity 0.2s ease-in-out;
427
  }
428
  #sb_instagram .sbi_header_img_hover{
429
+ position: absolute;
430
+ width: 100%;
431
+ top: 0;
432
+ bottom: 0;
433
+ left: 0;
434
+ text-align: center;
435
+ color: #fff;
436
+ background: rgba(0,0,0,0.75);
437
+
438
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
439
+ filter: alpha(opacity=0);
440
+ -moz-opacity: 0;
441
+ -khtml-opacity: 0;
442
+ opacity: 0;
443
+ border-radius: 40px;
444
+ transition: opacity 0.2s;
445
  }
446
  /* Fade the Instagram icon in when hovering on the header */
447
  #sb_instagram .sb_instagram_header a:hover .sbi_header_img_hover,
448
  #sb_instagram .sb_instagram_header a:focus .sbi_header_img_hover{
449
+ opacity: 1;
450
  }
451
  /* Header text */
452
  #sb_instagram .sbi_header_text{
453
+ float: left;
454
+ width: 100%;
455
+ padding-top: 5px;
456
  }
457
  #sb_instagram .sb_instagram_header a{
458
+ text-decoration: none;
459
  }
460
  #sb_instagram .sbi_header_text .sbi_bio,
461
  #sb_instagram .sbi_header_text h3{
462
+ float: left;
463
+ clear: both;
464
+ width: auto;
465
+ margin: 0 0 0 60px !important;
466
+ padding: 0 !important;
467
  }
468
  #sb_instagram .sb_instagram_header h3{
469
+ font-size: 16px;
470
+ line-height: 1.3;
471
  }
472
  #sb_instagram .sb_instagram_header p{
473
+ font-size: 13px;
474
+ line-height: 1.3;
475
  }
476
  #sb_instagram .sb_instagram_header h3.sbi_no_bio{
477
+ padding-top: 9px !important;
478
  }
479
  #sb_instagram .sbi_header_text img.emoji{
480
+ margin-right: 3px !important;
481
  }
482
 
483
 
484
  /* Buttons */
485
  #sb_instagram #sbi_load{
486
+ float: left;
487
+ clear: both;
488
+ width: 100%;
489
+ text-align: center;
490
  }
491
  #sb_instagram #sbi_load .fa-spinner{
492
+ display: none;
493
+ position: absolute;
494
+ top: 50%;
495
+ left: 50%;
496
+ margin: -8px 0 0 -7px;
497
+ font-size: 15px;
498
  }
499
  #sb_instagram #sbi_load{
500
+ opacity: 1;
501
+ transition: all 0.5s ease-in;
502
  }
503
  #sb_instagram .sbi_load_btn .sbi_btn_text, #sb_instagram .sbi_load_btn .sbi_loader{
504
+ opacity: 1;
505
+ transition: all 0.1s ease-in;
506
  }
507
  #sb_instagram .sbi_hidden{
508
+ opacity: 0 !important;
509
  }
510
  #sb_instagram #sbi_load .sbi_load_btn,
511
  #sb_instagram .sbi_follow_btn a{
512
+ display: -moz-inline-stack;
513
+ display: inline-block;
514
+ vertical-align: top;
515
+ zoom: 1;
516
+ *display: inline;
517
+
518
+ padding: 7px 14px;
519
+ margin: 5px auto 0 auto;
520
+ background: #333;
521
+ color: #eee;
522
+ border: none;
523
+ color: #fff;
524
+ text-decoration: none;
525
+ font-size: 13px;
526
+ line-height: 1.5;
527
+
528
+ -moz-border-radius: 4px;
529
+ -webkit-border-radius: 4px;
530
+ border-radius: 4px;
531
+
532
+ -webkit-box-sizing: border-box;
533
+ -moz-box-sizing: border-box;
534
+ box-sizing: border-box;
535
  }
536
  #sb_instagram #sbi_load .sbi_load_btn {
537
+ position: relative;
538
  }
539
  /* Follow button */
540
  #sb_instagram .sbi_follow_btn{
541
+ display: -moz-inline-stack;
542
+ display: inline-block;
543
+ vertical-align: top;
544
+ zoom: 1;
545
+ *display: inline;
546
+ text-align: center;
547
  }
548
  #sb_instagram .sbi_follow_btn.sbi_top{
549
+ display: block;
550
+ margin-bottom: 5px;
551
  }
552
  #sb_instagram .sbi_follow_btn a{
553
+ background: #408bd1;
554
+ color: #fff;
555
  }
556
  #sb_instagram .sbi_follow_btn a,
557
  #sb_instagram .sbi_follow_btn a,
558
  #sb_instagram #sbi_load .sbi_load_btn{
559
+ transition: all 0.1s ease-in;
560
  }
561
  /* Hover state for default colors */
562
  #sb_instagram #sbi_load .sbi_load_btn:hover{
563
+ outline: none;
564
+ box-shadow: inset 0 0 20px 20px rgba(255,255,255,0.25);
565
  }
566
  #sb_instagram .sbi_follow_btn a:hover,
567
  #sb_instagram .sbi_follow_btn a:focus{
568
+ outline: none;
569
+ box-shadow: inset 0 0 10px 20px #359dff;
570
  }
571
  /* If a custom color is applied then just use opacity for the hover effect */
572
  #sb_instagram .sbi_follow_btn.sbi_custom a:hover,
573
  #sb_instagram .sbi_follow_btn.sbi_custom a:focus,
574
  #sb_instagram #sbi_load .sbi_load_btn.sbi_custom:hover{
575
+ box-shadow: inset 0 0 20px 20px rgba(255,255,255,0.15);
576
  }
577
  /* Active state */
578
  #sb_instagram .sbi_follow_btn a:active,
579
  #sb_instagram #sbi_load .sbi_load_btn:active{
580
+ box-shadow: inset 0 0 10px 20px rgba(0,0,0,0.3);
581
  }
582
 
583
  #sb_instagram .sbi_follow_btn .fa,
584
  #sb_instagram .sbi_follow_btn svg{
585
+ margin-bottom: -1px;
586
+ margin-right: 7px;
587
+ font-size: 15px;
588
  }
589
  #sb_instagram .sbi_follow_btn svg{
590
+ vertical-align: -.125em;
591
  }
592
  #sb_instagram #sbi_load .sbi_follow_btn{
593
+ margin-left: 5px;
594
  }
595
 
596
  /* Error messages */
597
  #sb_instagram .sb_instagram_error{
598
+ width: 100%;
599
+ text-align: center;
600
+ line-height: 1.4;
601
  }
602
 
603
  /* Mod only error msgs */
604
  #sbi_mod_error{
605
+ display: none;
606
+ border: 1px solid #ddd;
607
+ background: #eee;
608
+ color: #333;
609
+ margin: 10px 0 0;
610
+ padding: 10px 15px;
611
+ font-size: 13px;
612
+ text-align: center;
613
+ clear: both;
614
+
615
+ -moz-border-radius: 4px;
616
+ -webkit-border-radius: 4px;
617
+ border-radius: 4px;
618
  }
619
  #sbi_mod_error p{
620
+ padding: 5px 0 !important;
621
+ margin: 0 !important;
622
+ line-height: 1.3 !important;
623
  }
624
  #sbi_mod_error ol,
625
  #sbi_mod_error ul{
626
+ padding: 5px 0 5px 20px !important;
627
+ margin: 0 !important;
628
  }
629
  #sbi_mod_error li{
630
+ padding: 1px 0 !important;
631
+ margin: 0 !important;
632
  }
633
  #sbi_mod_error span{
634
+ font-size: 12px;
635
  }
636
 
637
  /* Medium */
638
  #sb_instagram.sbi_medium .sbi_playbtn,
639
  #sb_instagram.sbi_medium .sbi_photo_wrap .svg-inline--fa.fa-play{
640
+ margin-top: -12px;
641
+ margin-left: -9px;
642
+ font-size: 23px;
643
  }
644
  #sb_instagram.sbi_medium .sbi_type_carousel .sbi_photo_wrap .fa-clone{
645
+ right: 8px;
646
+ top: 8px;
647
+ font-size: 18px;
648
  }
649
  /* Small */
650
  #sb_instagram.sbi_small .sbi_playbtn,
651
  #sb_instagram.sbi_small .sbi_photo_wrap .svg-inline--fa.fa-play{
652
+ margin-top: -9px;
653
+ margin-left: -7px;
654
+ font-size: 18px;
655
  }
656
  #sb_instagram.sbi_small .sbi_type_carousel .sbi_photo_wrap .fa-clone{
657
+ right: 5px;
658
+ top: 5px;
659
+ font-size: 12px;
660
  }
661
 
662
  /* Media queries */
663
  @media all and (max-width: 640px){
664
+ /* Make 3-6 cols into 2 col */
665
+ #sb_instagram.sbi_col_3 #sbi_images .sbi_item,
666
+ #sb_instagram.sbi_col_4 #sbi_images .sbi_item,
667
+ #sb_instagram.sbi_col_5 #sbi_images .sbi_item,
668
+ #sb_instagram.sbi_col_6 #sbi_images .sbi_item{
669
+ width: 50%;
670
+ }
671
+ /* Make 7-10 cols into 4 col */
672
+ #sb_instagram.sbi_col_7 #sbi_images .sbi_item,
673
+ #sb_instagram.sbi_col_8 #sbi_images .sbi_item,
674
+ #sb_instagram.sbi_col_9 #sbi_images .sbi_item,
675
+ #sb_instagram.sbi_col_10 #sbi_images .sbi_item{
676
+ width: 25%;
677
+ }
678
+ /* On mobile make the min-width 100% */
679
+ #sb_instagram.sbi_width_resp{
680
+ width: 100% !important;
681
+ }
682
  }
683
  @media all and (max-width: 480px){
684
+ /* Make all cols into 1 col */
685
+ #sb_instagram.sbi_col_3 #sbi_images .sbi_item,
686
+ #sb_instagram.sbi_col_4 #sbi_images .sbi_item,
687
+ #sb_instagram.sbi_col_5 #sbi_images .sbi_item,
688
+ #sb_instagram.sbi_col_6 #sbi_images .sbi_item,
689
+ #sb_instagram.sbi_col_7 #sbi_images .sbi_item,
690
+ #sb_instagram.sbi_col_8 #sbi_images .sbi_item,
691
+ #sb_instagram.sbi_col_9 #sbi_images .sbi_item,
692
+ #sb_instagram.sbi_col_10 #sbi_images .sbi_item{
693
+ width: 100%;
694
+ }
695
+ }
696
+
697
+ /* NO JS */
698
+ #sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo_wrap{
699
+ box-sizing: border-box;
700
+ position: relative;
701
+ overflow: hidden;
702
+ }
703
+ #sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo_wrap:before {
704
+ content: "";
705
+ display: block;
706
+ padding-top: 100%;
707
+ z-index: -300;
708
+ }
709
+ #sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo {
710
+ position: absolute;
711
+ top: 0;
712
+ left: 0;
713
+ bottom: 0;
714
+ right: 0;
715
+ }
716
+ #sb_instagram.sbi_no_js #sbi_images .sbi_item.sbi_transition {
717
+ opacity: 1;
718
+ max-height: 640px;
719
+ }
720
+ #sb_instagram.sbi_no_js .sbi_photo img,
721
+ #sb_instagram.sbi_no_js .sbi_load_btn{
722
+ display: none;
723
+ }
css/sb-instagram.min.css CHANGED
@@ -1 +1 @@
1
- #sb_instagram,#sb_instagram.sbi_fixed_height{-webkit-box-sizing:border-box;-moz-box-sizing:border-box}#sb_instagram{width:100%;margin:0 auto;padding:0;box-sizing:border-box}#sb_instagram:after{content:"";display:table;clear:both}#sb_instagram.sbi_fixed_height{overflow:hidden;overflow-y:auto;box-sizing:border-box}#sb_instagram #sbi_images{width:100%;float:left;line-height:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#sb_instagram #sbi_images .sbi_item{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;max-height:1000px;padding:inherit!important;margin:0!important;text-decoration:none;opacity:1;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;-ms-transition:all .5s ease;transition:all .5s ease}#sb_instagram #sbi_images .sbi_item.sbi_transition{opacity:0;max-height:0}#sb_instagram.sbi_col_1 #sbi_images .sbi_item{width:100%}#sb_instagram.sbi_col_2 #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_3 #sbi_images .sbi_item{width:33.33%}#sb_instagram.sbi_col_4 #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_col_5 #sbi_images .sbi_item{width:20%}#sb_instagram.sbi_col_6 #sbi_images .sbi_item{width:16.66%}#sb_instagram.sbi_col_7 #sbi_images .sbi_item{width:14.28%}#sb_instagram.sbi_col_8 #sbi_images .sbi_item{width:12.5%}#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:11.11%}#sb_instagram.sbi_col_10 #sbi_images .sbi_item{width:10%}#sb_instagram.sbi_col_1.sbi_disable_mobile #sbi_images .sbi_item{width:100%}#sb_instagram.sbi_col_2.sbi_disable_mobile #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_3.sbi_disable_mobile #sbi_images .sbi_item{width:33.33%}#sb_instagram.sbi_col_4.sbi_disable_mobile #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_col_5.sbi_disable_mobile #sbi_images .sbi_item{width:20%}#sb_instagram.sbi_col_6.sbi_disable_mobile #sbi_images .sbi_item{width:16.66%}#sb_instagram.sbi_col_7.sbi_disable_mobile #sbi_images .sbi_item{width:14.28%}#sb_instagram.sbi_col_8.sbi_disable_mobile #sbi_images .sbi_item{width:12.5%}#sb_instagram.sbi_col_9.sbi_disable_mobile #sbi_images .sbi_item{width:11.11%}#sb_instagram.sbi_col_10.sbi_disable_mobile #sbi_images .sbi_item{width:10%}#sb_instagram .sbi_photo_wrap{position:relative}#sb_instagram .sbi_photo{display:block;text-decoration:none}#sb_instagram .sbi_photo img{width:100%;height:auto}#sb_instagram a,#sb_instagram a:active,#sb_instagram a:focus,#sb_instagram a:hover{outline:0}#sb_instagram img{display:block;padding:0!important;margin:0!important;max-width:100%!important;opacity:1!important}#sb_instagram .sbi_link{display:none;position:absolute;bottom:0;right:0;width:100%;padding:10px 0;background:rgba(0,0,0,.5);text-align:center;color:#fff;font-size:12px;line-height:1.1}#sb_instagram .sbi_link a{padding:0 6px;text-decoration:none;color:#fff;font-size:12px;line-height:1.1;display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1}#sb_instagram .sbi_link .sbi_lightbox_link{padding-bottom:5px}#sb_instagram .sbi_link a:focus,#sb_instagram .sbi_link a:hover{text-decoration:underline}#sb_instagram .sbi_photo_wrap:focus .sbi_link,#sb_instagram .sbi_photo_wrap:hover .sbi_link{display:block}#sb_instagram svg:not(:root).svg-inline--fa{height:1em}#sb_instagram .sbi_type_carousel .sbi_playbtn,#sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,#sb_instagram .sbi_type_video .sbi_playbtn,#sb_instagram .sbi_type_video .svg-inline--fa.fa-play,.sbi_type_carousel .fa-clone{display:block!important;position:absolute;z-index:1;color:#fff;color:rgba(255,255,255,.9);font-style:normal!important;text-shadow:0 0 8px rgba(0,0,0,.8)}#sb_instagram .sbi_type_carousel .sbi_playbtn,#sb_instagram .sbi_type_video .sbi_playbtn{z-index:2;top:50%;left:50%;margin-top:-24px;margin-left:-19px;padding:0;font-size:48px}#sb_instagram .sbi_type_carousel .fa-clone{right:12px;top:12px;font-size:24px;text-shadow:0 0 8px rgba(0,0,0,.3)}#sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,#sb_instagram .sbi_type_video .svg-inline--fa.fa-play,.sbi_type_carousel svg.fa-clone{-webkit-filter:drop-shadow( 0 0 2px rgba(0,0,0,.4) );filter:drop-shadow( 0 0 2px rgba(0, 0, 0, .4) )}#sb_instagram .sbi_loader{width:20px;height:20px;position:relative;top:50%;left:50%;margin:-10px 0 0 -10px;background-color:#000;background-color:rgba(0,0,0,.5);border-radius:100%;-webkit-animation:sbi-sk-scaleout 1s infinite ease-in-out;animation:sbi-sk-scaleout 1s infinite ease-in-out}#sb_instagram #sbi_load .sbi_loader{position:absolute;margin-top:-11px;background-color:#fff;opacity:1}@-webkit-keyframes sbi-sk-scaleout{0%{-webkit-transform:scale(0)}100%{-webkit-transform:scale(1);opacity:0}}@keyframes sbi-sk-scaleout{0%{-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);opacity:0}}#sb_instagram .fa-spin,#sbi_lightbox .fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}#sb_instagram .fa-pulse,#sbi_lightbox .fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}#sb_instagram .sb_instagram_header{float:left;clear:both;margin:0 0 15px;padding:0;line-height:1.2;width:100%}#sb_instagram .sb_instagram_header a{float:left;display:block;min-width:100%\9;transition:color .5s ease;text-decoration:none}@media all and (min-width:480px){#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img img{width:80px;height:80px;border-radius:40px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3{font-size:20px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{font-size:14px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3{margin-left:95px!important;line-height:1.4}#sb_instagram .sbi_medium .sbi_header_text h3{margin-right:-85px!important}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{margin-top:4px!important}#sb_instagram .sbi_medium .sbi_header_text.sbi_no_info h3{padding-top:20px!important}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_img,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_img img{width:120px;height:120px;border-radius:60px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3{font-size:28px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{font-size:16px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3{margin-left:140px!important;line-height:1.5}#sb_instagram .sbi_large .sbi_header_text h3{margin-right:-120px!important}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{margin-top:12px!important}#sb_instagram .sbi_large .sbi_header_text.sbi_no_info h3{padding-top:32px!important}}#sb_instagram .sbi_header_img{float:left;position:relative;width:50px;margin:0 0 0 -100%!important;overflow:hidden;-moz-border-radius:40px;-webkit-border-radius:40px;border-radius:40px}#sb_instagram .sbi_header_img img{float:left;margin:0!important;padding:0!important;border:none!important;-moz-border-radius:40px;-webkit-border-radius:40px;border-radius:40px}#sb_instagram .sbi_header_img_hover i{position:absolute;top:50%;left:50%;margin-top:-12px;margin-left:-12px;width:24px;height:24px;overflow:hidden;background:url(../img/small-logo.png) no-repeat}#sb_instagram .sb_instagram_header .sbi_fade_in{opacity:1;transition:opacity .2s ease-in-out}#sb_instagram .sbi_header_img_hover{position:absolute;width:100%;top:0;bottom:0;left:0;text-align:center;color:#fff;background:rgba(0,0,0,.75);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity:0;opacity:0;border-radius:40px;transition:opacity .2s}#sb_instagram .sb_instagram_header a:focus .sbi_header_img_hover,#sb_instagram .sb_instagram_header a:hover .sbi_header_img_hover{opacity:1}#sb_instagram .sbi_header_text{float:left;width:100%;padding-top:5px}#sb_instagram .sbi_header_text .sbi_bio,#sb_instagram .sbi_header_text h3{float:left;clear:both;width:auto;margin:0 0 0 60px!important;padding:0!important}#sb_instagram #sbi_load,#sb_instagram .sb_instagram_error{width:100%;text-align:center;line-height:1.5}#sb_instagram .sb_instagram_header h3{font-size:16px;line-height:1.3}#sb_instagram .sb_instagram_header p{font-size:13px;line-height:1.3}#sb_instagram .sb_instagram_header h3.sbi_no_bio{padding-top:9px!important}#sb_instagram .sbi_header_text img.emoji{margin-right:3px!important}#sb_instagram #sbi_load{float:left;clear:both;opacity:1;transition:all .5s ease-in}#sb_instagram #sbi_load .fa-spinner{display:none;position:absolute;top:50%;left:50%;margin:-8px 0 0 -7px;font-size:15px}#sb_instagram .sbi_load_btn .sbi_btn_text,#sb_instagram .sbi_load_btn .sbi_loader{opacity:1;transition:all .1s ease-in}#sb_instagram .sbi_hidden{opacity:0!important}#sb_instagram #sbi_load .sbi_load_btn,#sb_instagram .sbi_follow_btn a{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;padding:7px 14px;margin:5px auto 0;background:#333;border:none;color:#fff;text-decoration:none;font-size:13px;line-height:1.5;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;transition:all .1s ease-in}#sb_instagram #sbi_load .sbi_load_btn{position:relative}#sb_instagram .sbi_follow_btn{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;text-align:center}#sb_instagram .sbi_follow_btn.sbi_top{display:block;margin-bottom:5px}#sb_instagram .sbi_follow_btn a{background:#408bd1;color:#fff}#sb_instagram #sbi_load .sbi_load_btn:hover{outline:0;box-shadow:inset 0 0 20px 20px rgba(255,255,255,.25)}#sb_instagram .sbi_follow_btn a:focus,#sb_instagram .sbi_follow_btn a:hover{outline:0;box-shadow:inset 0 0 10px 20px #359dff}#sb_instagram #sbi_load .sbi_load_btn.sbi_custom:hover,#sb_instagram .sbi_follow_btn.sbi_custom a:focus,#sb_instagram .sbi_follow_btn.sbi_custom a:hover{box-shadow:inset 0 0 20px 20px rgba(255,255,255,.15)}#sb_instagram #sbi_load .sbi_load_btn:active,#sb_instagram .sbi_follow_btn a:active{box-shadow:inset 0 0 10px 20px rgba(0,0,0,.3)}#sb_instagram .sbi_follow_btn .fa,#sb_instagram .sbi_follow_btn svg{margin-bottom:-1px;margin-right:7px;font-size:15px}#sb_instagram .sbi_follow_btn svg{vertical-align:-.125em}#sb_instagram #sbi_load .sbi_follow_btn{margin-left:5px}#sbi_mod_error{display:none;border:1px solid #ddd;background:#eee;color:#333;margin:0;padding:10px 15px;font-size:13px;text-align:center;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px}#sbi_mod_error p{padding:5px 0!important;margin:0!important;line-height:1.3!important}#sbi_mod_error ol,#sbi_mod_error ul{padding:5px 0 5px 20px!important;margin:0!important}#sbi_mod_error li{padding:1px 0!important;margin:0!important}#sbi_mod_error span{font-size:12px}#sb_instagram.sbi_medium .sbi_photo_wrap .svg-inline--fa.fa-play,#sb_instagram.sbi_medium .sbi_playbtn{margin-top:-12px;margin-left:-9px;font-size:23px}#sb_instagram.sbi_medium .sbi_type_carousel .sbi_photo_wrap .fa-clone{right:8px;top:8px;font-size:18px}#sb_instagram.sbi_small .sbi_photo_wrap .svg-inline--fa.fa-play,#sb_instagram.sbi_small .sbi_playbtn{margin-top:-9px;margin-left:-7px;font-size:18px}#sb_instagram.sbi_small .sbi_type_carousel .sbi_photo_wrap .fa-clone{right:5px;top:5px;font-size:12px}@media all and (max-width:640px){#sb_instagram.sbi_col_3 #sbi_images .sbi_item,#sb_instagram.sbi_col_4 #sbi_images .sbi_item,#sb_instagram.sbi_col_5 #sbi_images .sbi_item,#sb_instagram.sbi_col_6 #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_10 #sbi_images .sbi_item,#sb_instagram.sbi_col_7 #sbi_images .sbi_item,#sb_instagram.sbi_col_8 #sbi_images .sbi_item,#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_width_resp{width:100%!important}}@media all and (max-width:480px){#sb_instagram.sbi_col_10 #sbi_images .sbi_item,#sb_instagram.sbi_col_3 #sbi_images .sbi_item,#sb_instagram.sbi_col_4 #sbi_images .sbi_item,#sb_instagram.sbi_col_5 #sbi_images .sbi_item,#sb_instagram.sbi_col_6 #sbi_images .sbi_item,#sb_instagram.sbi_col_7 #sbi_images .sbi_item,#sb_instagram.sbi_col_8 #sbi_images .sbi_item,#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:100%}}
1
+ #sb_instagram{width:100%;margin:0 auto;padding:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#sb_instagram:after{content:"";display:table;clear:both}#sb_instagram.sbi_fixed_height{overflow:hidden;overflow-y:auto;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#sb_instagram #sbi_images{width:100%;float:left;line-height:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#sb_instagram #sbi_images .sbi_item{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;max-height:1000px;padding:inherit!important;margin:0!important;text-decoration:none;opacity:1;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;-ms-transition:all .5s ease;transition:all .5s ease}#sb_instagram #sbi_images .sbi_item.sbi_transition{opacity:0;max-height:0}#sb_instagram.sbi_col_1 #sbi_images .sbi_item{width:100%}#sb_instagram.sbi_col_2 #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_3 #sbi_images .sbi_item{width:33.33%}#sb_instagram.sbi_col_4 #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_col_5 #sbi_images .sbi_item{width:20%}#sb_instagram.sbi_col_6 #sbi_images .sbi_item{width:16.66%}#sb_instagram.sbi_col_7 #sbi_images .sbi_item{width:14.28%}#sb_instagram.sbi_col_8 #sbi_images .sbi_item{width:12.5%}#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:11.11%}#sb_instagram.sbi_col_10 #sbi_images .sbi_item{width:10%}#sb_instagram.sbi_col_1.sbi_disable_mobile #sbi_images .sbi_item{width:100%}#sb_instagram.sbi_col_2.sbi_disable_mobile #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_3.sbi_disable_mobile #sbi_images .sbi_item{width:33.33%}#sb_instagram.sbi_col_4.sbi_disable_mobile #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_col_5.sbi_disable_mobile #sbi_images .sbi_item{width:20%}#sb_instagram.sbi_col_6.sbi_disable_mobile #sbi_images .sbi_item{width:16.66%}#sb_instagram.sbi_col_7.sbi_disable_mobile #sbi_images .sbi_item{width:14.28%}#sb_instagram.sbi_col_8.sbi_disable_mobile #sbi_images .sbi_item{width:12.5%}#sb_instagram.sbi_col_9.sbi_disable_mobile #sbi_images .sbi_item{width:11.11%}#sb_instagram.sbi_col_10.sbi_disable_mobile #sbi_images .sbi_item{width:10%}#sb_instagram .sbi_photo_wrap{position:relative}#sb_instagram .sbi_photo{display:block;text-decoration:none}#sb_instagram .sbi_photo img{width:100%;height:auto}#sb_instagram .sbi_no_js img{display:none}#sb_instagram a,#sb_instagram a:active,#sb_instagram a:focus,#sb_instagram a:hover{outline:0}#sb_instagram img{display:block;padding:0!important;margin:0!important;max-width:100%!important;opacity:1!important}#sb_instagram .sbi_link{display:none;position:absolute;bottom:0;right:0;width:100%;padding:10px 0;background:rgba(0,0,0,.5);text-align:center;color:#fff;font-size:12px;line-height:1.1}#sb_instagram .sbi_link a{padding:0 6px;text-decoration:none;color:#fff;font-size:12px;line-height:1.1;display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1}#sb_instagram .sbi_link .sbi_lightbox_link{padding-bottom:5px}#sb_instagram .sbi_link a:focus,#sb_instagram .sbi_link a:hover{text-decoration:underline}#sb_instagram .sbi_photo_wrap:focus .sbi_link,#sb_instagram .sbi_photo_wrap:hover .sbi_link{display:block}#sb_instagram svg:not(:root).svg-inline--fa{height:1em}#sb_instagram .sbi_type_carousel .sbi_playbtn,#sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,#sb_instagram .sbi_type_video .sbi_playbtn,#sb_instagram .sbi_type_video .svg-inline--fa.fa-play,.sbi_type_carousel .fa-clone{display:block!important;position:absolute;z-index:1;color:#fff;color:rgba(255,255,255,.9);font-style:normal!important;text-shadow:0 0 8px rgba(0,0,0,.8)}#sb_instagram .sbi_type_carousel .sbi_playbtn,#sb_instagram .sbi_type_video .sbi_playbtn{z-index:2;top:50%;left:50%;margin-top:-24px;margin-left:-19px;padding:0;font-size:48px}#sb_instagram .sbi_type_carousel .fa-clone{right:12px;top:12px;font-size:24px;text-shadow:0 0 8px rgba(0,0,0,.3)}#sb_instagram .sbi_type_carousel .svg-inline--fa.fa-play,#sb_instagram .sbi_type_video .svg-inline--fa.fa-play,.sbi_type_carousel svg.fa-clone{-webkit-filter:drop-shadow( 0 0 2px rgba(0,0,0,.4) );filter:drop-shadow( 0 0 2px rgba(0,0,0,.4) )}#sb_instagram .sbi_loader{width:20px;height:20px;position:relative;top:50%;left:50%;margin:-10px 0 0 -10px;background-color:#000;background-color:rgba(0,0,0,.5);border-radius:100%;-webkit-animation:sbi-sk-scaleout 1s infinite ease-in-out;animation:sbi-sk-scaleout 1s infinite ease-in-out}#sb_instagram #sbi_load .sbi_loader{position:absolute;margin-top:-11px;background-color:#fff;opacity:1}@-webkit-keyframes sbi-sk-scaleout{0%{-webkit-transform:scale(0)}100%{-webkit-transform:scale(1);opacity:0}}@keyframes sbi-sk-scaleout{0%{-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);opacity:0}}#sb_instagram .fa-spin,#sbi_lightbox .fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}#sb_instagram .fa-pulse,#sbi_lightbox .fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.sbi-screenreader{text-indent:-9999px!important;display:block!important;width:0!important;height:0!important;line-height:0!important}#sb_instagram .sb_instagram_header{float:left;clear:both;margin:0 0 15px 0;padding:0;line-height:1.2;width:100%}#sb_instagram .sb_instagram_header a{float:left;display:block;text-decoration:none;transition:color .5s ease}@media all and (min-width:480px){#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img{width:80px;height:80px;border-radius:40px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_img img{width:80px;height:80px;border-radius:40px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3{font-size:20px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{font-size:14px}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info,#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text h3{margin-left:95px!important;line-height:1.4}#sb_instagram .sbi_medium .sbi_header_text h3{margin-right:-85px!important}#sb_instagram .sb_instagram_header.sbi_medium .sbi_header_text .sbi_bio_info{margin-top:4px!important}#sb_instagram .sbi_medium .sbi_header_text.sbi_no_info h3{padding-top:20px!important}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_img{width:120px;height:120px;border-radius:60px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_img img{width:120px;height:120px;border-radius:60px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3{font-size:28px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{font-size:16px}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info,#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text h3{margin-left:140px!important;line-height:1.5}#sb_instagram .sbi_large .sbi_header_text h3{margin-right:-120px!important}#sb_instagram .sb_instagram_header.sbi_large .sbi_header_text .sbi_bio_info{margin-top:12px!important}#sb_instagram .sbi_large .sbi_header_text.sbi_no_info h3{padding-top:32px!important}}#sb_instagram .sbi_header_img{float:left;position:relative;width:50px;margin:0 0 0 -100%!important;overflow:hidden;-moz-border-radius:40px;-webkit-border-radius:40px;border-radius:40px}#sb_instagram .sbi_header_img img{float:left;margin:0!important;padding:0!important;border:none!important;-moz-border-radius:40px;-webkit-border-radius:40px;border-radius:40px}#sb_instagram .sbi_header_img_hover{opacity:0;position:absolute;width:100%;top:0;bottom:0;left:0;text-align:center;color:#fff;background:rgba(0,0,0,.75)}#sb_instagram .sbi_header_img_hover .sbi_new_logo{position:absolute;top:50%;left:50%;margin-top:-12px;margin-left:-12px;width:24px;height:24px;font-size:24px}#sb_instagram .sbi_header_img_hover i{overflow:hidden;background:url(../img/small-logo.png) no-repeat 0 0}#sb_instagram .sbi_header_img_hover{z-index:2;transition:opacity .4s ease-in-out}#sb_instagram .sb_instagram_header .sbi_fade_in{opacity:1;transition:opacity .2s ease-in-out}#sb_instagram .sbi_header_img_hover{position:absolute;width:100%;top:0;bottom:0;left:0;text-align:center;color:#fff;background:rgba(0,0,0,.75);-moz-opacity:0;-khtml-opacity:0;opacity:0;border-radius:40px;transition:opacity .2s}#sb_instagram .sb_instagram_header a:focus .sbi_header_img_hover,#sb_instagram .sb_instagram_header a:hover .sbi_header_img_hover{opacity:1}#sb_instagram .sbi_header_text{float:left;width:100%;padding-top:5px}#sb_instagram .sb_instagram_header a{text-decoration:none}#sb_instagram .sbi_header_text .sbi_bio,#sb_instagram .sbi_header_text h3{float:left;clear:both;width:auto;margin:0 0 0 60px!important;padding:0!important}#sb_instagram .sb_instagram_header h3{font-size:16px;line-height:1.3}#sb_instagram .sb_instagram_header p{font-size:13px;line-height:1.3}#sb_instagram .sb_instagram_header h3.sbi_no_bio{padding-top:9px!important}#sb_instagram .sbi_header_text img.emoji{margin-right:3px!important}#sb_instagram #sbi_load{float:left;clear:both;width:100%;text-align:center}#sb_instagram #sbi_load .fa-spinner{display:none;position:absolute;top:50%;left:50%;margin:-8px 0 0 -7px;font-size:15px}#sb_instagram #sbi_load{opacity:1;transition:all .5s ease-in}#sb_instagram .sbi_load_btn .sbi_btn_text,#sb_instagram .sbi_load_btn .sbi_loader{opacity:1;transition:all .1s ease-in}#sb_instagram .sbi_hidden{opacity:0!important}#sb_instagram #sbi_load .sbi_load_btn,#sb_instagram .sbi_follow_btn a{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;padding:7px 14px;margin:5px auto 0 auto;background:#333;color:#eee;border:none;color:#fff;text-decoration:none;font-size:13px;line-height:1.5;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#sb_instagram #sbi_load .sbi_load_btn{position:relative}#sb_instagram .sbi_follow_btn{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;text-align:center}#sb_instagram .sbi_follow_btn.sbi_top{display:block;margin-bottom:5px}#sb_instagram .sbi_follow_btn a{background:#408bd1;color:#fff}#sb_instagram #sbi_load .sbi_load_btn,#sb_instagram .sbi_follow_btn a{transition:all .1s ease-in}#sb_instagram #sbi_load .sbi_load_btn:hover{outline:0;box-shadow:inset 0 0 20px 20px rgba(255,255,255,.25)}#sb_instagram .sbi_follow_btn a:focus,#sb_instagram .sbi_follow_btn a:hover{outline:0;box-shadow:inset 0 0 10px 20px #359dff}#sb_instagram #sbi_load .sbi_load_btn.sbi_custom:hover,#sb_instagram .sbi_follow_btn.sbi_custom a:focus,#sb_instagram .sbi_follow_btn.sbi_custom a:hover{box-shadow:inset 0 0 20px 20px rgba(255,255,255,.15)}#sb_instagram #sbi_load .sbi_load_btn:active,#sb_instagram .sbi_follow_btn a:active{box-shadow:inset 0 0 10px 20px rgba(0,0,0,.3)}#sb_instagram .sbi_follow_btn .fa,#sb_instagram .sbi_follow_btn svg{margin-bottom:-1px;margin-right:7px;font-size:15px}#sb_instagram .sbi_follow_btn svg{vertical-align:-.125em}#sb_instagram #sbi_load .sbi_follow_btn{margin-left:5px}#sb_instagram .sb_instagram_error{width:100%;text-align:center;line-height:1.4}#sbi_mod_error{display:none;border:1px solid #ddd;background:#eee;color:#333;margin:10px 0 0;padding:10px 15px;font-size:13px;text-align:center;clear:both;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px}#sbi_mod_error p{padding:5px 0!important;margin:0!important;line-height:1.3!important}#sbi_mod_error ol,#sbi_mod_error ul{padding:5px 0 5px 20px!important;margin:0!important}#sbi_mod_error li{padding:1px 0!important;margin:0!important}#sbi_mod_error span{font-size:12px}#sb_instagram.sbi_medium .sbi_photo_wrap .svg-inline--fa.fa-play,#sb_instagram.sbi_medium .sbi_playbtn{margin-top:-12px;margin-left:-9px;font-size:23px}#sb_instagram.sbi_medium .sbi_type_carousel .sbi_photo_wrap .fa-clone{right:8px;top:8px;font-size:18px}#sb_instagram.sbi_small .sbi_photo_wrap .svg-inline--fa.fa-play,#sb_instagram.sbi_small .sbi_playbtn{margin-top:-9px;margin-left:-7px;font-size:18px}#sb_instagram.sbi_small .sbi_type_carousel .sbi_photo_wrap .fa-clone{right:5px;top:5px;font-size:12px}@media all and (max-width:640px){#sb_instagram.sbi_col_3 #sbi_images .sbi_item,#sb_instagram.sbi_col_4 #sbi_images .sbi_item,#sb_instagram.sbi_col_5 #sbi_images .sbi_item,#sb_instagram.sbi_col_6 #sbi_images .sbi_item{width:50%}#sb_instagram.sbi_col_10 #sbi_images .sbi_item,#sb_instagram.sbi_col_7 #sbi_images .sbi_item,#sb_instagram.sbi_col_8 #sbi_images .sbi_item,#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:25%}#sb_instagram.sbi_width_resp{width:100%!important}}@media all and (max-width:480px){#sb_instagram.sbi_col_10 #sbi_images .sbi_item,#sb_instagram.sbi_col_3 #sbi_images .sbi_item,#sb_instagram.sbi_col_4 #sbi_images .sbi_item,#sb_instagram.sbi_col_5 #sbi_images .sbi_item,#sb_instagram.sbi_col_6 #sbi_images .sbi_item,#sb_instagram.sbi_col_7 #sbi_images .sbi_item,#sb_instagram.sbi_col_8 #sbi_images .sbi_item,#sb_instagram.sbi_col_9 #sbi_images .sbi_item{width:100%}}#sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo_wrap{box-sizing:border-box;position:relative;overflow:hidden}#sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo_wrap:before{content:"";display:block;padding-top:100%;z-index:-300}#sb_instagram.sbi_no_js #sbi_images .sbi_item .sbi_photo{position:absolute;top:0;left:0;bottom:0;right:0}#sb_instagram.sbi_no_js #sbi_images .sbi_item.sbi_transition{opacity:1;max-height:640px}#sb_instagram.sbi_no_js .sbi_load_btn,#sb_instagram.sbi_no_js .sbi_photo img{display:none}
img/instagram-pro-promo.png CHANGED
Binary file
img/placeholder.png ADDED
Binary file
img/sbi-icon-offer.png ADDED
Binary file
img/sbi-icon.png CHANGED
Binary file
inc/admin/actions.php ADDED
@@ -0,0 +1,817 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Includes functions related to actions while in the admin area.
4
+ *
5
+ * - All AJAX related features
6
+ * - Enqueueing of JS and CSS files
7
+ * - Settings link on "Plugins" page
8
+ * - Creation of local avatar image files
9
+ * - Connecting accounts on the "Configure" tab
10
+ * - Displaying admin notices
11
+ * - Clearing caches
12
+ */
13
+ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14
+
15
+ function sb_instagram_admin_style() {
16
+ wp_register_style( 'sb_instagram_admin_css', SBI_PLUGIN_URL . 'css/sb-instagram-admin.css', array(), SBIVER );
17
+ wp_enqueue_style( 'sb_instagram_font_awesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css' );
18
+ wp_enqueue_style( 'sb_instagram_admin_css' );
19
+ wp_enqueue_style( 'wp-color-picker' );
20
+ }
21
+ add_action( 'admin_enqueue_scripts', 'sb_instagram_admin_style' );
22
+
23
+ function sb_instagram_admin_scripts() {
24
+ wp_enqueue_script( 'sb_instagram_admin_js', SBI_PLUGIN_URL . 'js/sb-instagram-admin.js', array(), SBIVER );
25
+ wp_localize_script( 'sb_instagram_admin_js', 'sbiA', array(
26
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
27
+ 'sbi_nonce' => wp_create_nonce( 'sbi_nonce' )
28
+ )
29
+ );
30
+ if( !wp_script_is('jquery-ui-draggable') ) {
31
+ wp_enqueue_script(
32
+ array(
33
+ 'jquery',
34
+ 'jquery-ui-core',
35
+ 'jquery-ui-draggable'
36
+ )
37
+ );
38
+ }
39
+ wp_enqueue_script(
40
+ array(
41
+ 'hoverIntent',
42
+ 'wp-color-picker'
43
+ )
44
+ );
45
+ }
46
+ add_action( 'admin_enqueue_scripts', 'sb_instagram_admin_scripts' );
47
+
48
+ // Add a Settings link to the plugin on the Plugins page
49
+ $sbi_plugin_file = 'instagram-feed/instagram-feed.php';
50
+ add_filter( "plugin_action_links_{$sbi_plugin_file}", 'sbi_add_settings_link', 10, 2 );
51
+
52
+ //modify the link by unshifting the array
53
+ function sbi_add_settings_link( $links, $file ) {
54
+ $sbi_settings_link = '<a href="' . admin_url( 'admin.php?page=sb-instagram-feed' ) . '">' . __( 'Settings', 'instagram-feed' ) . '</a>';
55
+ array_unshift( $links, $sbi_settings_link );
56
+
57
+ return $links;
58
+ }
59
+
60
+
61
+ /**
62
+ * Called via ajax to automatically save access token and access token secret
63
+ * retrieved with the big blue button
64
+ */
65
+ function sbi_auto_save_tokens() {
66
+ $nonce = $_POST['sbi_nonce'];
67
+
68
+ if ( ! wp_verify_nonce( $nonce, 'sbi_nonce' ) ) {
69
+ die ( 'You did not do this the right way!' );
70
+ }
71
+
72
+ wp_cache_delete ( 'alloptions', 'options' );
73
+
74
+ $options = sbi_get_database_settings();
75
+ $new_access_token = isset( $_POST['access_token'] ) ? sanitize_text_field( $_POST['access_token'] ) : false;
76
+ $split_token = $new_access_token ? explode( '.', $new_access_token ) : array();
77
+ $new_user_id = isset( $split_token[0] ) ? $split_token[0] : '';
78
+
79
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
80
+ $test_connection_data = sbi_account_data_for_token( $new_access_token );
81
+
82
+ $connected_accounts[ $new_user_id ] = array(
83
+ 'access_token' => sbi_get_parts( $new_access_token ),
84
+ 'user_id' => $test_connection_data['id'],
85
+ 'username' => $test_connection_data['username'],
86
+ 'is_valid' => $test_connection_data['is_valid'],
87
+ 'last_checked' => $test_connection_data['last_checked'],
88
+ 'profile_picture' => $test_connection_data['profile_picture'],
89
+ );
90
+
91
+ if ( !$options['sb_instagram_disable_resize'] ) {
92
+ if ( sbi_create_local_avatar( $test_connection_data['username'], $test_connection_data['profile_picture'] ) ) {
93
+ $connected_accounts[ $new_user_id ]['local_avatar'] = true;
94
+ }
95
+ } else {
96
+ $connected_accounts[ $new_user_id ]['local_avatar'] = false;
97
+ }
98
+
99
+ $options['connected_accounts'] = $connected_accounts;
100
+
101
+ update_option( 'sb_instagram_settings', $options );
102
+
103
+ echo wp_json_encode( $connected_accounts[ $new_user_id ] );
104
+
105
+ die();
106
+ }
107
+ add_action( 'wp_ajax_sbi_auto_save_tokens', 'sbi_auto_save_tokens' );
108
+
109
+ function sbi_delete_local_avatar( $username ) {
110
+ var_dump( 'deleting' );
111
+ $upload = wp_upload_dir();
112
+
113
+ $image_files = glob( trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) . $username . '.jpg' ); // get all matching images
114
+ foreach ( $image_files as $file ) { // iterate files
115
+ if ( is_file( $file ) ) {
116
+ unlink( $file );
117
+ }
118
+ }
119
+ }
120
+
121
+ function sbi_create_local_avatar( $username, $file_name ) {
122
+ $image_editor = wp_get_image_editor( $file_name );
123
+
124
+ if ( ! is_wp_error( $image_editor ) ) {
125
+ $upload = wp_upload_dir();
126
+
127
+ $full_file_name = trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) . $username . '.jpg';
128
+
129
+ $saved_image = $image_editor->save( $full_file_name );
130
+
131
+ if ( ! $saved_image ) {
132
+ global $sb_instagram_posts_manager;
133
+
134
+ $sb_instagram_posts_manager->add_error( 'image_editor_save', array(
135
+ __( 'Error saving edited image.', 'instagram-feed' ),
136
+ $full_file_name
137
+ ) );
138
+ } else {
139
+ return true;
140
+ }
141
+ } else {
142
+ global $sb_instagram_posts_manager;
143
+
144
+ $message = __( 'Error editing image.', 'instagram-feed' );
145
+ if ( isset( $image_editor ) && isset( $image_editor->errors ) ) {
146
+ foreach ( $image_editor->errors as $key => $item ) {
147
+ $message .= ' ' . $key . '- ' . $item[0] . ' |';
148
+ }
149
+ }
150
+
151
+ $sb_instagram_posts_manager->add_error( 'image_editor', array( $file_name, $message ) );
152
+ }
153
+ return false;
154
+ }
155
+
156
+ function sbi_connect_business_accounts() {
157
+ $nonce = $_POST['sbi_nonce'];
158
+
159
+ if ( ! wp_verify_nonce( $nonce, 'sbi_nonce' ) ) {
160
+ die ( 'You did not do this the right way!' );
161
+ }
162
+
163
+ $accounts = isset( $_POST['accounts'] ) ? json_decode( stripslashes( $_POST['accounts'] ), true ) : false;
164
+ $options = sbi_get_database_settings();
165
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
166
+
167
+ foreach ( $accounts as $account ) {
168
+ $access_token = isset( $account['access_token'] ) ? $account['access_token'] : '';
169
+ $page_access_token = isset( $account['page_access_token'] ) ? $account['page_access_token'] : '';
170
+ $username = isset( $account['username'] ) ? $account['username'] : '';
171
+ $name = isset( $account['name'] ) ? $account['name'] : '';
172
+ $profile_picture = isset( $account['profile_picture_url'] ) ? $account['profile_picture_url'] : '';
173
+ $user_id = isset( $account['id'] ) ? $account['id'] : '';
174
+ $type = 'business';
175
+
176
+ $connected_accounts[ $user_id ] = array(
177
+ 'access_token' => $access_token,
178
+ 'page_access_token' => $page_access_token,
179
+ 'user_id' => $user_id,
180
+ 'username' => $username,
181
+ 'is_valid' => true,
182
+ 'last_checked' => time(),
183
+ 'profile_picture' => $profile_picture,
184
+ 'name' => $name,
185
+ 'type' => $type
186
+ );
187
+
188
+ if ( !$options['sb_instagram_disable_resize'] ) {
189
+ if ( sbi_create_local_avatar( $username, $profile_picture ) ) {
190
+ $connected_accounts[ $user_id ]['local_avatar'] = true;
191
+ }
192
+ } else {
193
+ $connected_accounts[ $user_id ]['local_avatar'] = false;
194
+ }
195
+ }
196
+
197
+ $options['connected_accounts'] = $connected_accounts;
198
+
199
+ update_option( 'sb_instagram_settings', $options );
200
+
201
+ echo wp_json_encode( $connected_accounts );
202
+
203
+ die();
204
+ }
205
+ add_action( 'wp_ajax_sbi_connect_business_accounts', 'sbi_connect_business_accounts' );
206
+
207
+ function sbi_auto_save_id() {
208
+ $nonce = $_POST['sbi_nonce'];
209
+
210
+ if ( ! wp_verify_nonce( $nonce, 'sbi_nonce' ) ) {
211
+ die ( 'You did not do this the right way!' );
212
+ }
213
+ if ( current_user_can( 'edit_posts' ) && isset( $_POST['id'] ) ) {
214
+ $options = get_option( 'sb_instagram_settings', array() );
215
+
216
+ $options['sb_instagram_user_id'] = array( sanitize_text_field( $_POST['id'] ) );
217
+
218
+ update_option( 'sb_instagram_settings', $options );
219
+ }
220
+ die();
221
+ }
222
+ add_action( 'wp_ajax_sbi_auto_save_id', 'sbi_auto_save_id' );
223
+
224
+ function sbi_test_token() {
225
+ $access_token = isset( $_POST['access_token'] ) ? sanitize_text_field( $_POST['access_token'] ) : false;
226
+ $account_id = isset( $_POST['account_id'] ) ? sanitize_text_field( $_POST['account_id'] ) : false;
227
+ $options = sbi_get_database_settings();
228
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
229
+
230
+ if ( $access_token ) {
231
+ wp_cache_delete ( 'alloptions', 'options' );
232
+
233
+ $number_dots = substr_count ( $access_token , '.' );
234
+ $test_connection_data = array( 'error_message' => 'A successful connection could not be made. Please make sure your Access Token is valid.');
235
+
236
+ if ( $number_dots > 1 ) {
237
+ $split_token = explode( '.', $access_token );
238
+ $new_user_id = isset( $split_token[0] ) ? $split_token[0] : '';
239
+
240
+ $test_connection_data = sbi_account_data_for_token( $access_token );
241
+ } else if (! empty( $account_id ) ) {
242
+ $url = 'https://graph.facebook.com/'.$account_id.'?fields=biography,id,username,website,followers_count,media_count,profile_picture_url,name&access_token='.sbi_maybe_clean( $access_token );
243
+ $json = json_decode( sbi_business_account_request( $url, array( 'access_token' => $access_token ) ), true );
244
+ if ( isset( $json['id'] ) ) {
245
+ $new_user_id = $json['id'];
246
+ $test_connection_data = array(
247
+ 'access_token' => $access_token,
248
+ 'id' => $json['id'],
249
+ 'username' => $json['username'],
250
+ 'type' => 'business',
251
+ 'is_valid' => true,
252
+ 'last_checked' => time(),
253
+ 'profile_picture' => $json['profile_picture_url']
254
+ );
255
+ }
256
+
257
+ }
258
+
259
+ if ( isset( $test_connection_data['error_message'] ) ) {
260
+ echo $test_connection_data['error_message'];
261
+ } elseif ( $test_connection_data !== false ) {
262
+ $username = $test_connection_data['username'] ? $test_connection_data['username'] : $connected_accounts[ $new_user_id ]['username'];
263
+ $user_id = $test_connection_data['id'] ? $test_connection_data['id'] : $connected_accounts[ $new_user_id ]['user_id'];
264
+ $profile_picture = $test_connection_data['profile_picture'] ? $test_connection_data['profile_picture'] : $connected_accounts[ $new_user_id ]['profile_picture'];
265
+ $type = isset( $test_connection_data['type'] ) ? $test_connection_data['type'] : 'personal';
266
+ $connected_accounts[ $new_user_id ] = array(
267
+ 'access_token' => sbi_get_parts( $access_token ),
268
+ 'user_id' => $user_id,
269
+ 'username' => $username,
270
+ 'type' => $type,
271
+ 'is_valid' => $test_connection_data['is_valid'],
272
+ 'last_checked' => $test_connection_data['last_checked'],
273
+ 'profile_picture' => $profile_picture
274
+ );
275
+
276
+ if ( !$options['sb_instagram_disable_resize'] ) {
277
+ if ( sbi_create_local_avatar( $username, $profile_picture ) ) {
278
+ $connected_accounts[ $new_user_id ]['local_avatar'] = true;
279
+ }
280
+ } else {
281
+ $connected_accounts[ $new_user_id ]['local_avatar'] = false;
282
+ }
283
+
284
+ $options['connected_accounts'] = $connected_accounts;
285
+
286
+ update_option( 'sb_instagram_settings', $options );
287
+
288
+ echo wp_json_encode( $connected_accounts[ $new_user_id ] );
289
+ } else {
290
+ echo 'A successful connection could not be made. Please make sure your Access Token is valid.';
291
+ }
292
+
293
+ }
294
+
295
+ die();
296
+ }
297
+ add_action( 'wp_ajax_sbi_test_token', 'sbi_test_token' );
298
+
299
+ function sbi_delete_account() {
300
+ $nonce = $_POST['sbi_nonce'];
301
+
302
+ if ( ! wp_verify_nonce( $nonce, 'sbi_nonce' ) ) {
303
+ die ( 'You did not do this the right way!' );
304
+ }
305
+ $account_id = isset( $_POST['account_id'] ) ? sanitize_text_field( $_POST['account_id'] ) : false;
306
+ $options = get_option( 'sb_instagram_settings', array() );
307
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
308
+
309
+ if ( $account_id ) {
310
+ wp_cache_delete ( 'alloptions', 'options' );
311
+ $username = $connected_accounts[ $account_id ]['username'];
312
+
313
+ $num_times_used = 0;
314
+ foreach ( $connected_accounts as $connected_account ) {
315
+
316
+ if ( $connected_account['username'] === $username ) {
317
+ $num_times_used++;
318
+ }
319
+ }
320
+
321
+ if ( $num_times_used < 2 ) {
322
+ sbi_delete_local_avatar( $username );
323
+ }
324
+
325
+ unset( $connected_accounts[ $account_id ] );
326
+
327
+ $options['connected_accounts'] = $connected_accounts;
328
+
329
+ update_option( 'sb_instagram_settings', $options );
330
+
331
+ }
332
+
333
+ die();
334
+ }
335
+ add_action( 'wp_ajax_sbi_delete_account', 'sbi_delete_account' );
336
+
337
+ function sbi_account_data_for_token( $access_token ) {
338
+ $return = array(
339
+ 'id' => false,
340
+ 'username' => false,
341
+ 'is_valid' => false,
342
+ 'last_checked' => time()
343
+ );
344
+ $url = 'https://api.instagram.com/v1/users/self/?access_token=' . sbi_maybe_clean( $access_token );
345
+ $args = array(
346
+ 'timeout' => 60,
347
+ 'sslverify' => false
348
+ );
349
+ $result = wp_remote_get( $url, $args );
350
+
351
+ if ( ! is_wp_error( $result ) ) {
352
+ $data = json_decode( $result['body'] );
353
+ } else {
354
+ $data = array();
355
+ }
356
+
357
+ if ( isset( $data->data->id ) ) {
358
+ $return['id'] = $data->data->id;
359
+ $return['username'] = $data->data->username;
360
+ $return['is_valid'] = true;
361
+ $return['profile_picture'] = $data->data->profile_picture;
362
+
363
+ } elseif ( isset( $data->error_type ) && $data->error_type === 'OAuthRateLimitException' ) {
364
+ $return['error_message'] = 'This account\'s access token is currently over the rate limit. Try removing this access token from all feeds and wait an hour before reconnecting.';
365
+ } else {
366
+ if ( is_wp_error( $result ) ) {
367
+ $return['error_message'] = '';
368
+
369
+ if ( isset( $result->errors ) ) {
370
+ foreach ( $result->errors as $key => $item ) {
371
+ $return['error_message'] .= ' '.$key . ' - ' . $item[0] . ' |';
372
+ }
373
+ }
374
+ } elseif ( isset( $data->error_message ) ) {
375
+ $return['error_message'] = $data->error_message;
376
+ }
377
+
378
+ }
379
+
380
+ return $return;
381
+ }
382
+
383
+ function sbi_get_connected_accounts_data( $sb_instagram_at ) {
384
+ $sbi_options = get_option( 'sb_instagram_settings' );
385
+ $return = array();
386
+ $return['connected_accounts'] = isset( $sbi_options['connected_accounts'] ) ? $sbi_options['connected_accounts'] : array();
387
+
388
+ if ( empty( $connected_accounts ) && ! empty( $sb_instagram_at ) ) {
389
+ $tokens = explode(',', $sb_instagram_at );
390
+ $user_ids = array();
391
+
392
+ foreach ( $tokens as $token ) {
393
+ $account = sbi_account_data_for_token( $token );
394
+ if ( isset( $account['is_valid'] ) ) {
395
+ $split = explode( '.', $token );
396
+ $return['connected_accounts'][ $split[0] ] = array(
397
+ 'access_token' => sbi_get_parts( $token ),
398
+ 'user_id' => $split[0],
399
+ 'username' => '',
400
+ 'is_valid' => true,
401
+ 'last_checked' => time(),
402
+ 'profile_picture' => ''
403
+ );
404
+ $user_ids[] = $split[0];
405
+ }
406
+
407
+ }
408
+
409
+ $sbi_options['connected_accounts'] = $return['connected_accounts'];
410
+ $sbi_options['sb_instagram_at'] = '';
411
+ $sbi_options['sb_instagram_user_id'] = $user_ids;
412
+
413
+ $return['user_ids'] = $user_ids;
414
+
415
+ update_option( 'sb_instagram_settings', $sbi_options );
416
+ }
417
+
418
+ return $return;
419
+ }
420
+
421
+ function sbi_business_account_request( $url, $account, $remove_access_token = true ) {
422
+ $args = array(
423
+ 'timeout' => 60,
424
+ 'sslverify' => false
425
+ );
426
+ $result = wp_remote_get( $url, $args );
427
+
428
+ if ( ! is_wp_error( $result ) ) {
429
+ $response_no_at = $remove_access_token ? str_replace( sbi_maybe_clean( $account['access_token'] ), '{accesstoken}', $result['body'] ) : $result['body'];
430
+ return $response_no_at;
431
+ } else {
432
+ return wp_json_encode( $result );
433
+ }
434
+ }
435
+
436
+ function sbi_after_connection() {
437
+
438
+ if ( isset( $_POST['access_token'] ) ) {
439
+ $access_token = sanitize_text_field( $_POST['access_token'] );
440
+ $account_info = sbi_account_data_for_token( $access_token );
441
+ echo wp_json_encode( $account_info );
442
+ }
443
+
444
+ die();
445
+ }
446
+ add_action( 'wp_ajax_sbi_after_connection', 'sbi_after_connection' );
447
+
448
+ function sbi_clear_backups() {
449
+ $nonce = isset( $_POST['sbi_nonce'] ) ? sanitize_text_field( $_POST['sbi_nonce'] ) : '';
450
+
451
+ if ( ! wp_verify_nonce( $nonce, 'sbi_nonce' ) ) {
452
+ die ( 'You did not do this the right way!' );
453
+ }
454
+
455
+ //Delete all transients
456
+ global $wpdb;
457
+ $table_name = $wpdb->prefix . "options";
458
+ $wpdb->query( "
459
+ DELETE
460
+ FROM $table_name
461
+ WHERE `option_name` LIKE ('%!sbi\_%')
462
+ " );
463
+ $wpdb->query( "
464
+ DELETE
465
+ FROM $table_name
466
+ WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
467
+ " );
468
+ $wpdb->query( "
469
+ DELETE
470
+ FROM $table_name
471
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
472
+ " );
473
+
474
+ die();
475
+ }
476
+ add_action( 'wp_ajax_sbi_clear_backups', 'sbi_clear_backups' );
477
+
478
+ function sbi_reset_resized() {
479
+
480
+ global $sb_instagram_posts_manager;
481
+ $sb_instagram_posts_manager->delete_all_sbi_instagram_posts();
482
+
483
+ echo "1";
484
+
485
+ die();
486
+ }
487
+ add_action( 'wp_ajax_sbi_reset_resized', 'sbi_reset_resized' );
488
+
489
+ function sbi_reset_log() {
490
+
491
+ delete_option( 'sb_instagram_errors' );
492
+
493
+ echo "1";
494
+
495
+ die();
496
+ }
497
+ add_action( 'wp_ajax_sbi_reset_log', 'sbi_reset_log' );
498
+
499
+ add_action('admin_notices', 'sbi_admin_error_notices');
500
+ function sbi_admin_error_notices() {
501
+ //Only display notice to admins
502
+ if( !current_user_can( 'manage_options' ) ) return;
503
+
504
+ global $sb_instagram_posts_manager;
505
+
506
+ if ( isset( $_GET['page'] ) && in_array( $_GET['page'], array( 'sb-instagram-feed' )) ) {
507
+ $errors = $sb_instagram_posts_manager->get_errors();
508
+ if ( ! empty( $errors ) && ( isset( $errors['database_create_posts'] ) || isset( $errors['database_create_posts_feeds'] ) || isset( $errors['upload_dir'] ) || isset( $errors['ajax'] ) ) ) : ?>
509
+ <div class="notice notice-warning is-dismissible sbi-admin-notice">
510
+
511
+ <?php foreach ( $sb_instagram_posts_manager->get_errors() as $type => $error ) : ?>
512
+ <?php if ( (in_array( $type, array( 'database_create_posts', 'database_create_posts_feeds', 'upload_dir' ) ) && !$sb_instagram_posts_manager->image_resizing_disabled() ) ) : ?>
513
+ <p><strong><?php echo $error[0]; ?></strong></p>
514
+ <p><?php _e( 'Note for support', 'instagram-feed' ); ?>: <?php echo $error[1]; ?></p>
515
+ <?php endif; ?>
516
+ <?php endforeach; ?>
517
+ <?php if ( ( isset( $errors['database_create_posts'] ) || isset( $errors['database_create_posts_feeds'] ) || isset( $errors['upload_dir'] ) ) && !$sb_instagram_posts_manager->image_resizing_disabled() ) : ?>
518
+ <p><?php _e( sprintf( 'Visit our %s page for help', '<a href="https://smashballoon.com/instagram-feed/support/faq/" target="_blank">FAQ</a>' ), 'instagram-feed' ); ?></p>
519
+ <?php endif; ?>
520
+
521
+ <?php foreach ( $sb_instagram_posts_manager->get_errors() as $type => $error ) : ?>
522
+ <?php if (in_array( $type, array( 'ajax' ) )) : ?>
523
+ <p class="sbi-admin-error" data-sbi-type="ajax"><strong><?php echo $error[0]; ?></strong></p>
524
+ <p><?php echo $error[1]; ?></p>
525
+ <?php endif; ?>
526
+ <?php endforeach; ?>
527
+
528
+ </div>
529
+
530
+ <?php endif;
531
+ }
532
+
533
+ }
534
+
535
+ function sbi_maybe_add_ajax_test_error() {
536
+ if ( isset( $_GET['page'] ) && $_GET['page'] === 'sb-instagram-feed' ) {
537
+ global $sb_instagram_posts_manager;
538
+
539
+ if ( $sb_instagram_posts_manager->should_add_ajax_test_notice() ) {
540
+ $sb_instagram_posts_manager->add_error( 'ajax', array( __( 'Unable to use admin-ajax.php when displaying feeds. Some features of the plugin will be unavailable.', 'instagram-feed' ), __( sprintf( 'Please visit %s to troubleshoot.', '<a href="https://smashballoon.com/admin-ajax-requests-are-not-working/">'.__( 'this page', 'instagram-feed' ).'</a>' ), 'instagram-feed' ) ) );
541
+ } else {
542
+ $sb_instagram_posts_manager->remove_error( 'ajax' );
543
+ }
544
+ }
545
+ }
546
+ add_action( 'admin_init', 'sbi_maybe_add_ajax_test_error' );
547
+
548
+ function sbi_get_current_time() {
549
+ $current_time = time();
550
+
551
+ // where to do tests
552
+ // $current_time = strtotime( 'November 25, 2022' ) + 1;
553
+
554
+ return $current_time;
555
+ }
556
+
557
+ // generates the html for the admin notices
558
+ function sbi_notices_html() {
559
+
560
+ //Only show to admins
561
+ $current_screen = get_current_screen();
562
+ $is_plugins_page = isset( $current_screen->id ) && $current_screen->id === 'plugins';
563
+ $page = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
564
+ //Only show to admins
565
+ if ( ! current_user_can( 'manage_options' )
566
+ || ($page !== 'sb-instagram-feed' && !$is_plugins_page) ) {
567
+ return;
568
+ }
569
+
570
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
571
+ $current_time = sbi_get_current_time();
572
+ $sbi_bfcm_discount_code = 'happysmashgiving' . date('Y', $current_time );
573
+
574
+ // reset everything for testing
575
+ if ( false ) {
576
+ global $current_user;
577
+ $user_id = $current_user->ID;
578
+ delete_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice' );
579
+ //delete_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice' );
580
+ //$sbi_statuses_option = array( 'first_install' => strtotime( 'December 8, 2019' ) );
581
+ //$sbi_statuses_option = array( 'first_install' => time() );
582
+
583
+ //update_option( 'sbi_statuses', $sbi_statuses_option, false );
584
+ //delete_option( 'sbi_rating_notice');
585
+ //delete_transient( 'instagram_feed_rating_notice_waiting' );
586
+
587
+ //set_transient( 'instagram_feed_rating_notice_waiting', 'waiting', 2 * WEEK_IN_SECONDS );
588
+ //update_option( 'sbi_rating_notice', 'pending', false );
589
+ }
590
+
591
+ //$sbi_statuses_option['rating_notice_dismissed'] = time();
592
+ //update_option( 'sbi_statuses', $sbi_statuses_option, false );
593
+ // rating notice logic
594
+ $sbi_rating_notice_option = get_option( 'sbi_rating_notice', false );
595
+ $sbi_rating_notice_waiting = get_transient( 'instagram_feed_rating_notice_waiting' );
596
+ $should_show_rating_notice = ($sbi_rating_notice_waiting !== 'waiting' && $sbi_rating_notice_option !== 'dismissed');
597
+
598
+ // black friday cyber monday logic
599
+ $thanksgiving_this_year = sbi_get_future_date( 11, date('Y', $current_time ), 4, 4, 1 );
600
+ $one_week_before_black_friday_this_year = $thanksgiving_this_year - 7*24*60*60;
601
+ $one_day_after_cyber_monday_this_year = $thanksgiving_this_year + 5*24*60*60;
602
+ $has_been_two_days_since_rating_dismissal = isset( $sbi_statuses_option['rating_notice_dismissed'] ) ? ((int)$sbi_statuses_option['rating_notice_dismissed'] + 2*24*60*60) < $current_time : true;
603
+
604
+ $could_show_bfcm_discount = ($current_time > $one_week_before_black_friday_this_year && $current_time < $one_day_after_cyber_monday_this_year);
605
+ $should_show_bfcm_discount = false;
606
+ if ( $could_show_bfcm_discount && $has_been_two_days_since_rating_dismissal ) {
607
+ global $current_user;
608
+ $user_id = $current_user->ID;
609
+
610
+ $ignore_bfcm_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice' );
611
+ $ignore_bfcm_sale_notice_meta = isset( $ignore_bfcm_sale_notice_meta[0] ) ? $ignore_bfcm_sale_notice_meta[0] : '';
612
+
613
+ /* Check that the user hasn't already clicked to ignore the message */
614
+ $should_show_bfcm_discount = ($ignore_bfcm_sale_notice_meta !== 'always' && $ignore_bfcm_sale_notice_meta !== date( 'Y', $current_time ));
615
+ }
616
+
617
+ // new user discount logic
618
+ $in_new_user_month_range = true;
619
+ $should_show_new_user_discount = false;
620
+ $has_been_one_month_since_rating_dismissal = isset( $sbi_statuses_option['rating_notice_dismissed'] ) ? ((int)$sbi_statuses_option['rating_notice_dismissed'] + 30*24*60*60) < $current_time + 1: true;
621
+
622
+ if ( isset( $sbi_statuses_option['first_install'] ) && $sbi_statuses_option['first_install'] === 'from_update' ) {
623
+ global $current_user;
624
+ $user_id = $current_user->ID;
625
+ $ignore_new_user_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice' );
626
+ $ignore_new_user_sale_notice_meta = isset( $ignore_new_user_sale_notice_meta[0] ) ? $ignore_new_user_sale_notice_meta[0] : '';
627
+
628
+ if ( $ignore_new_user_sale_notice_meta !== 'always' ) {
629
+ $should_show_new_user_discount = true;
630
+ }
631
+ } elseif ( $in_new_user_month_range && $has_been_one_month_since_rating_dismissal ) {
632
+ global $current_user;
633
+ $user_id = $current_user->ID;
634
+ $ignore_new_user_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice' );
635
+ $ignore_new_user_sale_notice_meta = isset( $ignore_new_user_sale_notice_meta[0] ) ? $ignore_new_user_sale_notice_meta[0] : '';
636
+
637
+ if ( $ignore_new_user_sale_notice_meta !== 'always'
638
+ && isset( $sbi_statuses_option['first_install'] )
639
+ && $current_time > (int)$sbi_statuses_option['first_install'] + 60*60*24*30 ) {
640
+ $should_show_new_user_discount = true;
641
+ }
642
+ }
643
+
644
+ // for debugging
645
+ if ( false ) {
646
+ global $current_user;
647
+ $user_id = $current_user->ID;
648
+ $ignore_bfcm_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice' );
649
+ $ignore_new_user_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice' );
650
+
651
+ var_dump( 'new user rating option', $sbi_rating_notice_option );
652
+ var_dump( 'new user rating transient', $sbi_rating_notice_waiting );
653
+
654
+ var_dump( 'should show new user rating notice?', $should_show_rating_notice );
655
+
656
+ var_dump( 'new user discount month range?', $in_new_user_month_range );
657
+ var_dump( 'should show new user discount?', $should_show_new_user_discount );
658
+
659
+ var_dump( 'Thanksgiving this year?', date('m/d/Y', $thanksgiving_this_year ) );
660
+
661
+ var_dump( 'could show bfcm discount?', $could_show_bfcm_discount );
662
+ var_dump( 'should show bfcm discount?', $should_show_bfcm_discount );
663
+
664
+ var_dump( 'ignore_bfcm_sale_notice_meta', $ignore_bfcm_sale_notice_meta );
665
+ var_dump( 'ignore_new_user_sale_notice_meta', $ignore_new_user_sale_notice_meta );
666
+
667
+ var_dump( $sbi_statuses_option );
668
+ }
669
+
670
+ $should_show_bfcm_discount = false; // temporary to not show notices on update
671
+ $should_show_new_user_discount = false; // temporary to not show notices on update
672
+
673
+ if ( $should_show_rating_notice ) {
674
+ $other_notice_html = '';
675
+ $dismiss_url = add_query_arg( 'sbi_ignore_rating_notice_nag', '1' );
676
+ $later_url = add_query_arg( 'sbi_ignore_rating_notice_nag', 'later' );
677
+ if ( $should_show_bfcm_discount ) {
678
+ $other_notice_html = '<p class="sbi_other_notice">' . __( 'PS. We currently have a Black Friday/Cyber Monday deal going on for <b>20% off</b> the Pro version of the plugin.', 'instagram-feed' ) . '<a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi&discount='.$sbi_bfcm_discount_code.'" target="_blank" class="sbi_offer_btn">' . __( 'Get this deal!', 'instagram-feed' ) . '</a></p>';
679
+
680
+ $dismiss_url = add_query_arg( array(
681
+ 'sbi_ignore_rating_notice_nag' => '1',
682
+ 'sbi_ignore_bfcm_sale_notice' => date( 'Y', $current_time )
683
+ )
684
+ );
685
+ $later_url = add_query_arg( array(
686
+ 'sbi_ignore_rating_notice_nag' => 'later',
687
+ 'sbi_ignore_bfcm_sale_notice' => date( 'Y', $current_time )
688
+ )
689
+ );
690
+ }
691
+
692
+ echo"
693
+ <div class='sbi_notice sbi_review_notice'>
694
+ <img src='". SBI_PLUGIN_URL . 'img/sbi-icon.png' ."' alt='" . __( 'Instagram Feed', 'instagram-feed' ) . "'>
695
+ <div class='sbi-notice-text'>
696
+ <p>" . __( "It's great to see that you've been using the <strong>Smash Balloon Instagram Feed</strong> plugin for a while now. Hopefully you're happy with it!&nbsp; If so, would you consider leaving a positive review? It really helps to support the plugin and helps others to discover it too!", 'instagram-feed' ) . "</p>
697
+ <p class='links'>
698
+ <a class='sbi_notice_dismiss' href='https://wordpress.org/support/plugin/instagram-feed/reviews/' target='_blank'>" . __( 'Sure, I\'d love to!', 'instagram-feed' ) . "</a>
699
+ &middot;
700
+ <a class='sbi_notice_dismiss' href='" .esc_url( $dismiss_url ). "'>" . __( 'No thanks', 'instagram-feed' ) . "</a>
701
+ &middot;
702
+ <a class='sbi_notice_dismiss' href='" .esc_url( $dismiss_url ). "'>" . __( 'I\'ve already given a review', 'instagram-feed' ) . "</a>
703
+ &middot;
704
+ <a class='sbi_notice_dismiss' href='" .esc_url( $later_url ). "'>" . __( 'Ask Me Later', 'instagram-feed' ) . "</a>
705
+ </p>"
706
+ . $other_notice_html .
707
+ "</div>
708
+ <a class='sbi_notice_close' href='" .esc_url( $dismiss_url ). "'><i class='fa fa-close'></i></a>
709
+ </div>";
710
+
711
+ } elseif ( $should_show_new_user_discount ) {
712
+ global $current_user;
713
+ $user_id = $current_user->ID;
714
+ $ignore_new_user_sale_notice_meta = get_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice' );
715
+ if ( $ignore_new_user_sale_notice_meta !== 'always' ) {
716
+
717
+ echo "
718
+ <div class='sbi_notice sbi_review_notice sbi_new_user_sale_notice'>
719
+ <img src='" . SBI_PLUGIN_URL . 'img/sbi-icon-offer.png' . "' alt='Instagram Feed'>
720
+ <div class='sbi-notice-text'>
721
+ <p>" . __( '<b style="font-weight: 700;">Thank you!</b> We appreciate you using the Smash Balloon Instagram Feed plugin and wanted to say thank you by offering you a limited time <b>20% discount</b> on the Pro version.', 'instagram-feed' ) . "</p>
722
+ <p class='links'>
723
+ <a class='sbi_notice_dismiss sbi_offer_btn' href='https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi&discount=instagramthankyou' target='_blank'>" . __( 'Yes please!', 'instagram-feed' ) . "</a>
724
+ <a class='sbi_notice_dismiss' style='margin-left: 5px;' href='" . esc_url( add_query_arg( 'sbi_ignore_new_user_sale_notice', 'always' ) ) . "'>" . __( 'I\'m not interested', 'instagram-feed' ) . "</a>
725
+
726
+ </p>
727
+ </div>
728
+ <a class='sbi_new_user_sale_notice_close' href='" . esc_url( add_query_arg( 'sbi_ignore_new_user_sale_notice', 'always' ) ) . "'><i class='fa fa-close'></i></a>
729
+ </div>
730
+ ";
731
+ }
732
+
733
+ } elseif ( $should_show_bfcm_discount ) {
734
+
735
+ echo "
736
+ <div class='sbi_notice sbi_review_notice sbi_bfcm_sale_notice'>
737
+ <img src='". SBI_PLUGIN_URL . 'img/sbi-icon-offer.png' ."' alt='Instagram Feed'>
738
+ <div class='sbi-notice-text'>
739
+ <p>" . __( '<b style="font-weight: 700;">Black Friday/Cyber Monday Deal!</b> Thank you for using our free Instagram Feed plugin. For a limited time, we\'re offering <b>20% off</b> the Pro version for all of our users.', 'instagram-feed' ) . "</p>
740
+ <p class='links'>
741
+ <a class='sbi_notice_dismiss sbi_offer_btn' href='https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi&discount=".$sbi_bfcm_discount_code."' target='_blank'>" . __( 'Get this offer!', 'instagram-feed' ) . "</a>
742
+ <a class='sbi_notice_dismiss' style='margin-left: 5px;' href='" .esc_url( add_query_arg( 'sbi_ignore_bfcm_sale_notice', date( 'Y', $current_time ) ) ). "'>" . __( 'I\'m not interested', 'instagram-feed' ) . "</a>
743
+ </p>
744
+ </div>
745
+ <a class='sbi_bfcm_sale_notice_close' href='" .esc_url( add_query_arg( 'sbi_ignore_bfcm_sale_notice', date( 'Y', $current_time ) ) ). "'><i class='fa fa-close'></i></a>
746
+ </div>
747
+ ";
748
+
749
+ }
750
+
751
+ }
752
+ add_action( 'admin_notices', 'sbi_notices_html', 8 ); // priority 12 for Twitter, priority 10 for Facebook
753
+
754
+ function sbi_process_nags() {
755
+
756
+ global $current_user;
757
+ $user_id = $current_user->ID;
758
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
759
+
760
+ if ( isset( $_GET['sbi_ignore_rating_notice_nag'] ) ) {
761
+ if ( (int)$_GET['sbi_ignore_rating_notice_nag'] === 1 ) {
762
+ update_option( 'sbi_rating_notice', 'dismissed', false );
763
+ $sbi_statuses_option['rating_notice_dismissed'] = sbi_get_current_time();
764
+ update_option( 'sbi_statuses', $sbi_statuses_option, false );
765
+
766
+ } elseif ( $_GET['sbi_ignore_rating_notice_nag'] === 'later' ) {
767
+ set_transient( 'instagram_feed_rating_notice_waiting', 'waiting', 2 * WEEK_IN_SECONDS );
768
+ update_option( 'sbi_rating_notice', 'pending', false );
769
+ }
770
+ }
771
+
772
+ if ( isset( $_GET['sbi_ignore_new_user_sale_notice'] ) ) {
773
+ $response = sanitize_text_field( $_GET['sbi_ignore_new_user_sale_notice'] );
774
+ if ( $response === 'always' ) {
775
+ update_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice', 'always' );
776
+
777
+ $current_month_number = (int)date('n', sbi_get_current_time() );
778
+ $not_early_in_the_year = ($current_month_number > 5);
779
+
780
+ if ( $not_early_in_the_year ) {
781
+ update_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice', date( 'Y', sbi_get_current_time() ) );
782
+ }
783
+
784
+ }
785
+ }
786
+
787
+ if ( isset( $_GET['sbi_ignore_bfcm_sale_notice'] ) ) {
788
+ $response = sanitize_text_field( $_GET['sbi_ignore_bfcm_sale_notice'] );
789
+ if ( $response === 'always' ) {
790
+ update_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice', 'always' );
791
+ } elseif ( $response === date( 'Y', sbi_get_current_time() ) ) {
792
+ update_user_meta( $user_id, 'sbi_ignore_bfcm_sale_notice', date( 'Y', sbi_get_current_time() ) );
793
+ }
794
+ update_user_meta( $user_id, 'sbi_ignore_new_user_sale_notice', 'always' );
795
+ }
796
+
797
+ }
798
+ add_action( 'admin_init', 'sbi_process_nags' );
799
+
800
+ function sbi_get_future_date( $month, $year, $week, $day, $direction ) {
801
+ if ( $direction > 0 ) {
802
+ $startday = 1;
803
+ } else {
804
+ $startday = date( 't', mktime(0, 0, 0, $month, 1, $year ) );
805
+ }
806
+
807
+ $start = mktime( 0, 0, 0, $month, $startday, $year );
808
+ $weekday = date( 'N', $start );
809
+
810
+ $offset = 0;
811
+ if ( $direction * $day >= $direction * $weekday ) {
812
+ $offset = -$direction * 7;
813
+ }
814
+
815
+ $offset += $direction * ($week * 7) + ($day - $weekday);
816
+ return mktime( 0, 0, 0, $month, $startday + $offset, $year );
817
+ }
inc/admin/main.php ADDED
@@ -0,0 +1,2511 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Includes functions for all admin page templates and
4
+ * functions that add menu pages in the dashboard. Also
5
+ * has code for saving settings with defaults.
6
+ */
7
+ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
8
+
9
+ function sb_instagram_menu() {
10
+ $cap = current_user_can( 'manage_instagram_feed_options' ) ? 'manage_instagram_feed_options' : 'manage_options';
11
+
12
+ add_menu_page(
13
+ __( 'Instagram Feed', 'instagram-feed' ),
14
+ __( 'Instagram Feed', 'instagram-feed' ),
15
+ $cap,
16
+ 'sb-instagram-feed',
17
+ 'sb_instagram_settings_page'
18
+ );
19
+ add_submenu_page(
20
+ 'sb-instagram-feed',
21
+ __( 'Settings', 'instagram-feed' ),
22
+ __( 'Settings', 'instagram-feed' ),
23
+ $cap,
24
+ 'sb-instagram-feed',
25
+ 'sb_instagram_settings_page'
26
+ );
27
+ }
28
+ add_action('admin_menu', 'sb_instagram_menu');
29
+
30
+ function sb_instagram_settings_page() {
31
+
32
+ //Hidden fields
33
+ $sb_instagram_settings_hidden_field = 'sb_instagram_settings_hidden_field';
34
+ $sb_instagram_configure_hidden_field = 'sb_instagram_configure_hidden_field';
35
+ $sb_instagram_customize_hidden_field = 'sb_instagram_customize_hidden_field';
36
+
37
+ //Declare defaults
38
+ $sb_instagram_settings_defaults = array(
39
+ 'sb_instagram_at' => '',
40
+ 'sb_instagram_user_id' => '',
41
+ 'sb_instagram_preserve_settings' => '',
42
+ 'sb_instagram_cache_time' => 1,
43
+ 'sb_instagram_cache_time_unit' => 'hours',
44
+ 'sbi_caching_type' => 'page',
45
+ 'sbi_cache_cron_interval' => '12hours',
46
+ 'sbi_cache_cron_time' => '1',
47
+ 'sbi_cache_cron_am_pm' => 'am',
48
+ 'sb_instagram_width' => '100',
49
+ 'sb_instagram_width_unit' => '%',
50
+ 'sb_instagram_feed_width_resp' => false,
51
+ 'sb_instagram_height' => '',
52
+ 'sb_instagram_num' => '20',
53
+ 'sb_instagram_height_unit' => '',
54
+ 'sb_instagram_cols' => '4',
55
+ 'sb_instagram_disable_mobile' => false,
56
+ 'sb_instagram_image_padding' => '5',
57
+ 'sb_instagram_image_padding_unit' => 'px',
58
+ 'sb_instagram_sort' => 'none',
59
+ 'sb_instagram_background' => '',
60
+ 'sb_instagram_show_btn' => true,
61
+ 'sb_instagram_btn_background' => '',
62
+ 'sb_instagram_btn_text_color' => '',
63
+ 'sb_instagram_btn_text' => __( 'Load More...', 'instagram-feed' ),
64
+ 'sb_instagram_image_res' => 'auto',
65
+ //Header
66
+ 'sb_instagram_show_header' => true,
67
+ 'sb_instagram_header_size' => 'small',
68
+ 'sb_instagram_header_color' => '',
69
+ //Follow button
70
+ 'sb_instagram_show_follow_btn' => true,
71
+ 'sb_instagram_folow_btn_background' => '',
72
+ 'sb_instagram_follow_btn_text_color' => '',
73
+ 'sb_instagram_follow_btn_text' => __( 'Follow on Instagram', 'instagram-feed' ),
74
+ //Misc
75
+ 'sb_instagram_custom_css' => '',
76
+ 'sb_instagram_custom_js' => '',
77
+ 'sb_instagram_cron' => 'no',
78
+ 'sb_instagram_backup' => true,
79
+ 'sb_ajax_initial' => false,
80
+ 'sb_instagram_ajax_theme' => false,
81
+ 'sb_instagram_disable_resize' => false,
82
+ 'sb_instagram_favor_local' => false,
83
+ 'disable_js_image_loading' => false,
84
+ 'enqueue_js_in_head' => false,
85
+ 'enqueue_css_in_shortcode' => false,
86
+ 'sb_instagram_disable_mob_swipe' => false,
87
+ 'sbi_font_method' => 'svg',
88
+ 'sb_instagram_disable_awesome' => false
89
+ );
90
+ //Save defaults in an array
91
+ $options = wp_parse_args(get_option('sb_instagram_settings'), $sb_instagram_settings_defaults);
92
+ update_option( 'sb_instagram_settings', $options );
93
+
94
+ //Set the page variables
95
+ $sb_instagram_at = $options[ 'sb_instagram_at' ];
96
+ $sb_instagram_user_id = $options[ 'sb_instagram_user_id' ];
97
+ $sb_instagram_preserve_settings = $options[ 'sb_instagram_preserve_settings' ];
98
+ $sb_instagram_ajax_theme = $options[ 'sb_instagram_ajax_theme' ];
99
+ $enqueue_js_in_head = $options[ 'enqueue_js_in_head' ];
100
+ $disable_js_image_loading = $options[ 'disable_js_image_loading' ];
101
+ $sb_instagram_disable_resize = $options[ 'sb_instagram_disable_resize' ];
102
+ $sb_instagram_favor_local = $options[ 'sb_instagram_favor_local' ];
103
+
104
+ $sb_instagram_cache_time = $options[ 'sb_instagram_cache_time' ];
105
+ $sb_instagram_cache_time_unit = $options[ 'sb_instagram_cache_time_unit' ];
106
+
107
+ $sbi_caching_type = $options[ 'sbi_caching_type' ];
108
+ $sbi_cache_cron_interval = $options[ 'sbi_cache_cron_interval' ];
109
+ $sbi_cache_cron_time = $options[ 'sbi_cache_cron_time' ];
110
+ $sbi_cache_cron_am_pm = $options[ 'sbi_cache_cron_am_pm' ];
111
+
112
+ $sb_instagram_width = $options[ 'sb_instagram_width' ];
113
+ $sb_instagram_width_unit = $options[ 'sb_instagram_width_unit' ];
114
+ $sb_instagram_feed_width_resp = $options[ 'sb_instagram_feed_width_resp' ];
115
+ $sb_instagram_height = $options[ 'sb_instagram_height' ];
116
+ $sb_instagram_height_unit = $options[ 'sb_instagram_height_unit' ];
117
+ $sb_instagram_num = $options[ 'sb_instagram_num' ];
118
+ $sb_instagram_cols = $options[ 'sb_instagram_cols' ];
119
+ $sb_instagram_disable_mobile = $options[ 'sb_instagram_disable_mobile' ];
120
+ $sb_instagram_image_padding = $options[ 'sb_instagram_image_padding' ];
121
+ $sb_instagram_image_padding_unit = $options[ 'sb_instagram_image_padding_unit' ];
122
+ $sb_instagram_sort = $options[ 'sb_instagram_sort' ];
123
+ $sb_instagram_background = $options[ 'sb_instagram_background' ];
124
+ $sb_instagram_show_btn = $options[ 'sb_instagram_show_btn' ];
125
+ $sb_instagram_btn_background = $options[ 'sb_instagram_btn_background' ];
126
+ $sb_instagram_btn_text_color = $options[ 'sb_instagram_btn_text_color' ];
127
+ $sb_instagram_btn_text = $options[ 'sb_instagram_btn_text' ];
128
+ $sb_instagram_image_res = $options[ 'sb_instagram_image_res' ];
129
+ //Header
130
+ $sb_instagram_show_header = $options[ 'sb_instagram_show_header' ];
131
+ $sb_instagram_header_size = $options[ 'sb_instagram_header_size' ];
132
+ $sb_instagram_show_bio = isset( $options[ 'sb_instagram_show_bio' ] ) ? $options[ 'sb_instagram_show_bio' ] : true;
133
+ $sb_instagram_header_color = $options[ 'sb_instagram_header_color' ];
134
+ //Follow button
135
+ $sb_instagram_show_follow_btn = $options[ 'sb_instagram_show_follow_btn' ];
136
+ $sb_instagram_folow_btn_background = $options[ 'sb_instagram_folow_btn_background' ];
137
+ $sb_instagram_follow_btn_text_color = $options[ 'sb_instagram_follow_btn_text_color' ];
138
+ $sb_instagram_follow_btn_text = $options[ 'sb_instagram_follow_btn_text' ];
139
+ //Misc
140
+ $sb_instagram_custom_css = $options[ 'sb_instagram_custom_css' ];
141
+ $sb_instagram_custom_js = $options[ 'sb_instagram_custom_js' ];
142
+ $sb_instagram_cron = $options[ 'sb_instagram_cron' ];
143
+ $sb_instagram_backup = $options[ 'sb_instagram_backup' ];
144
+ $sb_ajax_initial = $options[ 'sb_ajax_initial' ];
145
+ $sbi_font_method = $options[ 'sbi_font_method' ];
146
+ $sb_instagram_disable_awesome = $options[ 'sb_instagram_disable_awesome' ];
147
+
148
+
149
+ //Check nonce before saving data
150
+ if ( ! isset( $_POST['sb_instagram_settings_nonce'] ) || ! wp_verify_nonce( $_POST['sb_instagram_settings_nonce'], 'sb_instagram_saving_settings' ) ) {
151
+ //Nonce did not verify
152
+ } else {
153
+ // See if the user has posted us some information. If they did, this hidden field will be set to 'Y'.
154
+ if( isset($_POST[ $sb_instagram_settings_hidden_field ]) && $_POST[ $sb_instagram_settings_hidden_field ] == 'Y' ) {
155
+
156
+ if( isset($_POST[ $sb_instagram_configure_hidden_field ]) && $_POST[ $sb_instagram_configure_hidden_field ] == 'Y' ) {
157
+
158
+ $sb_instagram_at = sanitize_text_field( $_POST[ 'sb_instagram_at' ] );
159
+ $sb_instagram_user_id = array();
160
+ if ( isset( $_POST[ 'sb_instagram_user_id' ] )) {
161
+ if ( is_array( $_POST[ 'sb_instagram_user_id' ] ) ) {
162
+ foreach( $_POST[ 'sb_instagram_user_id' ] as $user_id ) {
163
+ $sb_instagram_user_id[] = sanitize_text_field( $user_id );
164
+ }
165
+ } else {
166
+ $sb_instagram_user_id[] = sanitize_text_field( $_POST[ 'sb_instagram_user_id' ] );
167
+ }
168
+ }
169
+ isset($_POST[ 'sb_instagram_preserve_settings' ]) ? $sb_instagram_preserve_settings = sanitize_text_field( $_POST[ 'sb_instagram_preserve_settings' ] ) : $sb_instagram_preserve_settings = '';
170
+ isset($_POST[ 'sb_instagram_cache_time' ]) ? $sb_instagram_cache_time = sanitize_text_field( $_POST[ 'sb_instagram_cache_time' ] ) : $sb_instagram_cache_time = '';
171
+ isset($_POST[ 'sb_instagram_cache_time_unit' ]) ? $sb_instagram_cache_time_unit = sanitize_text_field( $_POST[ 'sb_instagram_cache_time_unit' ] ) : $sb_instagram_cache_time_unit = '';
172
+
173
+ isset($_POST[ 'sbi_caching_type' ]) ? $sbi_caching_type = sanitize_text_field( $_POST[ 'sbi_caching_type' ] ) : $sbi_caching_type = '';
174
+ isset($_POST[ 'sbi_cache_cron_interval' ]) ? $sbi_cache_cron_interval = sanitize_text_field( $_POST[ 'sbi_cache_cron_interval' ] ) : $sbi_cache_cron_interval = '';
175
+ isset($_POST[ 'sbi_cache_cron_time' ]) ? $sbi_cache_cron_time = sanitize_text_field( $_POST[ 'sbi_cache_cron_time' ] ) : $sbi_cache_cron_time = '';
176
+ isset($_POST[ 'sbi_cache_cron_am_pm' ]) ? $sbi_cache_cron_am_pm = sanitize_text_field( $_POST[ 'sbi_cache_cron_am_pm' ] ) : $sbi_cache_cron_am_pm = '';
177
+
178
+ $options[ 'sb_instagram_at' ] = $sb_instagram_at;
179
+ $options[ 'sb_instagram_user_id' ] = $sb_instagram_user_id;
180
+ $options[ 'sb_instagram_preserve_settings' ] = $sb_instagram_preserve_settings;
181
+
182
+ $options[ 'sb_instagram_cache_time' ] = $sb_instagram_cache_time;
183
+ $options[ 'sb_instagram_cache_time_unit' ] = $sb_instagram_cache_time_unit;
184
+
185
+ $options[ 'sbi_caching_type' ] = $sbi_caching_type;
186
+ $options[ 'sbi_cache_cron_interval' ] = $sbi_cache_cron_interval;
187
+ $options[ 'sbi_cache_cron_time' ] = $sbi_cache_cron_time;
188
+ $options[ 'sbi_cache_cron_am_pm' ] = $sbi_cache_cron_am_pm;
189
+
190
+
191
+ //Delete all SBI transients
192
+ global $wpdb;
193
+ $table_name = $wpdb->prefix . "options";
194
+ $wpdb->query( "
195
+ DELETE
196
+ FROM $table_name
197
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
198
+ " );
199
+ $wpdb->query( "
200
+ DELETE
201
+ FROM $table_name
202
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
203
+ " );
204
+ $wpdb->query( "
205
+ DELETE
206
+ FROM $table_name
207
+ WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
208
+ " );
209
+ $wpdb->query( "
210
+ DELETE
211
+ FROM $table_name
212
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
213
+ " );
214
+
215
+ if ( $sbi_caching_type === 'background' ) {
216
+ delete_option( 'sbi_cron_report' );
217
+ SB_Instagram_Cron_Updater::start_cron_job( $sbi_cache_cron_interval, $sbi_cache_cron_time, $sbi_cache_cron_am_pm );
218
+ }
219
+
220
+ } //End config tab post
221
+
222
+ if( isset($_POST[ $sb_instagram_customize_hidden_field ]) && $_POST[ $sb_instagram_customize_hidden_field ] == 'Y' ) {
223
+
224
+ //Validate and sanitize width field
225
+ $safe_width = intval( sanitize_text_field( $_POST['sb_instagram_width'] ) );
226
+ if ( ! $safe_width ) $safe_width = '';
227
+ if ( strlen( $safe_width ) > 4 ) $safe_width = substr( $safe_width, 0, 4 );
228
+ $sb_instagram_width = $safe_width;
229
+
230
+ $sb_instagram_width_unit = sanitize_text_field( $_POST[ 'sb_instagram_width_unit' ] );
231
+ isset($_POST[ 'sb_instagram_feed_width_resp' ]) ? $sb_instagram_feed_width_resp = sanitize_text_field( $_POST[ 'sb_instagram_feed_width_resp' ] ) : $sb_instagram_feed_width_resp = '';
232
+
233
+ //Validate and sanitize height field
234
+ $safe_height = intval( sanitize_text_field( $_POST['sb_instagram_height'] ) );
235
+ if ( ! $safe_height ) $safe_height = '';
236
+ if ( strlen( $safe_height ) > 4 ) $safe_height = substr( $safe_height, 0, 4 );
237
+ $sb_instagram_height = $safe_height;
238
+
239
+ $sb_instagram_height_unit = sanitize_text_field( $_POST[ 'sb_instagram_height_unit' ] );
240
+
241
+ //Validate and sanitize number of photos field
242
+ $safe_num = intval( sanitize_text_field( $_POST['sb_instagram_num'] ) );
243
+ if ( ! $safe_num ) $safe_num = '';
244
+ if ( strlen( $safe_num ) > 4 ) $safe_num = substr( $safe_num, 0, 4 );
245
+ $sb_instagram_num = $safe_num;
246
+
247
+ $sb_instagram_cols = sanitize_text_field( $_POST[ 'sb_instagram_cols' ] );
248
+ isset($_POST[ 'sb_instagram_disable_mobile' ]) ? $sb_instagram_disable_mobile = sanitize_text_field( $_POST[ 'sb_instagram_disable_mobile' ] ) : $sb_instagram_disable_mobile = '';
249
+
250
+ //Validate and sanitize padding field
251
+ $safe_padding = intval( sanitize_text_field( $_POST['sb_instagram_image_padding'] ) );
252
+ if ( ! $safe_padding ) $safe_padding = '';
253
+ if ( strlen( $safe_padding ) > 4 ) $safe_padding = substr( $safe_padding, 0, 4 );
254
+ $sb_instagram_image_padding = $safe_padding;
255
+
256
+ $sb_instagram_image_padding_unit = sanitize_text_field( $_POST[ 'sb_instagram_image_padding_unit' ] );
257
+ $sb_instagram_sort = sanitize_text_field( $_POST[ 'sb_instagram_sort' ] );
258
+ $sb_instagram_background = sanitize_text_field( $_POST[ 'sb_instagram_background' ] );
259
+ isset($_POST[ 'sb_instagram_show_btn' ]) ? $sb_instagram_show_btn = sanitize_text_field( $_POST[ 'sb_instagram_show_btn' ] ) : $sb_instagram_show_btn = '';
260
+ $sb_instagram_btn_background = sanitize_text_field( $_POST[ 'sb_instagram_btn_background' ] );
261
+ $sb_instagram_btn_text_color = sanitize_text_field( $_POST[ 'sb_instagram_btn_text_color' ] );
262
+ $sb_instagram_btn_text = sanitize_text_field( $_POST[ 'sb_instagram_btn_text' ] );
263
+ $sb_instagram_image_res = sanitize_text_field( $_POST[ 'sb_instagram_image_res' ] );
264
+ //Header
265
+ isset($_POST[ 'sb_instagram_show_header' ]) ? $sb_instagram_show_header = sanitize_text_field( $_POST[ 'sb_instagram_show_header' ] ) : $sb_instagram_show_header = '';
266
+ isset($_POST[ 'sb_instagram_show_bio' ]) ? $sb_instagram_show_bio = sanitize_text_field( $_POST[ 'sb_instagram_show_bio' ] ) : $sb_instagram_show_bio = '';
267
+ if (isset($_POST[ 'sb_instagram_header_size' ]) ) $sb_instagram_header_size = $_POST[ 'sb_instagram_header_size' ];
268
+
269
+ $sb_instagram_header_color = sanitize_text_field( $_POST[ 'sb_instagram_header_color' ] );
270
+ //Follow button
271
+ isset($_POST[ 'sb_instagram_show_follow_btn' ]) ? $sb_instagram_show_follow_btn = sanitize_text_field( $_POST[ 'sb_instagram_show_follow_btn' ] ) : $sb_instagram_show_follow_btn = '';
272
+ $sb_instagram_folow_btn_background = sanitize_text_field( $_POST[ 'sb_instagram_folow_btn_background' ] );
273
+ $sb_instagram_follow_btn_text_color = sanitize_text_field( $_POST[ 'sb_instagram_follow_btn_text_color' ] );
274
+ $sb_instagram_follow_btn_text = sanitize_text_field( $_POST[ 'sb_instagram_follow_btn_text' ] );
275
+ //Misc
276
+ $sb_instagram_custom_css = $_POST[ 'sb_instagram_custom_css' ];
277
+ $sb_instagram_custom_js = $_POST[ 'sb_instagram_custom_js' ];
278
+ isset($_POST[ 'sb_instagram_ajax_theme' ]) ? $sb_instagram_ajax_theme = sanitize_text_field( $_POST[ 'sb_instagram_ajax_theme' ] ) : $sb_instagram_ajax_theme = '';
279
+ isset($_POST[ 'enqueue_js_in_head' ]) ? $enqueue_js_in_head = $_POST[ 'enqueue_js_in_head' ] : $enqueue_js_in_head = '';
280
+ isset($_POST[ 'disable_js_image_loading' ]) ? $disable_js_image_loading = $_POST[ 'disable_js_image_loading' ] : $disable_js_image_loading = '';
281
+ isset($_POST[ 'sb_instagram_disable_resize' ]) ? $sb_instagram_disable_resize= sanitize_text_field( $_POST[ 'sb_instagram_disable_resize' ] ) : $sb_instagram_disable_resize = '';
282
+ isset($_POST[ 'sb_instagram_favor_local' ]) ? $sb_instagram_favor_local = sanitize_text_field( $_POST[ 'sb_instagram_favor_local' ] ) : $sb_instagram_favor_local = '';
283
+
284
+ if (isset($_POST[ 'sb_instagram_cron' ]) ) $sb_instagram_cron = $_POST[ 'sb_instagram_cron' ];
285
+ isset($_POST[ 'sb_instagram_backup' ]) ? $sb_instagram_backup = $_POST[ 'sb_instagram_backup' ] : $sb_instagram_backup = '';
286
+ isset($_POST[ 'sb_ajax_initial' ]) ? $sb_ajax_initial = $_POST[ 'sb_ajax_initial' ] : $sb_ajax_initial = '';
287
+ isset($_POST[ 'sbi_font_method' ]) ? $sbi_font_method = $_POST[ 'sbi_font_method' ] : $sbi_font_method = 'svg';
288
+ isset($_POST[ 'sb_instagram_disable_awesome' ]) ? $sb_instagram_disable_awesome = sanitize_text_field( $_POST[ 'sb_instagram_disable_awesome' ] ) : $sb_instagram_disable_awesome = '';
289
+
290
+ $options[ 'sb_instagram_width' ] = $sb_instagram_width;
291
+ $options[ 'sb_instagram_width_unit' ] = $sb_instagram_width_unit;
292
+ $options[ 'sb_instagram_feed_width_resp' ] = $sb_instagram_feed_width_resp;
293
+ $options[ 'sb_instagram_height' ] = $sb_instagram_height;
294
+ $options[ 'sb_instagram_height_unit' ] = $sb_instagram_height_unit;
295
+ $options[ 'sb_instagram_num' ] = $sb_instagram_num;
296
+ $options[ 'sb_instagram_cols' ] = $sb_instagram_cols;
297
+ $options[ 'sb_instagram_disable_mobile' ] = $sb_instagram_disable_mobile;
298
+ $options[ 'sb_instagram_image_padding' ] = $sb_instagram_image_padding;
299
+ $options[ 'sb_instagram_image_padding_unit' ] = $sb_instagram_image_padding_unit;
300
+ $options[ 'sb_instagram_sort' ] = $sb_instagram_sort;
301
+ $options[ 'sb_instagram_background' ] = $sb_instagram_background;
302
+ $options[ 'sb_instagram_show_btn' ] = $sb_instagram_show_btn;
303
+ $options[ 'sb_instagram_btn_background' ] = $sb_instagram_btn_background;
304
+ $options[ 'sb_instagram_btn_text_color' ] = $sb_instagram_btn_text_color;
305
+ $options[ 'sb_instagram_btn_text' ] = $sb_instagram_btn_text;
306
+ $options[ 'sb_instagram_image_res' ] = $sb_instagram_image_res;
307
+ //Header
308
+ $options[ 'sb_instagram_show_header' ] = $sb_instagram_show_header;
309
+ $options[ 'sb_instagram_header_size' ] = $sb_instagram_header_size;
310
+ $options[ 'sb_instagram_show_bio' ] = $sb_instagram_show_bio;
311
+ $options[ 'sb_instagram_header_color' ] = $sb_instagram_header_color;
312
+ //Follow button
313
+ $options[ 'sb_instagram_show_follow_btn' ] = $sb_instagram_show_follow_btn;
314
+ $options[ 'sb_instagram_folow_btn_background' ] = $sb_instagram_folow_btn_background;
315
+ $options[ 'sb_instagram_follow_btn_text_color' ] = $sb_instagram_follow_btn_text_color;
316
+ $options[ 'sb_instagram_follow_btn_text' ] = $sb_instagram_follow_btn_text;
317
+ //Misc
318
+ $options[ 'sb_instagram_custom_css' ] = $sb_instagram_custom_css;
319
+ $options[ 'sb_instagram_custom_js' ] = $sb_instagram_custom_js;
320
+ $options[ 'sb_instagram_ajax_theme' ] = $sb_instagram_ajax_theme;
321
+ $options[ 'enqueue_js_in_head' ] = $enqueue_js_in_head;
322
+ $options[ 'disable_js_image_loading' ] = $disable_js_image_loading;
323
+ $options[ 'sb_instagram_disable_resize' ] = $sb_instagram_disable_resize;
324
+ $options[ 'sb_instagram_favor_local' ] = $sb_instagram_favor_local;
325
+ $options[ 'sb_ajax_initial' ] = $sb_ajax_initial;
326
+ $options[ 'sb_instagram_cron' ] = $sb_instagram_cron;
327
+ $options['sb_instagram_backup'] = $sb_instagram_backup;
328
+ $options['sbi_font_method'] = $sbi_font_method;
329
+ $options[ 'sb_instagram_disable_awesome' ] = $sb_instagram_disable_awesome;
330
+
331
+ //clear expired tokens
332
+ delete_option( 'sb_expired_tokens' );
333
+
334
+ //Delete all SBI transients
335
+ global $wpdb;
336
+ $table_name = $wpdb->prefix . "options";
337
+ $wpdb->query( "
338
+ DELETE
339
+ FROM $table_name
340
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
341
+ " );
342
+ $wpdb->query( "
343
+ DELETE
344
+ FROM $table_name
345
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
346
+ " );
347
+ $wpdb->query( "
348
+ DELETE
349
+ FROM $table_name
350
+ WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
351
+ " );
352
+ $wpdb->query( "
353
+ DELETE
354
+ FROM $table_name
355
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
356
+ " );
357
+
358
+ if( $sb_instagram_cron == 'no' ) wp_clear_scheduled_hook('sb_instagram_cron_job');
359
+
360
+ //Run cron when Misc settings are saved
361
+ if( $sb_instagram_cron == 'yes' ){
362
+ //Clear the existing cron event
363
+ wp_clear_scheduled_hook('sb_instagram_cron_job');
364
+
365
+ $sb_instagram_cache_time = $options[ 'sb_instagram_cache_time' ];
366
+ $sb_instagram_cache_time_unit = $options[ 'sb_instagram_cache_time_unit' ];
367
+
368
+ //Set the event schedule based on what the caching time is set to
369
+ $sb_instagram_cron_schedule = 'hourly';
370
+ if( $sb_instagram_cache_time_unit == 'hours' && $sb_instagram_cache_time > 5 ) $sb_instagram_cron_schedule = 'twicedaily';
371
+ if( $sb_instagram_cache_time_unit == 'days' ) $sb_instagram_cron_schedule = 'daily';
372
+
373
+ wp_schedule_event(time(), $sb_instagram_cron_schedule, 'sb_instagram_cron_job');
374
+
375
+ sb_instagram_clear_page_caches();
376
+ }
377
+
378
+ } //End customize tab post
379
+
380
+ //Save the settings to the settings array
381
+ update_option( 'sb_instagram_settings', $options );
382
+
383
+ ?>
384
+ <div class="updated"><p><strong><?php _e( 'Settings saved.', 'instagram-feed' ); ?></strong></p></div>
385
+ <?php } ?>
386
+
387
+ <?php } //End nonce check ?>
388
+
389
+
390
+ <div id="sbi_admin" class="wrap">
391
+
392
+ <div id="header">
393
+ <h1><?php _e( 'Instagram Feed', 'instagram-feed' ); ?></h1>
394
+ </div>
395
+
396
+ <form name="form1" method="post" action="">
397
+ <input type="hidden" name="<?php echo $sb_instagram_settings_hidden_field; ?>" value="Y">
398
+ <?php wp_nonce_field( 'sb_instagram_saving_settings', 'sb_instagram_settings_nonce' ); ?>
399
+
400
+ <?php $sbi_active_tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( $_GET['tab'] ) : 'configure'; ?>
401
+ <h2 class="nav-tab-wrapper">
402
+ <a href="?page=sb-instagram-feed&amp;tab=configure" class="nav-tab <?php echo $sbi_active_tab == 'configure' ? 'nav-tab-active' : ''; ?>"><?php _e( '1. Configure', 'instagram-feed' ); ?></a>
403
+ <a href="?page=sb-instagram-feed&amp;tab=customize" class="nav-tab <?php echo $sbi_active_tab == 'customize' ? 'nav-tab-active' : ''; ?>"><?php _e( '2. Customize', 'instagram-feed' ); ?></a>
404
+ <a href="?page=sb-instagram-feed&amp;tab=display" class="nav-tab <?php echo $sbi_active_tab == 'display' ? 'nav-tab-active' : ''; ?>"><?php _e( '3. Display Your Feed', 'instagram-feed' ); ?></a>
405
+ <a href="?page=sb-instagram-feed&amp;tab=support" class="nav-tab <?php echo $sbi_active_tab == 'support' ? 'nav-tab-active' : ''; ?>"><?php _e( 'Support', 'instagram-feed' ); ?></a>
406
+ </h2>
407
+
408
+ <?php if( $sbi_active_tab == 'configure' ) { //Start Configure tab ?>
409
+ <input type="hidden" name="<?php echo $sb_instagram_configure_hidden_field; ?>" value="Y">
410
+
411
+ <table class="form-table">
412
+ <tbody>
413
+ <h3><?php _e( 'Configure', 'instagram-feed' ); ?></h3>
414
+
415
+ <div id="sbi_config">
416
+ <a data-new-api="https://www.facebook.com/dialog/oauth?client_id=254638078422287&redirect_uri=https://api.smashballoon.com/instagram-graph-api-redirect.php&scope=manage_pages,instagram_basic,instagram_manage_insights&state=<?php echo admin_url('admin.php?page=sb-instagram-feed'); ?>"
417
+ data-old-api="https://instagram.com/oauth/authorize/?client_id=3a81a9fa2a064751b8c31385b91cc25c&scope=basic&redirect_uri=https://smashballoon.com/instagram-feed/instagram-token-plugin/?return_uri=<?php echo admin_url('admin.php?page=sb-instagram-feed'); ?>&response_type=token&state=<?php echo admin_url('admin.php?page-sb-instagram-feed'); ?>&hl=en"
418
+ href="https://instagram.com/oauth/authorize/?client_id=3a81a9fa2a064751b8c31385b91cc25c&scope=basic&redirect_uri=https://smashballoon.com/instagram-feed/instagram-token-plugin/?return_uri=<?php echo admin_url('admin.php?page=sb-instagram-feed'); ?>&response_type=token&state=<?php echo admin_url('admin.php?page-sb-instagram-feed'); ?>&hl=en" class="sbi_admin_btn"><i class="fa fa-user-plus" aria-hidden="true" style="font-size: 20px;"></i>&nbsp; <?php _e('Connect an Instagram Account', 'instagram-feed' ); ?></a>
419
+
420
+ <!--<a href="https://instagram.com/oauth/authorize/?client_id=3a81a9fa2a064751b8c31385b91cc25c&scope=basic+public_content&redirect_uri=https://smashballoon.com/instagram-feed/instagram-token-plugin/?return_uri=<?php echo admin_url('admin.php?page=sb-instagram-feed'); ?>&response_type=token&state=<?php echo admin_url('admin.php?page-sb-instagram-feed'); ?>" class="sbi_admin_btn"><i class="fa fa-user-plus" aria-hidden="true" style="font-size: 20px;"></i>&nbsp; <?php _e('Connect an Instagram Account', 'instagram-feed' ); ?></a>
421
+ -->
422
+ <a href="https://smashballoon.com/instagram-feed/token/" target="_blank" style="position: relative; top: 14px; left: 15px;"><?php _e('Button not working?', 'instagram-feed'); ?></a>
423
+ </div>
424
+
425
+ <!-- Old Access Token -->
426
+ <input name="sb_instagram_at" id="sb_instagram_at" type="hidden" value="<?php echo esc_attr( $sb_instagram_at ); ?>" size="80" maxlength="100" placeholder="Click button above to get your Access Token" />
427
+ <?php
428
+
429
+ $returned_data = sbi_get_connected_accounts_data( $sb_instagram_at );
430
+ $connected_accounts = $returned_data['connected_accounts'];
431
+ $user_feeds_returned = isset( $returned_data['user_ids'] ) ? $returned_data['user_ids'] : false;
432
+ if ( $user_feeds_returned ) {
433
+ $user_feed_ids = $user_feeds_returned;
434
+ } else {
435
+ $user_feed_ids = ! is_array( $sb_instagram_user_id ) ? explode( ',', $sb_instagram_user_id ) : $sb_instagram_user_id;
436
+ }
437
+ $expired_tokens = get_option( 'sb_expired_tokens', array() );
438
+ ?>
439
+
440
+ <tr valign="top">
441
+ <th scope="row"><label><?php _e( 'Instagram Accounts', 'instagram-feed' ); ?></label><span style="font-weight:normal; font-style:italic; font-size: 12px; display: block;"><?php _e('Use the button above to connect an Instagram account', 'instagram-feed'); ?></span></th>
442
+ <td class="sbi_connected_accounts_wrap">
443
+ <?php if ( empty( $connected_accounts ) ) : ?>
444
+ <p class="sbi_no_accounts"><?php _e( 'No Instagram accounts connected. Click the button above to connect an account.', 'instagram-feed' ); ?></p><br />
445
+ <?php else: ?>
446
+ <?php foreach ( $connected_accounts as $account ) :
447
+ $username = $account['username'] ? $account['username'] : $account['user_id'];
448
+ if ( isset( $account['local_avatar'] ) && $account['local_avatar'] && isset( $options['sb_instagram_favor_local'] ) && $options['sb_instagram_favor_local' ] === 'on' ) {
449
+ $upload = wp_upload_dir();
450
+ $resized_url = trailingslashit( $upload['baseurl'] ) . trailingslashit( SBI_UPLOADS_NAME );
451
+ $profile_picture = '<img class="sbi_ca_avatar" src="'.$resized_url . $account['username'].'.jpg" />'; //Could add placeholder avatar image
452
+ } else {
453
+ $profile_picture = $account['profile_picture'] ? '<img class="sbi_ca_avatar" src="'.$account['profile_picture'].'" />' : ''; //Could add placeholder avatar image
454
+ }
455
+ $access_token_expired = (in_array( $account['access_token'], $expired_tokens, true ) || in_array( sbi_maybe_clean( $account['access_token'] ), $expired_tokens, true ));
456
+ $is_invalid_class = ! $account['is_valid'] || $access_token_expired ? ' sbi_account_invalid' : '';
457
+ $in_user_feed = in_array( $account['user_id'], $user_feed_ids, true );
458
+ $account_type = isset( $account['type'] ) ? $account['type'] : 'personal';
459
+
460
+ ?>
461
+ <div class="sbi_connected_account<?php echo $is_invalid_class; ?><?php if ( $in_user_feed ) echo ' sbi_account_active' ?> sbi_account_type_<?php echo $account_type; ?>" id="sbi_connected_account_<?php echo esc_attr( $account['user_id'] ); ?>" data-accesstoken="<?php echo esc_attr( $account['access_token'] ); ?>" data-userid="<?php echo esc_attr( $account['user_id'] ); ?>" data-username="<?php echo esc_attr( $account['username'] ); ?>" data-type="<?php echo esc_attr( $account_type ); ?>">
462
+
463
+ <div class="sbi_ca_alert">
464
+ <span><?php _e( 'The Access Token for this account is expired or invalid. Click the button above to attempt to renew it.', 'instagram-feed' ) ?></span>
465
+ </div>
466
+ <div class="sbi_ca_info">
467
+
468
+ <div class="sbi_ca_delete">
469
+ <a href="JavaScript:void(0);" class="sbi_delete_account"><i class="fa fa-times"></i><span class="sbi_remove_text"><?php _e( 'Remove', 'instagram-feed' ); ?></span></a>
470
+ </div>
471
+
472
+ <div class="sbi_ca_username">
473
+ <?php echo $profile_picture; ?>
474
+ <strong><?php echo $username; ?><span><?php echo $account_type; ?></span></strong>
475
+ </div>
476
+
477
+ <div class="sbi_ca_actions">
478
+ <?php if ( ! $in_user_feed ) : ?>
479
+ <a href="JavaScript:void(0);" class="sbi_use_in_user_feed button-primary"><i class="fa fa-plus-circle" aria-hidden="true"></i><?php _e( 'Add to Primary Feed', 'instagram-feed' ); ?></a>
480
+ <?php else : ?>
481
+ <a href="JavaScript:void(0);" class="sbi_remove_from_user_feed button-primary"><i class="fa fa-minus-circle" aria-hidden="true"></i><?php _e( 'Remove from Primary Feed', 'instagram-feed' ); ?></a>
482
+ <?php endif; ?>
483
+ <a class="sbi_ca_token_shortcode button-secondary" href="JavaScript:void(0);"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i><?php _e( 'Add to another Feed', 'instagram-feed' ); ?></a>
484
+ <p class="sbi_ca_show_token"><input type="checkbox" id="sbi_ca_show_token_<?php echo esc_attr( $account['user_id'] ); ?>" /><label for="sbi_ca_show_token_<?php echo esc_attr( $account['user_id'] ); ?>"><?php _e('Show Access Token', 'instagram-feed'); ?></label></p>
485
+
486
+ </div>
487
+
488
+ <div class="sbi_ca_shortcode">
489
+
490
+ <p><?php _e('Copy and paste this shortcode into your page or widget area', 'instagram-feed'); ?>:<br>
491
+ <?php if ( !empty( $account['username'] ) ) : ?>
492
+ <code>[instagram-feed user="<?php echo esc_html( $account['username'] ); ?>"]</code>
493
+ <?php else : ?>
494
+ <code>[instagram-feed accesstoken="<?php echo $account['access_token']; ?>"]</code>
495
+ <?php endif; ?>
496
+ </p>
497
+
498
+ <p><?php _e('To add multiple users in the same feed, simply separate them using commas', 'instagram-feed'); ?>:<br>
499
+ <?php if ( !empty( $account['username'] ) ) : ?>
500
+ <code>[instagram-feed user="<?php echo esc_html( $account['username'] ); ?>, a_second_user, a_third_user"]</code>
501
+ <?php else : ?>
502
+ <code>[instagram-feed accesstoken="<?php echo $account['access_token']; ?>, another_access_token"]</code>
503
+ <?php endif; ?>
504
+
505
+ <p><?php echo sprintf( __('Click on the %s tab to learn more about shortcodes', 'instagram-feed'), '<a href="?page=sb-instagram-feed&tab=display" target="_blank">'. __( 'Display Your Feed', 'instagram-feed' ) . '</a>' ); ?></p>
506
+ </div>
507
+
508
+ <div class="sbi_ca_accesstoken">
509
+ <span class="sbi_ca_token_label"><?php _e('Access Token', 'instagram-feed');?>:</span><input type="text" class="sbi_ca_token" value="<?php echo $account['access_token']; ?>" readonly="readonly" onclick="this.focus();this.select()" title="<?php _e('To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac).', 'instagram-feed');?>">
510
+ </div>
511
+
512
+ </div>
513
+
514
+ </div>
515
+
516
+ <?php endforeach; ?>
517
+ <?php endif; ?>
518
+ <a href="JavaScript:void(0);" class="sbi_manually_connect button-secondary"><?php _e( 'Manually Connect an Account', 'instagram-feed' ); ?></a>
519
+ <div class="sbi_manually_connect_wrap">
520
+ <input name="sb_manual_at" id="sb_manual_at" type="text" value="" style="margin-top: 4px; padding: 5px 9px; margin-left: 0px;" size="64" minlength="15" maxlength="200" placeholder="Enter a valid Instagram Access Token" /><span class='sbi_business_profile_tag'><?php _e('Business Profile', 'instagram-feed');?></span>
521
+ <div class="sbi_manual_account_id_toggle">
522
+ <label><?php _e('Please enter the User ID for this Business Profile:', 'instagram-feed');?></label>
523
+ <input name="sb_manual_account_id" id="sb_manual_account_id" type="text" value="" style="margin-top: 4px; padding: 5px 9px; margin-left: 0px;" size="40" minlength="5" maxlength="100" placeholder="Eg: 15641403491391489" />
524
+ </div>
525
+ <p class="sbi_submit" style="display: inline-block;"><input type="sbi_submit" name="submit" id="sbi_manual_submit" class="button button-primary" style="text-align: center; padding: 0;" value="<?php _e('Connect This Account', 'instagram-feed' );?>"></p>
526
+ </div>
527
+ </td>
528
+ </tr>
529
+
530
+
531
+ <?php if( isset($_GET['access_token']) && isset($_GET['graph_api']) && empty($_POST) ) { ?>
532
+ <?php
533
+ $access_token = sbi_maybe_clean(urldecode(sanitize_text_field($_GET['access_token'])));
534
+ $url = 'https://graph.facebook.com/me/accounts?fields=instagram_business_account,access_token&limit=500&access_token='.$access_token;
535
+ $args = array(
536
+ 'timeout' => 60,
537
+ 'sslverify' => false
538
+ );
539
+ $result = wp_remote_get( $url, $args );
540
+ $pages_data = '{}';
541
+ if ( ! is_wp_error( $result ) ) {
542
+ $pages_data = $result['body'];
543
+ } else {
544
+ $page_error = $result;
545
+ }
546
+
547
+ $pages_data_arr = json_decode($pages_data);
548
+ $num_accounts = 0;
549
+ if(isset($pages_data_arr)){
550
+ $num_accounts = is_array( $pages_data_arr->data ) ? count( $pages_data_arr->data ) : 0;
551
+ }
552
+ ?>
553
+ <div id="sbi_config_info" class="sb_list_businesses sbi_num_businesses_<?php echo $num_accounts; ?>">
554
+ <div class="sbi_config_modal">
555
+ <div class="sbi-managed-pages">
556
+ <?php if ( isset( $page_error ) && isset( $page_error->errors ) ) {
557
+ foreach ($page_error->errors as $key => $item) {
558
+ echo '<div class="sbi_user_id_error" style="display:block;"><strong>Connection Error: </strong>' . $key . ': ' . $item[0] . '</div>';
559
+ }
560
+ }
561
+ ?>
562
+ <?php if( empty($pages_data_arr->data) ) : ?>
563
+ <span id="sbi-bus-account-error">
564
+ <p style="margin-top: 5px;"><b style="font-size: 16px">Couldn't find Business Profile</b><br />
565
+ Uh oh. It looks like this Facebook account is not currently connected to an Instagram Business profile. Please check that you are logged into the <a href="https://www.facebook.com/" target="_blank">Facebook account</a> in this browser which is associated with your Instagram Business Profile.</p>
566
+ <p><b style="font-size: 16px">Why do I need a Business Profile?</b><br />
567
+ A Business Profile is not required. If you want to display a regular User feed then you can do this by selecting to connect a Personal account instead. For directions on how to convert your Personal profile into a Business profile please <a href="https://smashballoon.com/instagram-business-profiles" target="_blank">see here</a>.</p>
568
+ </span>
569
+
570
+ <?php elseif ( $num_accounts === 0 ): ?>
571
+ <span id="sbi-bus-account-error">
572
+ <p style="margin-top: 5px;"><b style="font-size: 16px">Couldn't find Business Profile</b><br />
573
+ Uh oh. It looks like this Facebook account is not currently connected to an Instagram Business profile. Please check that you are logged into the <a href="https://www.facebook.com/" target="_blank">Facebook account</a> in this browser which is associated with your Instagram Business Profile.</p>
574
+ <p>If you are, in fact, logged-in to the correct account please make sure you have Instagram accounts connected with your Facebook account by following <a href="https://smashballoon.com/reconnecting-an-instagram-business-profile/" target="_blank">this FAQ</a></p>
575
+ </span>
576
+ <?php else: ?>
577
+ <p class="sbi-managed-page-intro"><b style="font-size: 16px;">Instagram Business profiles for this account</b></p>
578
+ <?php if ( $num_accounts > 1 ) : ?>
579
+ <div class="sbi-managed-page-select-all"><input type="checkbox" id="sbi-select-all" class="sbi-select-all"><label for="sbi-select-all">Select All</label></div>
580
+ <?php endif; ?>
581
+ <div class="sbi-scrollable-accounts">
582
+
583
+ <?php foreach ( $pages_data_arr->data as $page => $page_data ) : ?>
584
+
585
+ <?php if( isset( $page_data->instagram_business_account ) ) :
586
+
587
+ $instagram_business_id = $page_data->instagram_business_account->id;
588
+
589
+ $page_access_token = isset( $page_data->access_token ) ? $page_data->access_token : '';
590
+
591
+ //Make another request to get page info
592
+ $instagram_account_url = 'https://graph.facebook.com/'.$instagram_business_id.'?fields=name,username,profile_picture_url&access_token='.$access_token;
593
+
594
+ $args = array(
595
+ 'timeout' => 60,
596
+ 'sslverify' => false
597
+ );
598
+ $result = wp_remote_get( $instagram_account_url, $args );
599
+ $instagram_account_info = '{}';
600
+ if ( ! is_wp_error( $result ) ) {
601
+ $instagram_account_info = $result['body'];
602
+ } else {
603
+ $page_error = $result;
604
+ }
605
+
606
+ $instagram_account_data = json_decode($instagram_account_info);
607
+
608
+ $instagram_biz_img = isset( $instagram_account_data->profile_picture_url ) ? $instagram_account_data->profile_picture_url : false;
609
+ $selected_class = $instagram_business_id == $sb_instagram_user_id ? ' sbi-page-selected' : '';
610
+
611
+ ?>
612
+ <?php if ( isset( $page_error ) && isset( $page_error->errors ) ) :
613
+ foreach ($page_error->errors as $key => $item) {
614
+ echo '<div class="sbi_user_id_error" style="display:block;"><strong>Connection Error: </strong>' . $key . ': ' . $item[0] . '</div>';
615
+ }
616
+ else : ?>
617
+ <div class="sbi-managed-page<?php echo $selected_class; ?>" data-page-token="<?php echo esc_attr( $page_access_token ); ?>" data-token="<?php echo esc_attr( $access_token ); ?>" data-page-id="<?php echo esc_attr( $instagram_business_id ); ?>">
618
+ <div class="sbi-add-checkbox">
619
+ <input id="sbi-<?php echo esc_attr( $instagram_business_id ); ?>" type="checkbox" name="sbi_managed_pages[]" value="<?php echo esc_attr( $instagram_account_info ); ?>">
620
+ </div>
621
+ <div class="sbi-managed-page-details">
622
+ <label for="sbi-<?php echo esc_attr( $instagram_business_id ); ?>"><img class="sbi-page-avatar" border="0" height="50" width="50" src="<?php echo esc_url( $instagram_biz_img ); ?>"><b style="font-size: 16px;"><?php echo esc_html( $instagram_account_data->name ); ?></b>
623
+ <br />@<?php echo esc_html( $instagram_account_data->username); ?><span style="font-size: 11px; margin-left: 5px;">(<?php echo esc_html( $instagram_business_id ); ?>)</span></label>
624
+ </div>
625
+ </div>
626
+ <?php endif; ?>
627
+
628
+ <?php endif; ?>
629
+
630
+ <?php endforeach; ?>
631
+
632
+ </div> <!-- end scrollable -->
633
+ <a href="JavaScript:void(0);" id="sbi-connect-business-accounts" class="button button-primary" disabled="disabled" style="margin-top: 20px;">Connect Accounts</a>
634
+
635
+ <?php endif; ?>
636
+
637
+ <a href="JavaScript:void(0);" class="sbi_modal_close"><i class="fa fa-times"></i></a>
638
+ </div>
639
+ </div>
640
+ </div>
641
+ <?php } ?>
642
+
643
+ <?php //Display connected page
644
+ if (isset( $sbi_connected_page ) && strpos($sbi_connected_page, ':') !== false) {
645
+
646
+ $sbi_connected_page_pieces = explode(":", $sbi_connected_page);
647
+ $sbi_connected_page_id = $sbi_connected_page_pieces[0];
648
+ $sbi_connected_page_name = $sbi_connected_page_pieces[1];
649
+ $sbi_connected_page_image = $sbi_connected_page_pieces[2];
650
+
651
+ echo '&nbsp;';
652
+ echo '<p style="font-weight: bold; margin-bottom: 5px;">Connected Business Profile:</p>';
653
+ echo '<div class="sbi-managed-page sbi-no-select">';
654
+ echo '<p><img class="sbi-page-avatar" border="0" height="50" width="50" src="'.$sbi_connected_page_image.'"><b>'.$sbi_connected_page_name.'</b> &nbsp; ('.$sbi_connected_page_id.')</p>';
655
+ echo '</div>';
656
+ }
657
+
658
+ $sb_instagram_type = 'user';
659
+ ?>
660
+
661
+ <tr valign="top" class="sbi_feed_type">
662
+ <th scope="row"><label><?php _e('Show Photos From:', 'instagram-feed'); ?></label><code class="sbi_shortcode"> type
663
+ Eg: type=user id=12986477
664
+ </code></th>
665
+ <td>
666
+ <div class="sbi_row">
667
+ <div class="sbi_col sbi_one">
668
+ <input type="radio" name="sb_instagram_type" id="sb_instagram_type_user" value="user" <?php if($sb_instagram_type == "user") echo "checked"; ?> />
669
+ <label class="sbi_radio_label" for="sb_instagram_type_user"><?php _e( 'User Account:', 'instagram-feed' ); ?></label>
670
+ </div>
671
+ <div class="sbi_col sbi_two">
672
+ <div class="sbi_user_feed_ids_wrap">
673
+ <?php foreach ( $user_feed_ids as $feed_id ) : if ( $feed_id !== '' ) :?>
674
+ <?php if( count($connected_accounts) > 0 ) { ?><div id="sbi_user_feed_id_<?php echo $feed_id; ?>" class="sbi_user_feed_account_wrap"><?php } ?>
675
+
676
+ <?php if ( isset( $connected_accounts[ $feed_id ] ) && ! empty( $connected_accounts[ $feed_id ]['username'] ) ) : ?>
677
+ <strong><?php echo $connected_accounts[ $feed_id ]['username']; ?></strong> <span>(<?php echo $feed_id; ?>)</span>
678
+ <input name="sb_instagram_user_id[]" id="sb_instagram_user_id" type="hidden" value="<?php echo esc_attr( $feed_id ); ?>" />
679
+ <?php elseif ( isset( $connected_accounts[ $feed_id ] ) && ! empty( $connected_accounts[ $feed_id ]['access_token'] ) ) : ?>
680
+ <strong><?php echo $feed_id; ?></strong>
681
+ <input name="sb_instagram_user_id[]" id="sb_instagram_user_id" type="hidden" value="<?php echo esc_attr( $feed_id ); ?>" />
682
+ <?php endif; ?>
683
+
684
+ <?php if( count($connected_accounts) > 0 ) { ?></div><?php } ?>
685
+ <?php endif; endforeach; ?>
686
+ </div>
687
+
688
+ <?php if ( empty( $user_feed_ids ) ) : ?>
689
+ <p class="sbi_no_accounts" style="margin-top: -3px; margin-right: 10px;"><?php _e( 'Connect a user account above', 'instagram-feed' ); ?></p>
690
+ <?php endif; ?>
691
+
692
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);" style="margin: 5px 0 10px 0; display: inline-block; height: 19px;"><?php _e("How to display User feeds", 'instagram-feed' ); ?></a>
693
+ <div class="sbi_tooltip"><?php _e("<p><b>Displaying Posts from Your User Account</b><br />Simply connect an account using the button above.</p><p style='padding-top:8px;'><b>Displaying Posts from Other Instagram Accounts</b><br />Due to recent changes in the Instagram API it is no longer possible to display photos from other Instagram accounts which you do not have access to. You can only display the user feed of an account which you connect above. You can connect as many account as you like by logging in using the button above, or manually copy/pasting an Access Token by selecting the 'Manually Connect an Account' option.</p><p style='padding-top:10px;'><b>Multiple Acounts</b><br />It is only possible to display feeds from Instagram accounts which you own. In order to display feeds from multiple accounts, first connect them above and then use the buttons to add the account either to your primary feed or to another feed on your site.</p>", 'instagram-feed'); ?></div><br />
694
+ </div>
695
+
696
+ </div>
697
+
698
+ <div class="sbi_pro sbi_row">
699
+ <div class="sbi_col sbi_one">
700
+ <input disabled type="radio" name="sb_instagram_type" id="sb_instagram_type_hashtag" value="hashtag" <?php if($sb_instagram_type == "hashtag") echo "checked"; ?> />
701
+ <label class="sbi_radio_label" for="sb_instagram_type_hashtag"><?php _e( 'Hashtag:', 'instagram-feed' ); ?></label>
702
+ </div>
703
+ <div class="sbi_col sbi_two">
704
+
705
+ <p class="sbi_pro_tooltip"><?php _e( 'Upgrade to the Pro version to display hashtag feeds', 'instagram-feed' ); ?><i class="fa fa-caret-down" aria-hidden="true"></i></p>
706
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank" class="sbi_lock"><i class="fa fa-rocket"></i><?php _e('Pro', 'instagram-feed'); ?></a>
707
+
708
+ <input readonly type="text" size="25" style="height: 32px; top: -2px; position: relative; box-shadow: none;" />
709
+ &nbsp;<a class="sbi_tooltip_link sbi_pro" href="JavaScript:void(0);"><?php _e( 'What is this?', 'instagram-feed' ); ?></a>
710
+
711
+ <p class="sbi_tooltip"><?php _e( 'Display posts from a specific hashtag instead of from a user', 'instagram-feed' ); ?></p>
712
+ </div>
713
+ </div>
714
+
715
+ <div class="sbi_row sbi_pro">
716
+ <br>
717
+ <a class="sbi_tooltip_link sbi_pro" href="JavaScript:void(0);" style="margin-left: 0;"><i class="fa fa-question-circle" aria-hidden="true" style="margin-right: 6px;"></i><?php _e('Combine multiple feed types into a single feed', 'instagram-feed'); ?></a>
718
+ <p class="sbi_tooltip">
719
+ <b><?php _e( 'Please note: this is only available in the <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">Pro version</a>', 'instagram-feed' ); ?>.</b><br />
720
+ <?php echo sprintf( __('To display multiple feed types in a single feed, use %s in your shortcode and then add each user name or hashtag of each feed into the shortcode, like so: %s. This will combine a user feed and a hashtag feed into the same feed.', 'instagram-feed'), 'type="mixed"', '<code>[instagram-feed type="mixed" user="smashballoon" hashtag="#awesomeplugins"]</code>' ); ?>
721
+ </p>
722
+ </div>
723
+
724
+ </td>
725
+ </tr>
726
+
727
+ <tr>
728
+ <th class="bump-left"><label for="sb_instagram_preserve_settings" class="bump-left"><?php _e("Preserve settings when plugin is removed", 'instagram-feed'); ?></label></th>
729
+ <td>
730
+ <input name="sb_instagram_preserve_settings" type="checkbox" id="sb_instagram_preserve_settings" <?php if($sb_instagram_preserve_settings == true) echo "checked"; ?> />
731
+ <label for="sb_instagram_preserve_settings"><?php _e('Yes', 'instagram-feed'); ?></label>
732
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
733
+ <p class="sbi_tooltip"><?php _e('When removing the plugin your settings are automatically erased. Checking this box will prevent any settings from being deleted. This means that you can uninstall and reinstall the plugin without losing your settings.', 'instagram-feed'); ?></p>
734
+ </td>
735
+ </tr>
736
+
737
+
738
+ <tr valign="top" class="sbi_cron_cache_opts">
739
+ <th scope="row"><?php _e( 'Check for new posts', 'instagram-feed' ); ?></th>
740
+ <td>
741
+
742
+ <div class="sbi_row">
743
+ <input type="radio" name="sbi_caching_type" id="sbi_caching_type_page" value="page" <?php if ( $sbi_caching_type === 'page' ) echo 'checked'; ?>>
744
+ <label for="sbi_caching_type_page"><?php _e( 'When the page loads', 'instagram-feed' ); ?></label>
745
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);" style="position: relative; top: 2px;"><i class="fa fa-question-circle" aria-hidden="true"></i></a>
746
+ <p class="sbi_tooltip sbi-more-info"><?php _e( 'Your Instagram post data is temporarily cached by the plugin in your WordPress database. There are two ways that you can set the plugin to check for new data', 'instagram-feed' ); ?>:<br><br>
747
+ <?php _e( '<b>1. When the page loads</b><br>Selecting this option means that when the cache expires then the plugin will check Facebook for new posts the next time that the feed is loaded. You can choose how long this data should be cached for. If you set the time to 60 minutes then the plugin will clear the cached data after that length of time, and the next time the page is viewed it will check for new data. <b>Tip:</b> If you\'re experiencing an issue with the plugin not updating automatically then try enabling the setting labeled <b>\'Force cache to clear on interval\'</b> which is located on the \'Customize\' tab.', 'instagram-feed' ); ?>
748
+ <br><br>
749
+ <?php _e( '<b>2. In the background</b><br>Selecting this option means that the plugin will check for new data in the background so that the feed is updated behind the scenes. You can select at what time and how often the plugin should check for new data using the settings below. <b>Please note</b> that the plugin will initially check for data from Instagram when the page first loads, but then after that will check in the background on the schedule selected - unless the cache is cleared.</p>', 'instagram-feed' ); ?>
750
+ </div>
751
+ <div class="sbi_row sbi-caching-page-options" style="display: none;">
752
+ <?php _e( 'Every', 'instagram-feed' ); ?>:
753
+ <input name="sb_instagram_cache_time" type="text" value="<?php echo esc_attr( $sb_instagram_cache_time ); ?>" size="4" />
754
+ <select name="sb_instagram_cache_time_unit">
755
+ <option value="minutes" <?php if($sb_instagram_cache_time_unit == "minutes") echo 'selected="selected"' ?> ><?php _e('Minutes', 'instagram-feed'); ?></option>
756
+ <option value="hours" <?php if($sb_instagram_cache_time_unit == "hours") echo 'selected="selected"' ?> ><?php _e('Hours', 'instagram-feed'); ?></option>
757
+ <option value="days" <?php if($sb_instagram_cache_time_unit == "days") echo 'selected="selected"' ?> ><?php _e('Days', 'instagram-feed'); ?></option>
758
+ </select>
759
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
760
+ <p class="sbi_tooltip"><?php _e('Your Instagram posts are temporarily cached by the plugin in your WordPress database. You can choose how long the posts should be cached for. If you set the time to 1 hour then the plugin will clear the cache after that length of time and check Instagram for posts again.', 'instagram-feed'); ?></p>
761
+ </div>
762
+
763
+ <div class="sbi_row">
764
+ <input type="radio" name="sbi_caching_type" id="sbi_caching_type_cron" value="background" <?php if ( $sbi_caching_type === 'background' ) echo 'checked'; ?>>
765
+ <label for="sbi_caching_type_cron"><?php _e( 'In the background', 'instagram-feed' ); ?></label>
766
+ </div>
767
+ <div class="sbi_row sbi-caching-cron-options" style="display: block;">
768
+
769
+ <select name="sbi_cache_cron_interval" id="sbi_cache_cron_interval">
770
+ <option value="30mins" <?php if ( $sbi_cache_cron_interval === '30mins' ) echo 'selected'; ?>><?php _e( 'Every 30 minutes', 'instagram-feed' ); ?></option>
771
+ <option value="1hour" <?php if ( $sbi_cache_cron_interval === '1hour' ) echo 'selected'; ?>><?php _e( 'Every hour', 'instagram-feed' ); ?></option>
772
+ <option value="12hours" <?php if ( $sbi_cache_cron_interval === '12hours' ) echo 'selected'; ?>><?php _e( 'Every 12 hours', 'instagram-feed' ); ?></option>
773
+ <option value="24hours" <?php if ( $sbi_cache_cron_interval === '24hours' ) echo 'selected'; ?>><?php _e( 'Every 24 hours', 'instagram-feed' ); ?></option>
774
+ </select>
775
+
776
+ <div id="sbi-caching-time-settings" style="display: none;">
777
+ <?php _e('at' ); ?>
778
+
779
+ <select name="sbi_cache_cron_time" style="width: 80px">
780
+ <option value="1" <?php if ( $sbi_cache_cron_time === '1' ) echo 'selected'; ?>>1:00</option>
781
+ <option value="2" <?php if ( $sbi_cache_cron_time === '2' ) echo 'selected'; ?>>2:00</option>
782
+ <option value="3" <?php if ( $sbi_cache_cron_time === '3' ) echo 'selected'; ?>>3:00</option>
783
+ <option value="4" <?php if ( $sbi_cache_cron_time === '4' ) echo 'selected'; ?>>4:00</option>
784
+ <option value="5" <?php if ( $sbi_cache_cron_time === '5' ) echo 'selected'; ?>>5:00</option>
785
+ <option value="6" <?php if ( $sbi_cache_cron_time === '6' ) echo 'selected'; ?>>6:00</option>
786
+ <option value="7" <?php if ( $sbi_cache_cron_time === '7' ) echo 'selected'; ?>>7:00</option>
787
+ <option value="8" <?php if ( $sbi_cache_cron_time === '8' ) echo 'selected'; ?>>8:00</option>
788
+ <option value="9" <?php if ( $sbi_cache_cron_time === '9' ) echo 'selected'; ?>>9:00</option>
789
+ <option value="10" <?php if ( $sbi_cache_cron_time === '10' ) echo 'selected'; ?>>10:00</option>
790
+ <option value="11" <?php if ( $sbi_cache_cron_time === '11' ) echo 'selected'; ?>>11:00</option>
791
+ <option value="0" <?php if ( $sbi_cache_cron_time === '0' ) echo 'selected'; ?>>12:00</option>
792
+ </select>
793
+
794
+ <select name="sbi_cache_cron_am_pm" style="width: 50px">
795
+ <option value="am" <?php if ( $sbi_cache_cron_am_pm === 'am' ) echo 'selected'; ?>>AM</option>
796
+ <option value="pm" <?php if ( $sbi_cache_cron_am_pm === 'pm' ) echo 'selected'; ?>>PM</option>
797
+ </select>
798
+ </div>
799
+
800
+ <?php
801
+ if ( wp_next_scheduled( 'sbi_feed_update' ) ) {
802
+ $time_format = get_option( 'time_format' );
803
+ if ( ! $time_format ) {
804
+ $time_format = 'g:i a';
805
+ }
806
+ //
807
+ $schedule = wp_get_schedule( 'sbi_feed_update' );
808
+ if ( $schedule == '30mins' ) $schedule = __( 'every 30 minutes', 'instagram-feed' );
809
+ if ( $schedule == 'twicedaily' ) $schedule = __( 'every 12 hours', 'instagram-feed' );
810
+ $sbi_next_cron_event = wp_next_scheduled( 'sbi_feed_update' );
811
+ echo '<p class="sbi-caching-sched-notice"><span><b>' . __( 'Next check', 'instagram-feed' ) . ': ' . date( $time_format, $sbi_next_cron_event + sbi_get_utc_offset() ) . ' (' . $schedule . ')</b> - ' . __( 'Note: Saving the settings on this page will clear the cache and reset this schedule', 'instagram-feed' ) . '</span></p>';
812
+ } else {
813
+ echo '<p style="font-size: 11px; color: #666;">' . __( 'Nothing currently scheduled', 'instagram-feed' ) . '</p>';
814
+ }
815
+ ?>
816
+
817
+ </div>
818
+
819
+ </td>
820
+ </tr>
821
+
822
+ </tbody>
823
+ </table>
824
+
825
+ <?php submit_button(); ?>
826
+ </form>
827
+
828
+ <p><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>&nbsp; <?php _e('Next Step: <a href="?page=sb-instagram-feed&tab=customize">Customize your Feed</a>', 'instagram-feed'); ?></p>
829
+
830
+ <p><i class="fa fa-life-ring" aria-hidden="true"></i>&nbsp; <?php _e('Need help setting up the plugin? Check out our <a href="https://smashballoon.com/instagram-feed/free/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">setup directions</a>', 'instagram-feed'); ?></p>
831
+
832
+
833
+ <?php } // End Configure tab ?>
834
+
835
+
836
+
837
+ <?php if( $sbi_active_tab == 'customize' ) { //Start Configure tab ?>
838
+
839
+ <p class="sb_instagram_contents_links" id="general">
840
+ <span><?php _e( 'Quick links:', 'instagram-feed' ); ?> </span>
841
+ <a href="#general"><?php _e( 'General', 'instagram-feed' ); ?></a>
842
+ <a href="#layout"><?php _e( 'Layout', 'instagram-feed' ); ?></a>
843
+ <a href="#photos"><?php _e( 'Photos', 'instagram-feed' ); ?></a>
844
+ <a href="#headeroptions"><?php _e( 'Header', 'instagram-feed' ); ?></a>
845
+ <a href="#loadmore"><?php _e( "'Load More' Button", 'instagram-feed' ); ?></a>
846
+ <a href="#follow"><?php _e( "'Follow' Button", 'instagram-feed' ); ?></a>
847
+ <a href="#customcss"><?php _e( 'Custom CSS', 'instagram-feed' ); ?></a>
848
+ <a href="#customjs"><?php _e( 'Custom JavaScript', 'instagram-feed' ); ?></a>
849
+ </p>
850
+
851
+ <input type="hidden" name="<?php echo $sb_instagram_customize_hidden_field; ?>" value="Y">
852
+
853
+ <h3><?php _e( 'General', 'instagram-feed' ); ?></h3>
854
+
855
+ <table class="form-table">
856
+ <tbody>
857
+ <tr valign="top">
858
+ <th scope="row"><label><?php _e('Width of Feed', 'instagram-feed'); ?></label><code class="sbi_shortcode"> width widthunit
859
+ Eg: width=50 widthunit=%</code></th>
860
+ <td>
861
+ <input name="sb_instagram_width" type="text" value="<?php echo esc_attr( $sb_instagram_width ); ?>" id="sb_instagram_width" size="4" maxlength="4" />
862
+ <select name="sb_instagram_width_unit" id="sb_instagram_width_unit">
863
+ <option value="px" <?php if($sb_instagram_width_unit == "px") echo 'selected="selected"' ?> ><?php _e('px', 'instagram-feed'); ?></option>
864
+ <option value="%" <?php if($sb_instagram_width_unit == "%") echo 'selected="selected"' ?> ><?php _e('%', 'instagram-feed'); ?></option>
865
+ </select>
866
+ <div id="sb_instagram_width_options">
867
+ <input name="sb_instagram_feed_width_resp" type="checkbox" id="sb_instagram_feed_width_resp" <?php if($sb_instagram_feed_width_resp == true) echo "checked"; ?> /><label for="sb_instagram_feed_width_resp"><?php _e('Set to be 100% width on mobile?', 'instagram-feed'); ?></label>
868
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e( 'What does this mean?', 'instagram-feed' ); ?></a>
869
+ <p class="sbi_tooltip"><?php _e("If you set a width on the feed then this will be used on mobile as well as desktop. Check this setting to set the feed width to be 100% on mobile so that it is responsive.", 'instagram-feed'); ?></p>
870
+ </div>
871
+ </td>
872
+ </tr>
873
+ <tr valign="top">
874
+ <th scope="row"><label><?php _e('Height of Feed', 'instagram-feed'); ?></label><code class="sbi_shortcode"> height heightunit
875
+ Eg: height=500 heightunit=px</code></th>
876
+ <td>
877
+ <input name="sb_instagram_height" type="text" value="<?php echo esc_attr( $sb_instagram_height ); ?>" size="4" maxlength="4" />
878
+ <select name="sb_instagram_height_unit">
879
+ <option value="px" <?php if($sb_instagram_height_unit == "px") echo 'selected="selected"' ?> ><?php _e('px', 'instagram-feed'); ?></option>
880
+ <option value="%" <?php if($sb_instagram_height_unit == "%") echo 'selected="selected"' ?> ><?php _e('%', 'instagram-feed'); ?></option>
881
+ </select>
882
+ </td>
883
+ </tr>
884
+ <tr valign="top">
885
+ <th scope="row"><label><?php _e('Background Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> background
886
+ Eg: background=d89531</code></th>
887
+ <td>
888
+ <input name="sb_instagram_background" type="text" value="<?php echo esc_attr( $sb_instagram_background ); ?>" class="sbi_colorpick" />
889
+ </td>
890
+ </tr>
891
+ </tbody>
892
+ </table>
893
+
894
+ <hr id="layout" />
895
+ <h3><?php _e('Layout', 'instagram-feed'); ?></h3>
896
+
897
+ <table class="form-table">
898
+ <tbody>
899
+ <?php
900
+ $selected_type = isset( $sb_instagram_layout_type ) ? $sb_instagram_layout_type : 'grid';
901
+ $layout_types = array(
902
+ 'grid' => __( 'Grid', 'instagram-feed' ),
903
+ 'carousel' => __( 'Carousel', 'instagram-feed' ),
904
+ 'masonry' => __( 'Masonry', 'instagram-feed' ),
905
+ 'highlight' => __( 'Highlight', 'instagram-feed' )
906
+ );
907
+ $layout_images = array(
908
+ 'grid' => SBI_PLUGIN_URL . 'img/grid.png',
909
+ 'carousel' => SBI_PLUGIN_URL . 'img/carousel.png',
910
+ 'masonry' => SBI_PLUGIN_URL . 'img/masonry.png',
911
+ 'highlight' => SBI_PLUGIN_URL . 'img/highlight.png'
912
+ );
913
+ ?>
914
+ <tr valign="top">
915
+ <th scope="row" class="sbi_pro"><label title="<?php _e('Click for shortcode option', 'instagram-feed'); ?>"><?php _e('Layout Type', 'instagram-feed'); ?></label><br /><span class="sbi_note" style="margin: 5px 0 0 0; font-weight: normal;"><?php _e('Select a layout to see associated<br />options', 'instagram-feed'); ?></span></th>
916
+ <td>
917
+ <div class="sbi_layouts">
918
+ <?php foreach( $layout_types as $layout_type => $label ) : ?>
919
+ <div class="sbi_layout_cell sbi_pro">
920
+ <input class="sb_layout_type" id="sb_layout_type_<?php echo esc_attr( $layout_type ); ?>" name="sb_instagram_layout_type" type="radio" value="<?php echo esc_attr( $layout_type ); ?>" <?php if ( $selected_type === $layout_type ) echo 'checked'; ?>/><label for="sb_layout_type_<?php echo esc_attr( $layout_type ); ?>"><span class="sbi_label"><?php echo esc_html( $label ); ?></span><img src="<?php echo esc_url( $layout_images[ $layout_type ] ); ?>" /></label>
921
+ </div>
922
+ <?php endforeach; ?>
923
+
924
+ <p class="sbi_pro_tooltip"><?php _e('Upgrade to the Pro version to unlock these layouts', 'instagram-feed'); ?><i class="fa fa-caret-down" aria-hidden="true"></i></p>
925
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank" class="sbi_lock"><i class="fa fa-rocket"></i><?php _e('Pro', 'instagram-feed'); ?></a>
926
+
927
+ </div>
928
+ <div class="sb_layout_options_wrap sbi_pro">
929
+ <a href="JavaScript:void(0);" class="sbi_close_options"><i class="fa fa-close"></i></a>
930
+ <div class="sb_instagram_layout_settings sbi_layout_type_grid">
931
+ <i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 8px;"></i><span class="sbi_note" style="margin-left: 0;"><?php _e('A uniform grid of square-cropped images.', 'instagram-feed'); ?></span>
932
+ </div>
933
+ <div class="sb_instagram_layout_settings sbi_layout_type_masonry">
934
+ <i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 8px;"></i><span class="sbi_note" style="margin-left: 0;"><?php _e('Images in their original aspect ratios with no vertical space between posts.', 'instagram-feed'); ?></span>
935
+ </div>
936
+ <div class="sb_instagram_layout_settings sbi_layout_type_carousel">
937
+ <div class="sb_instagram_layout_setting">
938
+ <i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 8px;"></i><span class="sbi_note" style="margin-left: 0;"><?php _e('Posts are displayed in a slideshow carousel.', 'instagram-feed'); ?></span>
939
+ </div>
940
+ <div class="sb_instagram_layout_setting">
941
+
942
+ <label><?php _e('Number of Rows', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouselrows
943
+ Eg: carouselrows=2</code>
944
+ <br>
945
+ <span class="sbi_note" style="margin: -5px 0 -10px 0; display: block;"><?php _e('Use the "Number of Columns" setting below this section to set how many posts are visible in the carousel at a given time.', 'instagram-feed'); ?></span>
946
+ <br>
947
+ <select name="sb_instagram_carousel_rows" id="sb_instagram_carousel_rows">
948
+ <option value="1">1</option>
949
+ <option value="2" selected="selected">2</option>
950
+ </select>
951
+ </div>
952
+ <div class="sb_instagram_layout_setting">
953
+ <label><?php _e('Loop Type', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouselloop
954
+ Eg: carouselloop=rewind
955
+ carouselloop=infinity</code>
956
+ <br>
957
+ <select name="sb_instagram_carousel_loop" id="sb_instagram_carousel_loop">
958
+ <option value="rewind"><?php _e('Rewind', 'instagram-feed'); ?></option>
959
+ <option value="infinity" selected="selected"><?php _e('Infinity', 'instagram-feed'); ?></option>
960
+ </select>
961
+ </div>
962
+ <div class="sb_instagram_layout_setting">
963
+ <input type="checkbox" name="sb_instagram_carousel_arrows" id="sb_instagram_carousel_arrows" checked="checked">
964
+ <label><?php _e('Show Navigation Arrows', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouselarrows
965
+ Eg: carouselarrows=true</code>
966
+ </div>
967
+ <div class="sb_instagram_layout_setting">
968
+ <input type="checkbox" name="sb_instagram_carousel_pag" id="sb_instagram_carousel_pag">
969
+ <label><?php _e('Show Pagination', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouselpag
970
+ Eg: carouselpag=true</code>
971
+ </div>
972
+ <div class="sb_instagram_layout_setting">
973
+ <input type="checkbox" name="sb_instagram_carousel_autoplay" id="sb_instagram_carousel_autoplay">
974
+ <label><?php _e('Enable Autoplay', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouselautoplay
975
+ Eg: carouselautoplay=true</code>
976
+ </div>
977
+ <div class="sb_instagram_layout_setting">
978
+ <label><?php _e('Interval Time', 'instagram-feed'); ?></label><code class="sbi_shortcode"> carouseltime
979
+ Eg: carouseltime=8000</code>
980
+ <br>
981
+ <input name="sb_instagram_carousel_interval" type="text" value="5000" size="6"><?php _e("miliseconds", 'instagram-feed'); ?>
982
+ </div>
983
+ </div>
984
+
985
+ <div class="sb_instagram_layout_settings sbi_layout_type_highlight">
986
+ <div class="sb_instagram_layout_setting">
987
+ <i class="fa fa-info-circle" aria-hidden="true" style="margin-right: 8px;"></i><span class="sbi_note" style="margin-left: 0;"><?php _e('Masonry style, square-cropped, image only (no captions or likes/comments below image). "Highlighted" posts are twice as large.', 'instagram-feed'); ?></span>
988
+ </div>
989
+ <div class="sb_instagram_layout_setting">
990
+ <label title="Click for shortcode option"><?php _e('Highlighting Type', 'instagram-feed'); ?></label><code class="sbi_shortcode"> highlighttype
991
+ Eg: highlighttype=pattern</code>
992
+ <br>
993
+ <select name="sb_instagram_highlight_type" id="sb_instagram_highlight_type">
994
+ <option value="pattern" selected="selected"><?php _e('Pattern', 'instagram-feed'); ?></option>
995
+ <option value="id"><?php _e('Post ID', 'instagram-feed'); ?></option>
996
+ <option value="hashtag"><?php _e('Hashtag', 'instagram-feed'); ?></option>
997
+ </select>
998
+ </div>
999
+ <div class="sb_instagram_highlight_sub_options sb_instagram_highlight_pattern sb_instagram_layout_setting" style="display: block;">
1000
+ <label></label><code class="sbi_shortcode"> highlightoffset
1001
+ Eg: highlightoffset=2</code>
1002
+ <br>
1003
+ <input name="sb_instagram_highlight_offset" type="number" min="0" value="0" style="width: 50px;">
1004
+ </div>
1005
+ <div class="sb_instagram_highlight_sub_options sb_instagram_highlight_pattern sb_instagram_layout_setting" style="display: block;">
1006
+ <label><?php _e('Pattern', 'instagram-feed'); ?></label><code class="sbi_shortcode"> highlightpattern
1007
+ Eg: highlightpattern=3</code>
1008
+ <br>
1009
+ <span><?php _e('Highlight every', 'instagram-feed'); ?></span><input name="sb_instagram_highlight_factor" type="number" min="2" value="6" style="width: 50px;"><span><?php _e('posts', 'instagram-feed'); ?></span>
1010
+ </div>
1011
+ <div class="sb_instagram_highlight_sub_options sb_instagram_highlight_hashtag sb_instagram_layout_setting" style="display: none;">
1012
+ <label><?php _e('Highlight Posts with these Hashtags', 'instagram-feed'); ?></label>
1013
+ <input name="sb_instagram_highlight_hashtag" id="sb_instagram_highlight_hashtag" type="text" size="40" value="#fishing">&nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What is this?', 'instagram-feed'); ?></a>
1014
+ <br>
1015
+ <span class="sbi_note" style="margin-left: 0;"><?php _e('Separate multiple hashtags using commas', 'instagram-feed'); ?></span>
1016
+
1017
+
1018
+ <p class="sbi_tooltip"><?php _e('You can use this setting to highlight posts by a hashtag. Use a specified hashtag in your posts and they will be automatically highlighted in your feed.', 'instagram-feed'); ?></p>
1019
+ </div>
1020
+ <div class="sb_instagram_highlight_sub_options sb_instagram_highlight_ids sb_instagram_layout_setting" style="display: none;">
1021
+ <label><?php _e('Highlight Posts by ID', 'instagram-feed'); ?></label>
1022
+ <textarea name="sb_instagram_highlight_ids" id="sb_instagram_highlight_ids" style="width: 100%;" rows="3">sbi_1852317219231323590_3269008872</textarea>
1023
+ <br>
1024
+ <span class="sbi_note" style="margin-left: 0;"><?php _e('Separate IDs using commas', 'instagram-feed'); ?></span>
1025
+
1026
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What is this?', 'instagram-feed'); ?></a>
1027
+ <p class="sbi_tooltip"><?php _e('You can use this setting to highlight posts by their ID. Enable and use "moderation mode", check the box to show post IDs underneath posts, then copy and paste IDs into this text box.', 'instagram-feed'); ?></p>
1028
+ </div>
1029
+ </div>
1030
+
1031
+ </div>
1032
+ </td>
1033
+ </tr>
1034
+ <tr valign="top">
1035
+ <th scope="row"><label><?php _e('Number of Photos', 'instagram-feed'); ?></label><code class="sbi_shortcode"> num
1036
+ Eg: num=6</code></th>
1037
+ <td>
1038
+ <input name="sb_instagram_num" type="text" value="<?php echo esc_attr( $sb_instagram_num ); ?>" size="4" maxlength="4" />
1039
+ <span class="sbi_note"><?php _e('Number of photos to show initially.', 'instagram-feed'); ?></span>
1040
+ </td>
1041
+ </tr>
1042
+ <tr valign="top">
1043
+ <th scope="row"><label><?php _e('Number of Columns', 'instagram-feed'); ?></label><code class="sbi_shortcode"> cols
1044
+ Eg: cols=3</code></th>
1045
+ <td>
1046
+ <select name="sb_instagram_cols">
1047
+ <option value="1" <?php if($sb_instagram_cols == "1") echo 'selected="selected"' ?> ><?php _e('1', 'instagram-feed'); ?></option>
1048
+ <option value="2" <?php if($sb_instagram_cols == "2") echo 'selected="selected"' ?> ><?php _e('2', 'instagram-feed'); ?></option>
1049
+ <option value="3" <?php if($sb_instagram_cols == "3") echo 'selected="selected"' ?> ><?php _e('3', 'instagram-feed'); ?></option>
1050
+ <option value="4" <?php if($sb_instagram_cols == "4") echo 'selected="selected"' ?> ><?php _e('4', 'instagram-feed'); ?></option>
1051
+ <option value="5" <?php if($sb_instagram_cols == "5") echo 'selected="selected"' ?> ><?php _e('5', 'instagram-feed'); ?></option>
1052
+ <option value="6" <?php if($sb_instagram_cols == "6") echo 'selected="selected"' ?> ><?php _e('6', 'instagram-feed'); ?></option>
1053
+ <option value="7" <?php if($sb_instagram_cols == "7") echo 'selected="selected"' ?> ><?php _e('7', 'instagram-feed'); ?></option>
1054
+ <option value="8" <?php if($sb_instagram_cols == "8") echo 'selected="selected"' ?> ><?php _e('8', 'instagram-feed'); ?></option>
1055
+ <option value="9" <?php if($sb_instagram_cols == "9") echo 'selected="selected"' ?> ><?php _e('9', 'instagram-feed'); ?></option>
1056
+ <option value="10" <?php if($sb_instagram_cols == "10") echo 'selected="selected"' ?> ><?php _e('10', 'instagram-feed'); ?></option>
1057
+ </select>
1058
+ </td>
1059
+ </tr>
1060
+ <tr valign="top">
1061
+ <th scope="row"><label><?php _e('Padding around Images', 'instagram-feed'); ?></label><code class="sbi_shortcode"> imagepadding imagepaddingunit</code></th>
1062
+ <td>
1063
+ <input name="sb_instagram_image_padding" type="text" value="<?php echo esc_attr( $sb_instagram_image_padding ); ?>" size="4" maxlength="4" />
1064
+ <select name="sb_instagram_image_padding_unit">
1065
+ <option value="px" <?php if($sb_instagram_image_padding_unit == "px") echo 'selected="selected"' ?> ><?php _e('px', 'instagram-feed'); ?></option>
1066
+ <option value="%" <?php if($sb_instagram_image_padding_unit == "%") echo 'selected="selected"' ?> ><?php _e('%', 'instagram-feed'); ?></option>
1067
+ </select>
1068
+ </td>
1069
+ </tr>
1070
+ <tr valign="top">
1071
+ <th scope="row"><label><?php _e("Disable mobile layout", 'instagram-feed'); ?></label><code class="sbi_shortcode"> disablemobile
1072
+ Eg: disablemobile=true</code></th>
1073
+ <td>
1074
+ <input type="checkbox" name="sb_instagram_disable_mobile" id="sb_instagram_disable_mobile" <?php if($sb_instagram_disable_mobile == true) echo 'checked="checked"' ?> />
1075
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e( 'What does this mean?', 'instagram-feed' ); ?></a>
1076
+ <p class="sbi_tooltip"><?php _e("By default on mobile devices the layout automatically changes to use fewer columns. Checking this setting disables the mobile layout.", 'instagram-feed'); ?></p>
1077
+ </td>
1078
+ </tr>
1079
+ </tbody>
1080
+ </table>
1081
+
1082
+ <?php submit_button(); ?>
1083
+
1084
+ <hr id="photos" />
1085
+ <h3><?php _e('Photos', 'instagram-feed'); ?></h3>
1086
+
1087
+ <table class="form-table">
1088
+ <tbody>
1089
+ <tr valign="top">
1090
+ <th scope="row"><label><?php _e('Sort Photos By', 'instagram-feed'); ?></label><code class="sbi_shortcode"> sortby
1091
+ Eg: sortby=random</code></th>
1092
+ <td>
1093
+ <select name="sb_instagram_sort">
1094
+ <option value="none" <?php if($sb_instagram_sort == "none") echo 'selected="selected"' ?> ><?php _e('Newest to oldest', 'instagram-feed'); ?></option>
1095
+ <option value="random" <?php if($sb_instagram_sort == "random") echo 'selected="selected"' ?> ><?php _e('Random', 'instagram-feed'); ?></option>
1096
+ </select>
1097
+ </td>
1098
+ </tr>
1099
+ <tr valign="top">
1100
+ <th scope="row"><label><?php _e('Image Resolution', 'instagram-feed'); ?></label><code class="sbi_shortcode"> imageres
1101
+ Eg: imageres=thumb</code></th>
1102
+ <td>
1103
+
1104
+ <select name="sb_instagram_image_res">
1105
+ <option value="auto" <?php if($sb_instagram_image_res == "auto") echo 'selected="selected"' ?> ><?php _e('Auto-detect (recommended)', 'instagram-feed'); ?></option>
1106
+ <option value="thumb" <?php if($sb_instagram_image_res == "thumb") echo 'selected="selected"' ?> ><?php _e('Thumbnail (150x150)', 'instagram-feed'); ?></option>
1107
+ <option value="medium" <?php if($sb_instagram_image_res == "medium") echo 'selected="selected"' ?> ><?php _e('Medium (306x306)', 'instagram-feed'); ?></option>
1108
+ <option value="full" <?php if($sb_instagram_image_res == "full") echo 'selected="selected"' ?> ><?php _e('Full size (640x640)', 'instagram-feed'); ?></option>
1109
+ </select>
1110
+
1111
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e( 'What does Auto-detect mean?', 'instagram-feed'); ?></a>
1112
+ <p class="sbi_tooltip"><?php _e("Auto-detect means that the plugin automatically sets the image resolution based on the size of your feed.", 'instagram-feed'); ?></p>
1113
+
1114
+ </td>
1115
+ </tr>
1116
+ </tbody>
1117
+ </table>
1118
+
1119
+ <span><a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a></span>
1120
+
1121
+ <div class="sbi-pro-options">
1122
+ <p class="sbi-upgrade-link">
1123
+ <i class="fa fa-rocket" aria-hidden="true"></i>&nbsp; <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable these settings', 'instagram-feed'); ?></a>
1124
+ </p>
1125
+ <table class="form-table">
1126
+ <tbody>
1127
+ <tr valign="top" class="sbi_pro">
1128
+ <th scope="row"><label><?php _e('Media Type to Display','instagram-feed'); ?></label></th>
1129
+ <td>
1130
+ <select name="sb_instagram_media_type" disabled>
1131
+ <option value="all"><?php _e('All','instagram-feed'); ?></option>
1132
+ <option value="photos"><?php _e('Photos only','instagram-feed'); ?></option>
1133
+ <option value="videos"><?php _e('Videos only','instagram-feed'); ?></option>
1134
+ </select>
1135
+ </td>
1136
+ </tr>
1137
+
1138
+ <tr valign="top" class="sbi_pro">
1139
+ <th scope="row"><label><?php _e("Enable Pop-up Lightbox", 'instagram-feed'); ?></label></th>
1140
+ <td>
1141
+ <input type="checkbox" name="sb_instagram_captionlinks" id="sb_instagram_captionlinks" disabled />
1142
+ </td>
1143
+ </tr>
1144
+
1145
+ <tr valign="top" class="sbi_pro">
1146
+ <th scope="row"><label><?php _e("Link Posts to URL in Caption (Shoppable feed)",'instagram-feed'); ?></label></th>
1147
+ <td>
1148
+ <input type="checkbox" name="sb_instagram_captionlinks" id="sb_instagram_captionlinks" disabled />
1149
+ &nbsp;<a class="sbi_tooltip_link sbi_pro" href="JavaScript:void(0);"><?php _e("What will this do?",'instagram-feed'); ?></a>
1150
+ <p class="sbi_tooltip"><?php _e("Checking this box will change the link for each post to any url included in the caption for that Instagram post. The lightbox will be disabled. Visit <a href='https://smashballoon.com/make-a-shoppable-feed?utm_source=plugin-free&utm_campaign=sbi'>this link</a> to learn how this works.",'instagram-feed'); ?></p>
1151
+ </td>
1152
+ </tr>
1153
+ </tbody>
1154
+ </table>
1155
+ </div>
1156
+
1157
+
1158
+ <hr />
1159
+ <h3><?php _e('Photo Hover Style','instagram-feed'); ?></h3>
1160
+
1161
+ <p style="padding-bottom: 18px;">
1162
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable Photo Hover styles','instagram-feed'); ?></a><br />
1163
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options','instagram-feed'); ?></a>
1164
+ </p>
1165
+
1166
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1167
+ <table class="form-table">
1168
+ <tbody>
1169
+ <tr valign="top" class="sbi_pro">
1170
+ <th scope="row"><label><?php _e('Hover Background Color', 'instagram-feed'); ?></label></th>
1171
+ <td>
1172
+ <input name="sb_hover_background" type="text" disabled class="sbi_colorpick" />
1173
+ </td>
1174
+ </tr>
1175
+ <tr valign="top" class="sbi_pro">
1176
+ <th scope="row"><label><?php _e('Hover Text Color', 'instagram-feed'); ?></label></th>
1177
+ <td>
1178
+ <input name="sb_hover_text" type="text" disabled class="sbi_colorpick" />
1179
+ </td>
1180
+ </tr>
1181
+ <tr valign="top" class="sbi_pro">
1182
+ <th scope="row"><label><?php _e('Information to display', 'instagram-feed'); ?></label></th>
1183
+ <td>
1184
+ <div>
1185
+ <input name="sbi_hover_inc_username" type="checkbox" disabled />
1186
+ <label for="sbi_hover_inc_username"><?php _e('Username', 'instagram-feed'); ?></label>
1187
+ </div>
1188
+ <div>
1189
+ <input name="sbi_hover_inc_icon" type="checkbox" disabled />
1190
+ <label for="sbi_hover_inc_icon"><?php _e('Expand Icon', 'instagram-feed'); ?></label>
1191
+ </div>
1192
+ <div>
1193
+ <input name="sbi_hover_inc_date" type="checkbox" disabled />
1194
+ <label for="sbi_hover_inc_date"><?php _e('Date', 'instagram-feed'); ?></label>
1195
+ </div>
1196
+ <div>
1197
+ <input name="sbi_hover_inc_instagram" type="checkbox" disabled />
1198
+ <label for="sbi_hover_inc_instagram"><?php _e('Instagram Icon/Link', 'instagram-feed'); ?></label>
1199
+ </div>
1200
+ <div>
1201
+ <input name="sbi_hover_inc_location" type="checkbox" disabled />
1202
+ <label for="sbi_hover_inc_location"><?php _e('Location', 'instagram-feed'); ?></label>
1203
+ </div>
1204
+ <div>
1205
+ <input name="sbi_hover_inc_caption" type="checkbox" disabled />
1206
+ <label for="sbi_hover_inc_caption"><?php _e('Caption', 'instagram-feed'); ?></label>
1207
+ </div>
1208
+ <div>
1209
+ <input name="sbi_hover_inc_likes" type="checkbox" disabled />
1210
+ <label for="sbi_hover_inc_likes"><?php _e('Like/Comment Icons', 'instagram-feed'); ?></label>
1211
+ </div>
1212
+ </td>
1213
+ </tr>
1214
+
1215
+ </tbody>
1216
+ </table>
1217
+ </div>
1218
+
1219
+
1220
+ <hr />
1221
+ <h3><?php _e( 'Carousel', 'instagram-feed' ); ?></h3>
1222
+ <p style="padding-bottom: 18px;">
1223
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable Carousels', 'instagram-feed'); ?></a><br />
1224
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a>
1225
+ </p>
1226
+
1227
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1228
+ <table class="form-table">
1229
+ <tbody>
1230
+ <tr valign="top" class="sbi_pro">
1231
+ <th scope="row"><label><?php _e("Enable Carousel", 'instagram-feed'); ?></label></th>
1232
+ <td>
1233
+ <input type="checkbox" disabled />
1234
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e("What is this?", 'instagram-feed'); ?></a>
1235
+ <p class="sbi_tooltip"><?php _e("Enable this setting to create a carousel slider out of your photos.", 'instagram-feed'); ?></p>
1236
+ </td>
1237
+ </tr>
1238
+ <tr valign="top" class="sbi_pro">
1239
+ <th scope="row"><label><?php _e("Show Navigation Arrows", 'instagram-feed'); ?></label></th>
1240
+ <td>
1241
+ <input type="checkbox" disabled />
1242
+ </td>
1243
+ </tr>
1244
+ <tr valign="top" class="sbi_pro">
1245
+ <th scope="row"><label><?php _e("Show Pagination", 'instagram-feed'); ?></label></th>
1246
+ <td>
1247
+ <input type="checkbox" disabled />
1248
+ </td>
1249
+ </tr>
1250
+ <tr valign="top" class="sbi_pro">
1251
+ <th scope="row"><label><?php _e("Enable Autoplay", 'instagram-feed'); ?></label></th>
1252
+ <td>
1253
+ <input type="checkbox" disabled />
1254
+ </td>
1255
+ </tr>
1256
+ <tr valign="top" class="sbi_pro">
1257
+ <th scope="row"><label><?php _e("Interval Time", 'instagram-feed'); ?></label></th>
1258
+ <td>
1259
+ <input name="sb_instagram_carousel_interval" type="text" disabled size="6" /><?php _e("milliseconds", 'instagram-feed'); ?>
1260
+ </td>
1261
+ </tr>
1262
+ </tbody>
1263
+ </table>
1264
+ </div>
1265
+
1266
+
1267
+
1268
+ <hr id="headeroptions" />
1269
+ <h3><?php _e("Header", 'instagram-feed'); ?></h3>
1270
+ <table class="form-table">
1271
+ <tbody>
1272
+ <tr valign="top">
1273
+ <th scope="row"><label><?php _e("Show Feed Header", 'instagram-feed'); ?></label><code class="sbi_shortcode"> showheader
1274
+ Eg: showheader=false</code></th>
1275
+ <td>
1276
+ <input type="checkbox" name="sb_instagram_show_header" id="sb_instagram_show_header" <?php if($sb_instagram_show_header == true) echo 'checked="checked"' ?> />
1277
+ </td>
1278
+ </tr>
1279
+ <tr valign="top">
1280
+ <th scope="row"><label><?php _e('Header Text Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> headercolor
1281
+ Eg: headercolor=fff</code></th>
1282
+ <td>
1283
+ <input name="sb_instagram_header_color" type="text" value="<?php echo esc_attr( $sb_instagram_header_color ); ?>" class="sbi_colorpick" />
1284
+ </td>
1285
+ </tr>
1286
+ </tbody>
1287
+ </table>
1288
+
1289
+ <span><a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a></span>
1290
+
1291
+ <div class="sbi-pro-options">
1292
+ <p class="sbi-upgrade-link">
1293
+ <i class="fa fa-rocket" aria-hidden="true"></i>&nbsp; <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable these settings', 'instagram-feed'); ?></a>
1294
+ </p>
1295
+ <table class="form-table">
1296
+ <tbody>
1297
+ <tr valign="top" class="sbi_pro">
1298
+ <th scope="row"><label><?php _e('Header Style','instagram-feed'); ?></label></th>
1299
+ <td>
1300
+ <select name="sb_instagram_header_style" style="float: left;">
1301
+ <option value="circle"><?php _e('Standard','instagram-feed'); ?></option>
1302
+ <option value="boxed"><?php _e('Boxed','instagram-feed'); ?></option>
1303
+ <option value="centered"><?php _e('Centered','instagram-feed'); ?></option>
1304
+ </select>
1305
+ </td>
1306
+ </tr>
1307
+ <tr valign="top" class="sbi_pro">
1308
+ <th scope="row"><label><?php _e('Header Size', 'instagram-feed'); ?></label><code class="sbi_shortcode"> headersize
1309
+ Eg: headersize=medium</code></th>
1310
+ <td>
1311
+ <select name="sb_instagram_header_size" id="sb_instagram_header_size" style="float: left;">
1312
+ <option value="small" <?php if($sb_instagram_header_size == "small") echo 'selected="selected"' ?> ><?php _e('Small', 'instagram-feed'); ?></option>
1313
+ <option value="medium" <?php if($sb_instagram_header_size == "medium") echo 'selected="selected"' ?> ><?php _e('Medium', 'instagram-feed'); ?></option>
1314
+ <option value="large" <?php if($sb_instagram_header_size == "large") echo 'selected="selected"' ?> ><?php _e('Large', 'instagram-feed'); ?></option>
1315
+ </select>
1316
+ </td>
1317
+ </tr>
1318
+ <tr valign="top" class="sbi_pro">
1319
+ <th scope="row"><label><?php _e("Show Bio Text", 'instagram-feed'); ?></label><code class="sbi_shortcode"> showbio
1320
+ Eg: showbio=false</code></th>
1321
+ <td>
1322
+ <?php $sb_instagram_show_bio = isset( $sb_instagram_show_bio ) ? $sb_instagram_show_bio : true; ?>
1323
+ <input type="checkbox" name="sb_instagram_show_bio" id="sb_instagram_show_bio" <?php if($sb_instagram_show_bio == true) echo 'checked="checked"' ?> />
1324
+ <span class="sbi_note"><?php _e("Only applies for Instagram accounts with bios", 'instagram-feed'); ?></span>
1325
+ </td>
1326
+ </tr>
1327
+ <tr valign="top" class="sbi_pro">
1328
+ <th scope="row"><label><?php _e("Show Number of Followers",'instagram-feed'); ?></label></th>
1329
+ <td>
1330
+ <input type="checkbox" disabled />
1331
+ <span class="sbi_note"><?php _e("This only applies when displaying photos from a User ID",'instagram-feed'); ?></span>
1332
+ </td>
1333
+ </tr>
1334
+ </tbody>
1335
+ </table>
1336
+ </div>
1337
+
1338
+ <?php submit_button(); ?>
1339
+
1340
+
1341
+ <hr />
1342
+ <h3><?php _e("Caption", 'instagram-feed'); ?></h3>
1343
+ <p style="padding-bottom: 18px;">
1344
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e("Upgrade to Pro to enable Photo Captions", 'instagram-feed'); ?></a><br />
1345
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e("Show Pro Options", 'instagram-feed'); ?></a>
1346
+ </p>
1347
+
1348
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1349
+ <table class="form-table">
1350
+ <tbody>
1351
+ <tr valign="top" class="sbi_pro">
1352
+ <th scope="row"><label><?php _e("Show Caption", 'instagram-feed'); ?></label></th>
1353
+ <td>
1354
+ <input type="checkbox" disabled />
1355
+ </td>
1356
+ </tr>
1357
+ <tr valign="top" class="sbi_pro">
1358
+ <th scope="row"><label><?php _e("Maximum Text Length", 'instagram-feed'); ?></label></th>
1359
+ <td>
1360
+ <input disabled size="4" />Characters
1361
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e("What is this?", 'instagram-feed'); ?></a>
1362
+ <p class="sbi_tooltip"><?php _e("The number of characters of text to display in the caption. An elipsis link will be added to allow the user to reveal more text if desired.", 'instagram-feed'); ?></p>
1363
+ </td>
1364
+ </tr>
1365
+ <tr valign="top" class="sbi_pro">
1366
+ <th scope="row"><label><?php _e('Text Color', 'instagram-feed'); ?></label></th>
1367
+ <td>
1368
+ <input type="text" disabled class="sbi_colorpick" />
1369
+ </td>
1370
+ </tr>
1371
+ <tr valign="top" class="sbi_pro">
1372
+ <th scope="row"><label><?php _e('Text Size', 'instagram-feed'); ?></label></th>
1373
+ <td>
1374
+ <select name="sb_instagram_caption_size" style="width: 180px;" disabled>
1375
+ <option value="inherit" ><?php _e('Inherit from theme', 'instagram-feed'); ?></option>
1376
+ <option value="10" >10px</option>
1377
+ <option value="11" >11px</option>
1378
+ <option value="12" >12px</option>
1379
+ <option value="13" >13px</option>
1380
+ <option value="14" >14px</option>
1381
+ <option value="16" >16px</option>
1382
+ <option value="18" >18px</option>
1383
+ <option value="20" >20px</option>
1384
+ <option value="24" >24px</option>
1385
+ <option value="28" >28px</option>
1386
+ <option value="32" >32px</option>
1387
+ <option value="36" >36px</option>
1388
+ <option value="40" >40px</option>
1389
+ </select>
1390
+ </td>
1391
+ </tr>
1392
+ </tbody>
1393
+ </table>
1394
+ </div>
1395
+
1396
+
1397
+ <hr />
1398
+ <h3><?php _e("Likes &amp; Comments", 'instagram-feed'); ?></h3>
1399
+ <p style="padding-bottom: 18px;">
1400
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e("Upgrade to Pro to enable Likes &amp; Comments", 'instagram-feed'); ?></a><br />
1401
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e("Show Pro Options", 'instagram-feed'); ?></a>
1402
+ </p>
1403
+
1404
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1405
+ <table class="form-table">
1406
+ <tbody>
1407
+ <tr valign="top" class="sbi_pro">
1408
+ <th scope="row"><label><?php _e("Show Icons", 'instagram-feed'); ?></label></th>
1409
+ <td>
1410
+ <input type="checkbox" disabled />
1411
+ </td>
1412
+ </tr>
1413
+ <tr valign="top" class="sbi_pro">
1414
+ <th scope="row"><label><?php _e('Icon Color', 'instagram-feed'); ?></label></th>
1415
+ <td>
1416
+ <input type="text" disabled class="sbi_colorpick" />
1417
+ </td>
1418
+ </tr>
1419
+ <tr valign="top" class="sbi_pro">
1420
+ <th scope="row"><label><?php _e('Icon Size', 'instagram-feed'); ?></label></th>
1421
+ <td>
1422
+ <select disabled name="sb_instagram_meta_size" style="width: 180px;">
1423
+ <option value="inherit"><?php _e('Inherit from theme', 'instagram-feed'); ?></option>
1424
+ <option value="10" >10px</option>
1425
+ <option value="11" >11px</option>
1426
+ <option value="12" >12px</option>
1427
+ <option value="13" >13px</option>
1428
+ <option value="14" >14px</option>
1429
+ <option value="16" >16px</option>
1430
+ <option value="18" >18px</option>
1431
+ <option value="20" >20px</option>
1432
+ <option value="24" >24px</option>
1433
+ <option value="28" >28px</option>
1434
+ <option value="32" >32px</option>
1435
+ <option value="36" >36px</option>
1436
+ <option value="40" >40px</option>
1437
+ </select>
1438
+ </td>
1439
+ </tr>
1440
+ </tbody>
1441
+ </table>
1442
+ </div>
1443
+
1444
+
1445
+ <hr />
1446
+ <h3><?php _e('Lightbox Comments', 'instagram-feed'); ?></h3>
1447
+
1448
+ <p style="padding-bottom: 18px;">
1449
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable Comments', 'instagram-feed'); ?></a><br />
1450
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a>
1451
+ </p>
1452
+
1453
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1454
+ <table class="form-table">
1455
+ <tbody>
1456
+
1457
+ <tr valign="top" class="sbi_pro">
1458
+ <th scope="row"><label><?php _e('Show Comments in Lightbox', 'instagram-feed'); ?></label></th>
1459
+ <td style="padding: 5px 10px 0 10px;">
1460
+ <input type="checkbox" disabled style="margin-right: 15px;" />
1461
+ <input class="button-secondary" style="margin-top: -5px;" disabled value="<?php echo esc_attr( 'Clear Comment Cache', 'instagram-feed' ); ?>" />
1462
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e("What is this?", 'instagram-feed'); ?></a>
1463
+ <p class="sbi_tooltip"><?php _e("This will remove the cached comments saved in the database", 'instagram-feed'); ?></p>
1464
+ </td>
1465
+ </tr>
1466
+ <tr valign="top" class="sbi_pro">
1467
+ <th scope="row"><label><?php _e('Number of Comments', 'instagram-feed'); ?></label></th>
1468
+ <td>
1469
+ <input name="sb_instagram_num_comments" type="text" disabled size="4" />
1470
+ <span class="sbi_note"><?php _e('Max number of latest comments.', 'instagram-feed'); ?></span>
1471
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e("What is this?", 'instagram-feed'); ?></a>
1472
+ <p class="sbi_tooltip"><?php _e("This is the maximum number of comments that will be shown in the lightbox. If there are more comments available than the number set, only the latest comments will be shown", 'instagram-feed'); ?></p>
1473
+ </td>
1474
+ </tr>
1475
+
1476
+ </tbody>
1477
+ </table>
1478
+ </div>
1479
+
1480
+
1481
+ <hr id="loadmore" />
1482
+ <h3><?php _e("'Load More' Button", 'instagram-feed'); ?></h3>
1483
+ <table class="form-table">
1484
+ <tbody>
1485
+ <tr valign="top">
1486
+ <th scope="row"><label><?php _e("Show the 'Load More' button", 'instagram-feed'); ?></label><code class="sbi_shortcode"> showbutton
1487
+ Eg: showbutton=false</code></th>
1488
+ <td>
1489
+ <input type="checkbox" name="sb_instagram_show_btn" id="sb_instagram_show_btn" <?php if($sb_instagram_show_btn == true) echo 'checked="checked"' ?> />
1490
+ </td>
1491
+ </tr>
1492
+ <tr valign="top">
1493
+ <th scope="row"><label><?php _e('Button Background Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> buttoncolor
1494
+ Eg: buttoncolor=8224e3</code></th>
1495
+ <td>
1496
+ <input name="sb_instagram_btn_background" type="text" value="<?php echo esc_attr( $sb_instagram_btn_background ); ?>" class="sbi_colorpick" />
1497
+ </td>
1498
+ </tr>
1499
+ <tr valign="top">
1500
+ <th scope="row"><label><?php _e('Button Text Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> buttontextcolor
1501
+ Eg: buttontextcolor=eeee22</code></th>
1502
+ <td>
1503
+ <input name="sb_instagram_btn_text_color" type="text" value="<?php echo esc_attr( $sb_instagram_btn_text_color ); ?>" class="sbi_colorpick" />
1504
+ </td>
1505
+ </tr>
1506
+ <tr valign="top">
1507
+ <th scope="row"><label><?php _e('Button Text', 'instagram-feed'); ?></label><code class="sbi_shortcode"> buttontext
1508
+ Eg: buttontext="Show more.."</code></th>
1509
+ <td>
1510
+ <input name="sb_instagram_btn_text" type="text" value="<?php echo esc_attr( stripslashes( $sb_instagram_btn_text ) ); ?>" size="20" />
1511
+ </td>
1512
+ </tr>
1513
+ </tbody>
1514
+ </table>
1515
+
1516
+ <?php submit_button(); ?>
1517
+
1518
+ <hr id="follow" />
1519
+ <h3><?php _e("'Follow' Button", 'instagram-feed'); ?></h3>
1520
+ <table class="form-table">
1521
+ <tbody>
1522
+ <tr valign="top">
1523
+ <th scope="row"><label><?php _e("Show the Follow button", 'instagram-feed'); ?></label><code class="sbi_shortcode"> showfollow
1524
+ Eg: showfollow=true</code></th>
1525
+ <td>
1526
+ <input type="checkbox" name="sb_instagram_show_follow_btn" id="sb_instagram_show_follow_btn" <?php if($sb_instagram_show_follow_btn == true) echo 'checked="checked"' ?> />
1527
+ </td>
1528
+ </tr>
1529
+
1530
+ <tr valign="top">
1531
+ <th scope="row"><label><?php _e('Button Background Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> followcolor
1532
+ Eg: followcolor=28a1bf</code></th>
1533
+ <td>
1534
+ <input name="sb_instagram_folow_btn_background" type="text" value="<?php echo esc_attr( $sb_instagram_folow_btn_background ); ?>" class="sbi_colorpick" />
1535
+ </td>
1536
+ </tr>
1537
+ <tr valign="top">
1538
+ <th scope="row"><label><?php _e('Button Text Color', 'instagram-feed'); ?></label><code class="sbi_shortcode"> followtextcolor
1539
+ Eg: followtextcolor=000</code></th>
1540
+ <td>
1541
+ <input name="sb_instagram_follow_btn_text_color" type="text" value="<?php echo esc_attr( $sb_instagram_follow_btn_text_color ); ?>" class="sbi_colorpick" />
1542
+ </td>
1543
+ </tr>
1544
+ <tr valign="top">
1545
+ <th scope="row"><label><?php _e('Button Text', 'instagram-feed'); ?></label><code class="sbi_shortcode"> followtext
1546
+ Eg: followtext="Follow me"</code></th>
1547
+ <td>
1548
+ <input name="sb_instagram_follow_btn_text" type="text" value="<?php echo esc_attr( stripslashes( $sb_instagram_follow_btn_text ) ); ?>" size="30" />
1549
+ </td>
1550
+ </tr>
1551
+ </tbody>
1552
+ </table>
1553
+
1554
+ <hr id="filtering" />
1555
+ <h3><?php _e('Post Filtering', 'instagram-feed'); ?></h3>
1556
+
1557
+ <p style="padding-bottom: 18px;">
1558
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable Post Filtering options', 'instagram-feed'); ?></a><br />
1559
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a>
1560
+ </p>
1561
+
1562
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1563
+
1564
+ <table class="form-table">
1565
+ <tbody>
1566
+ <tr valign="top" class="sbi_pro">
1567
+ <th scope="row"><label><?php _e('Remove photos containing these words or hashtags', 'instagram-feed'); ?></label></th>
1568
+ <td>
1569
+ <div class="sb_instagram_apply_labels">
1570
+ <p><?php _e('Apply to:', 'instagram-feed'); ?></p>
1571
+ <input class="sb_instagram_incex_one_all" type="radio" value="all" disabled /><label><?php _e('All feeds', 'instagram-feed'); ?></label>
1572
+ <input class="sb_instagram_incex_one_all" type="radio" value="one" disabled /><label><?php _e('One feed', 'instagram-feed'); ?></label>
1573
+ </div>
1574
+
1575
+ <input disabled name="sb_instagram_exclude_words" id="sb_instagram_exclude_words" type="text" style="width: 70%;" value="" />
1576
+ <br />
1577
+ <span class="sbi_note" style="margin-left: 0;"><?php _e('Separate words/hashtags using commas', 'instagram-feed'); ?></span>
1578
+ &nbsp;<a class="sbi_tooltip_link sbi_pro" href="JavaScript:void(0);"><?php _e( 'What is this?', 'instagram-feed'); ?></a>
1579
+ <p class="sbi_tooltip"><?php _e("You can use this setting to remove photos which contain certain words or hashtags in the caption. Separate multiple words or hashtags using commas.", 'instagram-feed'); ?></p>
1580
+ </td>
1581
+ </tr>
1582
+
1583
+ <tr valign="top" class="sbi_pro">
1584
+ <th scope="row"><label><?php _e('Show photos containing these words or hashtags', 'instagram-feed'); ?></label></th>
1585
+ <td>
1586
+ <div class="sb_instagram_apply_labels">
1587
+ <p><?php _e('Apply to:', 'instagram-feed'); ?></p>
1588
+ <input class="sb_instagram_incex_one_all" type="radio" value="all" disabled /><label><?php _e('All feeds', 'instagram-feed'); ?></label>
1589
+ <input class="sb_instagram_incex_one_all" type="radio" value="one" disabled /><label><?php _e('One feed', 'instagram-feed'); ?></label>
1590
+ </div>
1591
+
1592
+ <input disabled name="sb_instagram_include_words" id="sb_instagram_include_words" type="text" style="width: 70%;" value="" />
1593
+ <br />
1594
+ <span class="sbi_note" style="margin-left: 0;"><?php _e('Separate words/hashtags using commas', 'instagram-feed'); ?></span>
1595
+ &nbsp;<a class="sbi_tooltip_link sbi_pro" href="JavaScript:void(0);"><?php _e( 'What is this?', 'instagram-feed'); ?></a>
1596
+ <p class="sbi_tooltip"><?php _e("You can use this setting to only show photos which contain certain words or hashtags in the caption. For example, adding <code>sheep, cow, dog</code> will show any photos which contain either the word sheep, cow, or dog. Separate multiple words or hashtags using commas.", 'instagram-feed'); ?></p>
1597
+ </td>
1598
+ </tr>
1599
+ </tbody>
1600
+ </table>
1601
+ </div>
1602
+
1603
+
1604
+ <hr id="moderation" />
1605
+ <h3><?php _e('Moderation', 'instagram-feed'); ?></h3>
1606
+
1607
+ <p style="padding-bottom: 18px;">
1608
+ <a href="https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e('Upgrade to Pro to enable Moderation options', 'instagram-feed'); ?></a><br />
1609
+ <a href="javascript:void(0);" class="button button-secondary sbi-show-pro"><b>+</b> <?php _e('Show Pro Options', 'instagram-feed'); ?></a>
1610
+ </p>
1611
+
1612
+ <div class="sbi-pro-options" style="margin-top: -15px;">
1613
+ <table class="form-table">
1614
+ <tbody>
1615
+ <tr valign="top" class="sbi_pro">
1616
+ <th scope="row"><label><?php _e('Moderation Type', 'instagram-feed'); ?></label></th>
1617
+ <td>
1618
+ <input class="sb_instagram_moderation_mode" checked="checked" disabled type="radio" value="visual" style="margin-top: 0;" /><label><?php _e('Visual', 'instagram-feed'); ?></label>
1619
+ <input class="sb_instagram_moderation_mode" disabled type="radio" value="manual" style="margin-top: 0; margin-left: 10px;"/><label><?php _e('Manual', 'instagram-feed'); ?></label>
1620
+
1621
+ <p class="sbi_tooltip" style="display: block;"><?php _e("<b>Visual Moderation Mode</b><br />This adds a button to each feed that will allow you to hide posts, block users, and create white lists from the front end using a visual interface. Visit <a href='https://smashballoon.com/guide-to-moderation-mode/?utm_source=plugin-free&utm_campaign=sbi' target='_blank'>this page</a> for details", 'instagram-feed'); ?></p>
1622
+
1623
+ </td>
1624
+ </tr>
1625
+
1626
+ <tr valign="top" class="sbi_pro">
1627
+ <th scope="row"><label><?php _e('Only show posts by these users', 'instagram-feed'); ?></label></th>
1628
+ <td>
1629
+ <input type="text" style="width: 70%;" disabled /><br />
1630
+ <span class="sbi_note" style="margin-left: 0;"><?php _e('Separate usernames using commas', 'instagram-feed'); ?></span>
1631
+
1632
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e("What is this?", 'instagram-feed'); ?></a>
1633
+ <p class="sbi_tooltip"><?php _e("You can use this setting to show photos only from certain users in your feed. Just enter the usernames here which you want to show. Separate multiple usernames using commas.", 'instagram-feed'); ?></p>
1634
+ </td>
1635
+ </tr>
1636
+ <tr valign="top" class="sbi_pro">
1637
+ <th scope="row"><label><?php _e('White lists', 'instagram-feed'); ?></label></th>
1638
+ <td>
1639
+ <div class="sbi_white_list_names_wrapper">
1640
+ <?php _e("No white lists currently created", 'instagram-feed'); ?>
1641
+ </div>
1642
+
1643
+ <input disabled class="button-secondary" type="submit" value="<?php esc_attr_e( 'Clear White Lists', 'instagram-feed' ); ?>" />
1644
+ &nbsp;<a class="sbi_tooltip_link" href="JavaScript:void(0);" style="display: inline-block; margin-top: 5px;"><?php _e("What is this?", 'instagram-feed'); ?></a>
1645
+ <p class="sbi_tooltip"><?php _e("This will remove all of the white lists from the database", 'instagram-feed'); ?></p>
1646
+ </td>
1647
+ </tr>
1648
+
1649
+ </tbody>
1650
+ </table>
1651
+ </div>
1652
+
1653
+
1654
+
1655
+ <hr id="customcss" />
1656
+ <h3><?php _e('Misc', 'instagram-feed'); ?></h3>
1657
+
1658
+ <table class="form-table">
1659
+ <tbody>
1660
+ <tr valign="top">
1661
+ <td style="padding-bottom: 0;">
1662
+ <?php _e('<strong style="font-size: 15px;">Custom CSS</strong><br />Enter your own custom CSS in the box below', 'instagram-feed'); ?>
1663
+ </td>
1664
+ </tr>
1665
+ <tr valign="top">
1666
+ <td>
1667
+ <textarea name="sb_instagram_custom_css" id="sb_instagram_custom_css" style="width: 70%;" rows="7"><?php echo esc_textarea( stripslashes($sb_instagram_custom_css), 'instagram-feed' ); ?></textarea>
1668
+ </td>
1669
+ </tr>
1670
+ <tr valign="top" id="customjs">
1671
+ <td style="padding-bottom: 0;">
1672
+ <?php _e('<strong style="font-size: 15px;">Custom JavaScript</strong><br />Enter your own custom JavaScript/jQuery in the box below', 'instagram-feed'); ?>
1673
+ </td>
1674
+ </tr>
1675
+ <tr valign="top">
1676
+ <td>
1677
+ <textarea name="sb_instagram_custom_js" id="sb_instagram_custom_js" style="width: 70%;" rows="7"><?php echo esc_textarea( stripslashes($sb_instagram_custom_js), 'instagram-feed' ); ?></textarea>
1678
+ </td>
1679
+ </tr>
1680
+ </tbody>
1681
+ </table>
1682
+ <table class="form-table">
1683
+ <tbody>
1684
+
1685
+ <tr valign="top">
1686
+ <th scope="row"><label for="sb_instagram_ajax_theme" class="bump-left"><?php _e("Are you using an Ajax powered theme?", 'instagram-feed'); ?></label></th>
1687
+ <td>
1688
+ <input name="sb_instagram_ajax_theme" type="checkbox" id="sb_instagram_ajax_theme" <?php if($sb_instagram_ajax_theme == true) echo "checked"; ?> />
1689
+ <label for="sb_instagram_ajax_theme"><?php _e('Yes', 'instagram-feed'); ?></label>
1690
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1691
+ <p class="sbi_tooltip"><?php _e("When navigating your site, if your theme uses Ajax to load content into your pages (meaning your page doesn't refresh) then check this setting. If you're not sure then please check with the theme author.", 'instagram-feed'); ?></p>
1692
+ </td>
1693
+ </tr>
1694
+
1695
+ <tr>
1696
+ <th class="bump-left"><label class="bump-left"><?php _e("Image Resizing", 'instagram-feed'); ?></label></th>
1697
+ <td>
1698
+ <input name="sb_instagram_disable_resize" type="checkbox" id="sb_instagram_disable_resize" <?php if($sb_instagram_disable_resize == true) echo "checked"; ?> />
1699
+ <label for="sb_instagram_disable_resize"><?php _e('Disable Local Image Storing and Resizing', 'instagram-feed'); ?></label><br><br>
1700
+ <input name="sb_instagram_favor_local" type="checkbox" id="sb_instagram_favor_local" <?php if($sb_instagram_favor_local == true) echo "checked"; ?> />
1701
+ <label for="sb_instagram_favor_local"><?php _e('Favor Local Images', 'instagram-feed'); ?></label><br><br>
1702
+
1703
+ <input id="sbi_reset_resized" class="button-secondary" type="submit" value="<?php esc_attr_e( 'Reset Resized Images' ); ?>" style="vertical-align: middle;"/>
1704
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1705
+ <p class="sbi_tooltip"><?php _e("The plugin creates and stores resized versions of images in order to serve a more optimized resolution size in the feed. Click this button to clear all data related to resized images. Enable the setting to favor local images to always use a local, resized image if one is available.", 'instagram-feed'); ?></p>
1706
+ </td>
1707
+ </tr>
1708
+
1709
+ <tr valign="top">
1710
+ <th scope="row"><label><?php _e('Enqueue JS file in head', 'instagram-feed'); ?></label></th>
1711
+ <td>
1712
+ <input type="checkbox" name="enqueue_js_in_head" id="sb_instagram_enqueue_js_in_head" <?php if($enqueue_js_in_head == true) echo 'checked="checked"' ?> />
1713
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1714
+ <p class="sbi_tooltip"><?php _e("Check this box if you'd like to enqueue the JavaScript file for the plugin in the head instead of the footer.", 'instagram-feed'); ?></p>
1715
+ </td>
1716
+ </tr>
1717
+
1718
+ <tr valign="top">
1719
+ <th scope="row"><label><?php _e('Disable JS Image Loading', 'instagram-feed'); ?></label></th>
1720
+ <td>
1721
+ <input type="checkbox" name="disable_js_image_loading" id="sb_instagram_disable_js_image_loading" <?php if($disable_js_image_loading == true) echo 'checked="checked"' ?> />
1722
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1723
+ <p class="sbi_tooltip"><?php _e("Check this box to have images loaded server side instead of with JS.", 'instagram-feed'); ?></p>
1724
+ </td>
1725
+ </tr>
1726
+
1727
+ <tr valign="top">
1728
+ <th><label><?php _e("Enable Backup Caching", 'instagram-feed'); ?></label></th>
1729
+ <td class="sbi-customize-tab-opt">
1730
+ <input name="sb_instagram_backup" type="checkbox" id="sb_instagram_backup" <?php if($sb_instagram_backup == true) echo "checked"; ?> />
1731
+ <input id="sbi_clear_backups" class="button-secondary" type="submit" style="position: relative; top: -4px;" value="<?php esc_attr_e( 'Clear Backup Cache', 'instagram-feed' ); ?>" />
1732
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1733
+ <p class="sbi_tooltip"><?php _e('Every feed will save a duplicate version of itself in the database to be used if the normal cache is not available.', 'instagram-feed'); ?></p>
1734
+ </td>
1735
+ </tr>
1736
+
1737
+ <tr>
1738
+ <th class="bump-left">
1739
+ <label class="bump-left"><?php _e("Load initial posts with AJAX", 'instagram-feed'); ?></label>
1740
+ </th>
1741
+ <td>
1742
+ <input name="sb_ajax_initial" type="checkbox" id="sb_ajax_initial" <?php if($sb_ajax_initial == true) echo "checked"; ?> />
1743
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1744
+ <p class="sbi_tooltip"><?php _e("Initial posts will be loaded using AJAX instead of added to the page directly. If you use page caching, this will allow the feed to update according to the \"Check for new posts every\" setting on the \"Configure\" tab.", 'instagram-feed'); ?></p>
1745
+ </td>
1746
+ </tr>
1747
+
1748
+ <tr>
1749
+ <th class="bump-left">
1750
+ <label for="sb_instagram_cron" class="bump-left"><?php _e("Force cache to clear on interval", 'instagram-feed'); ?></label>
1751
+ </th>
1752
+ <td>
1753
+ <select name="sb_instagram_cron">
1754
+ <option value="unset" <?php if($sb_instagram_cron == "unset") echo 'selected="selected"' ?> > - </option>
1755
+ <option value="yes" <?php if($sb_instagram_cron == "yes") echo 'selected="selected"' ?> ><?php _e('Yes', 'instagram-feed'); ?></option>
1756
+ <option value="no" <?php if($sb_instagram_cron == "no") echo 'selected="selected"' ?> ><?php _e('No', 'instagram-feed'); ?></option>
1757
+ </select>
1758
+
1759
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1760
+ <p class="sbi_tooltip"><?php _e("If you're experiencing an issue with the plugin not auto-updating then you can set this to 'Yes' to run a scheduled event behind the scenes which forces the plugin cache to clear on a regular basis and retrieve new data from Instagram.", 'instagram-feed'); ?></p>
1761
+ </td>
1762
+ </tr>
1763
+ </tbody>
1764
+ </table>
1765
+ <table class="form-table">
1766
+ <tbody>
1767
+ <tr valign="top">
1768
+ <th scope="row"><label><?php _e("Disable Icon Font", 'instagram-feed'); ?></label></th>
1769
+ <td>
1770
+ <input type="checkbox" name="sb_instagram_disable_awesome" id="sb_instagram_disable_awesome" <?php if($sb_instagram_disable_awesome == true) echo 'checked="checked"' ?> /> <?php _e( 'Yes', 'instagram-feed' ); ?>
1771
+ </td>
1772
+ </tr>
1773
+ <tr>
1774
+ <th scope="row"><label for="sbi_font_method"><?php _e("Icon Method", 'instagram-feed'); ?></label></th>
1775
+ <td>
1776
+ <select name="sbi_font_method" id="sbi_font_method" class="default-text">
1777
+ <option value="svg" id="sbi-font_method" class="default-text" <?php if($sbi_font_method == 'svg') echo 'selected="selected"' ?>>SVG</option>
1778
+ <option value="fontfile" id="sbi-font_method" class="default-text" <?php if($sbi_font_method == 'fontfile') echo 'selected="selected"' ?>><?php _e("Font File", 'instagram-feed'); ?></option>
1779
+ </select>
1780
+ <a class="sbi_tooltip_link" href="JavaScript:void(0);"><?php _e('What does this mean?', 'instagram-feed'); ?></a>
1781
+ <p class="sbi_tooltip"><?php _e("This plugin uses SVGs for all icons in the feed. Use this setting to switch to font icons.", 'instagram-feed'); ?></p>
1782
+ </td>
1783
+ </tr>
1784
+ </tbody>
1785
+ </table>
1786
+
1787
+ <?php submit_button(); ?>
1788
+
1789
+ </form>
1790
+
1791
+ <p><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>&nbsp; <?php _e('Next Step: <a href="?page=sb-instagram-feed&tab=display">Display your Feed</a>', 'instagram-feed'); ?></p>
1792
+
1793
+ <p><i class="fa fa-life-ring" aria-hidden="true"></i>&nbsp; <?php _e('Need help setting up the plugin? Check out our <a href="https://smashballoon.com/instagram-feed/free/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">setup directions</a>', 'instagram-feed'); ?></p>
1794
+
1795
+
1796
+ <?php } //End Customize tab ?>
1797
+
1798
+
1799
+
1800
+ <?php if( $sbi_active_tab == 'display' ) { //Start Display tab ?>
1801
+
1802
+ <h3><?php _e('Display your Feed', 'instagram-feed'); ?></h3>
1803
+ <p><?php _e("Copy and paste the following shortcode directly into the page, post or widget where you'd like the feed to show up:", 'instagram-feed'); ?></p>
1804
+ <input type="text" value="[instagram-feed]" size="16" readonly="readonly" style="text-align: center;" onclick="this.focus();this.select()" title="<?php _e('To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac).', 'instagram-feed'); ?>" />
1805
+
1806
+ <h3 style="padding-top: 10px;"><?php _e( 'Multiple Feeds', 'instagram-feed' ); ?></h3>
1807
+ <p><?php _e("If you'd like to display multiple feeds then you can set different settings directly in the shortcode like so:", 'instagram-feed'); ?>
1808
+ <code>[instagram-feed num=9 cols=3]</code></p>
1809
+ <p><?php _e( 'You can display as many different feeds as you like, on either the same page or on different pages, by just using the shortcode options below. For example:', 'instagram-feed' ); ?><br />
1810
+ <code>[instagram-feed]</code><br />
1811
+ <code>[instagram-feed num=4 cols=4 showfollow=false]</code><br />
1812
+ <code>[instagram-feed accesstoken="ANOTHER_ACCESS_TOKEN"]</code>
1813
+ </p>
1814
+ <p><?php _e("See the table below for a full list of available shortcode options:", 'instagram-feed'); ?></p>
1815
+
1816
+ <p><span class="sbi_table_key"></span><?php _e('Pro version only', 'instagram-feed'); ?></p>
1817
+
1818
+ <table class="sbi_shortcode_table">
1819
+ <tbody>
1820
+ <tr valign="top">
1821
+ <th scope="row"><?php _e('Shortcode option', 'instagram-feed'); ?></th>
1822
+ <th scope="row"><?php _e('Description', 'instagram-feed'); ?></th>
1823
+ <th scope="row"><?php _e('Example', 'instagram-feed'); ?></th>
1824
+ </tr>
1825
+
1826
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Configure Options", 'instagram-feed'); ?></td></tr>
1827
+ <tr class="sbi_pro">
1828
+ <td>type</td>
1829
+ <td><?php _e("Display photos from a User ID (user)<br />Display posts from a Hashtag (hashtag)", 'instagram-feed'); ?></td>
1830
+ <td><code>[instagram-feed type=user]</code><br /><code>[instagram-feed type=hashtag]</code></td>
1831
+ </tr>
1832
+ <tr>
1833
+ <td>user</td>
1834
+ <td><?php _e('Your Instagram User Name. This must be from a connected account on the "Configure" tab.', 'instagram-feed'); ?></td>
1835
+ <td><code>[instagram-feed user="smashballoon"]</code></td>
1836
+ </tr>
1837
+ <tr class="sbi_pro">
1838
+ <td>hashtag</td>
1839
+ <td><?php _e('Any hashtag. Separate multiple IDs by commas.', 'instagram-feed'); ?></td>
1840
+ <td><code>[instagram-feed hashtag="#awesome"]</code></td>
1841
+ </tr>
1842
+
1843
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Customize Options", 'instagram-feed'); ?></td></tr>
1844
+ <tr>
1845
+ <td>width</td>
1846
+ <td><?php _e("The width of your feed. Any number.", 'instagram-feed'); ?></td>
1847
+ <td><code>[instagram-feed width=50]</code></td>
1848
+ </tr>
1849
+ <tr>
1850
+ <td>widthunit</td>
1851
+ <td><?php _e("The unit of the width. 'px' or '%'", 'instagram-feed'); ?></td>
1852
+ <td><code>[instagram-feed widthunit=%]</code></td>
1853
+ </tr>
1854
+ <tr>
1855
+ <td>height</td>
1856
+ <td><?php _e("The height of your feed. Any number.", 'instagram-feed'); ?></td>
1857
+ <td><code>[instagram-feed height=250]</code></td>
1858
+ </tr>
1859
+ <tr>
1860
+ <td>heightunit</td>
1861
+ <td><?php _e("The unit of the height. 'px' or '%'", 'instagram-feed'); ?></td>
1862
+ <td><code>[instagram-feed heightunit=px]</code></td>
1863
+ </tr>
1864
+ <tr>
1865
+ <td>background</td>
1866
+ <td><?php _e("The background color of the feed. Any hex color code.", 'instagram-feed'); ?></td>
1867
+ <td><code>[instagram-feed background=#ffff00]</code></td>
1868
+ </tr>
1869
+ <tr>
1870
+ <td>class</td>
1871
+ <td><?php _e("Add a CSS class to the feed container", 'instagram-feed'); ?></td>
1872
+ <td><code>[instagram-feed class=feedOne]</code></td>
1873
+ </tr>
1874
+
1875
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Layout Options", 'instagram-feed'); ?></td></tr>
1876
+ <tr class="sbi_pro">
1877
+ <td>layout</td>
1878
+ <td><?php _e("How posts are arranged visually in the feed. There are four layouts: Grid, Carousel Slider, Masonry Grid, or Highlight Grid. Options:", 'instagram-feed' ); ?> 'grid', 'carousel', 'masonry', or 'highlight'</td>
1879
+ <td><code>[instagram-feed layout=grid]</code></td>
1880
+ </tr>
1881
+ <tr>
1882
+ <td>num</td>
1883
+ <td><?php _e("The number of photos to display initially. Maximum is 33.", 'instagram-feed'); ?></td>
1884
+ <td><code>[instagram-feed num=10]</code></td>
1885
+ </tr>
1886
+ <tr class="sbi_pro">
1887
+ <td>nummobile</td>
1888
+ <td><?php _e("The number of photos to display initially for mobile screens (smaller than 480 pixels).", 'instagram-feed'); ?></td>
1889
+ <td><code>[instagram-feed nummobile=6]</code></td>
1890
+ </tr>
1891
+ <tr>
1892
+ <td>cols</td>
1893
+ <td><?php _e("The number of columns in your feed. 1 - 10.", 'instagram-feed'); ?></td>
1894
+ <td><code>[instagram-feed cols=5]</code></td>
1895
+ </tr>
1896
+ <tr class="sbi_pro">
1897
+ <td>colsmobile</td>
1898
+ <td><?php _e("The number of columns in your feed for mobile screens (smaller than 480 pixels).", 'instagram-feed'); ?></td>
1899
+ <td><code>[instagram-feed colsmobile=2]</code></td>
1900
+ </tr>
1901
+ <tr>
1902
+ <td>imagepadding</td>
1903
+ <td><?php _e("The spacing around your photos", 'instagram-feed'); ?></td>
1904
+ <td><code>[instagram-feed imagepadding=10]</code></td>
1905
+ </tr>
1906
+ <tr>
1907
+ <td>imagepaddingunit</td>
1908
+ <td><?php _e("The unit of the padding. 'px' or '%'", 'instagram-feed'); ?></td>
1909
+ <td><code>[instagram-feed imagepaddingunit=px]</code></td>
1910
+ </tr>
1911
+
1912
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Carousel Options", 'instagram-feed'); ?></td></tr>
1913
+ <tr class="sbi_pro">
1914
+ <td>carouselrows</td>
1915
+ <td><?php _e("Choose 1 or 2 rows of posts in the carousel", 'instagram-feed'); ?></td>
1916
+ <td><code>[instagram-feed carouselrows=1]</code></td>
1917
+ </tr>
1918
+ <tr class="sbi_pro">
1919
+ <td>carouselloop</td>
1920
+ <td><?php _e("Infinitely loop through posts or rewind", 'instagram-feed'); ?></td>
1921
+ <td><code>[instagram-feed carouselloop=rewind]</code></td>
1922
+ </tr>
1923
+ <tr class="sbi_pro">
1924
+ <td>carouselarrows</td>
1925
+ <td><?php _e("Display directional arrows on the carousel", 'instagram-feed'); ?></td>
1926
+ <td><code>[instagram-feed carouselarrows=true]</code></td>
1927
+ </tr>
1928
+ <tr class="sbi_pro">
1929
+ <td>carouselpag</td>
1930
+ <td><?php _e("Display pagination links below the carousel", 'instagram-feed'); ?></td>
1931
+ <td><code>[instagram-feed carouselpag=true]</code></td>
1932
+ </tr>
1933
+ <tr class="sbi_pro">
1934
+ <td>carouselautoplay</td>
1935
+ <td><?php _e("Make the carousel autoplay", 'instagram-feed'); ?></td>
1936
+ <td><code>[instagram-feed carouselautoplay=true]</code></td>
1937
+ </tr>
1938
+ <tr class="sbi_pro">
1939
+ <td>carouseltime</td>
1940
+ <td><?php _e("The interval time between slides for autoplay. Time in miliseconds.", 'instagram-feed'); ?></td>
1941
+ <td><code>[instagram-feed carouseltime=8000]</code></td>
1942
+ </tr>
1943
+
1944
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Highlight Options", 'instagram-feed'); ?></td></tr>
1945
+ <tr class="sbi_pro">
1946
+ <td>highlighttype</td>
1947
+ <td><?php _e("Choose from 3 different ways of highlighting posts including by pattern, hashtag, post id or. Options:", 'instagram-feed'); ?> 'pattern', 'hashtag', 'id'.</td>
1948
+ <td><code>[instagram-feed highlighttype=hashtag]</code></td>
1949
+ </tr>
1950
+ <tr class="sbi_pro">
1951
+ <td>highlightpattern</td>
1952
+ <td><?php _e("How often a post is highlighted.", 'instagram-feed'); ?></td>
1953
+ <td><code>[instagram-feed highlightpattern=7]</code></td>
1954
+ </tr>
1955
+ <tr class="sbi_pro">
1956
+ <td>highlightoffset</td>
1957
+ <td><?php _e("When to start the highlight pattern.", 'instagram-feed'); ?></td>
1958
+ <td><code>[instagram-feed highlightoffset=3]</code></td>
1959
+ </tr>
1960
+ <tr class="sbi_pro">
1961
+ <td>highlighthashtag</td>
1962
+ <td><?php _e("Highlight posts with these hashtags.", 'instagram-feed'); ?></td>
1963
+ <td><code>[instagram-feed highlighthashtag=best]</code></td>
1964
+ </tr>
1965
+
1966
+
1967
+
1968
+
1969
+
1970
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Photos Options", 'instagram-feed'); ?></td></tr>
1971
+ <tr>
1972
+ <td>sortby</td>
1973
+ <td><?php _e("Sort the posts by Newest to Oldest (none) or Random (random)", 'instagram-feed'); ?></td>
1974
+ <td><code>[instagram-feed sortby=random]</code></td>
1975
+ </tr>
1976
+ <tr>
1977
+ <td>imageres</td>
1978
+ <td><?php _e("The resolution/size of the photos including full, medium, thumbnail, and auto (based on size of image on page). Options:", 'instagram-feed'); ?> 'auto', full', 'medium' or 'thumb'.</td>
1979
+ <td><code>[instagram-feed imageres=full]</code></td>
1980
+ </tr>
1981
+ <tr class="sbi_pro">
1982
+ <td>media</td>
1983
+ <td><?php _e("Display all media, only photos, or only videos", 'instagram-feed'); ?></td>
1984
+ <td><code>[instagram-feed media=photos]</code></td>
1985
+ </tr>
1986
+ <tr class="sbi_pro">
1987
+ <td>disablelightbox</td>
1988
+ <td><?php _e("Whether to disable the photo Lightbox. It is enabled by default.", 'instagram-feed'); ?></td>
1989
+ <td><code>[instagram-feed disablelightbox=true]</code></td>
1990
+ </tr>
1991
+ <tr>
1992
+ <td>disablemobile</td>
1993
+ <td><?php _e("Disable the mobile layout. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
1994
+ <td><code>[instagram-feed disablemobile=true]</code></td>
1995
+ </tr>
1996
+ <tr class="sbi_pro">
1997
+ <td>captionlinks</td>
1998
+ <td><?php _e("Whether to use urls in captions for the photo's link instead of linking to instagram.com.", 'instagram-feed'); ?></td>
1999
+ <td><code>[instagram-feed captionlinks=true]</code></td>
2000
+ </tr>
2001
+
2002
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Lightbox Comments Options", 'instagram-feed'); ?></td></tr>
2003
+ <tr class="sbi_pro">
2004
+ <td>lightboxcomments</td>
2005
+ <td><?php _e("Whether to show comments in the lightbox for this feed.", 'instagram-feed'); ?></td>
2006
+ <td><code>[instagram-feed lightboxcomments=true]</code></td>
2007
+ </tr>
2008
+ <tr class="sbi_pro">
2009
+ <td>numcomments</td>
2010
+ <td><?php _e("Number of comments to show starting from the most recent.", 'instagram-feed'); ?></td>
2011
+ <td><code>[instagram-feed numcomments=10]</code></td>
2012
+ </tr>
2013
+
2014
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Photos Hover Style Options", 'instagram-feed'); ?></td></tr>
2015
+ <tr class="sbi_pro">
2016
+ <td>hovercolor</td>
2017
+ <td><?php _e("The background color when hovering over a photo. Any hex color code.", 'instagram-feed'); ?></td>
2018
+ <td><code>[instagram-feed hovercolor=#ff0000]</code></td>
2019
+ </tr>
2020
+ <tr class="sbi_pro">
2021
+ <td>hovertextcolor</td>
2022
+ <td><?php _e("The text/icon color when hovering over a photo. Any hex color code.", 'instagram-feed'); ?></td>
2023
+ <td><code>[instagram-feed hovertextcolor=#fff]</code></td>
2024
+ </tr>
2025
+ <tr class="sbi_pro">
2026
+ <td>hoverdisplay</td>
2027
+ <td><?php _e("The info to display when hovering over the photo such as the user name, post date, Instagram icon, location, caption, and like counts. Options:", 'instagram-feed'); ?><br />username, date, instagram, location, caption, likes</td>
2028
+ <td><code>[instagram-feed hoverdisplay="date, location, likes"]</code></td>
2029
+ </tr>
2030
+
2031
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Header Options", 'instagram-feed'); ?></td></tr>
2032
+ <tr>
2033
+ <td>showheader</td>
2034
+ <td><?php _e("Whether to show the feed Header. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
2035
+ <td><code>[instagram-feed showheader=false]</code></td>
2036
+ </tr>
2037
+ <tr class="sbi_pro">
2038
+ <td>showbio</td>
2039
+ <td><?php _e("Display the bio in the header. Options:", 'instagram-feed'); ?> 'true' or 'false'</td>
2040
+ <td><code>[instagram-feed showbio=true]</code></td>
2041
+ </tr>
2042
+ <tr class="sbi_pro">
2043
+ <td>headersize</td>
2044
+ <td><?php _e("Size of the header including small, medium and large. Options:", 'instagram-feed'); ?> small, medium, or large.</td>
2045
+ <td><code>[instagram-feed headersize=medium]</code></td>
2046
+ </tr>
2047
+ <tr>
2048
+ <td>headercolor</td>
2049
+ <td><?php _e("The color of the Header text. Any hex color code.", 'instagram-feed'); ?></td>
2050
+ <td><code>[instagram-feed headercolor=#333]</code></td>
2051
+ </tr>
2052
+
2053
+ <tr class="sbi_table_header"><td colspan=3><?php _e("'Load More' Button Options", 'instagram-feed'); ?></td></tr>
2054
+ <tr>
2055
+ <td>showbutton</td>
2056
+ <td><?php _e("Whether to show the 'Load More' button. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
2057
+ <td><code>[instagram-feed showbutton=false]</code></td>
2058
+ </tr>
2059
+ <tr>
2060
+ <td>buttoncolor</td>
2061
+ <td><?php _e("The background color of the button. Any hex color code.", 'instagram-feed'); ?></td>
2062
+ <td><code>[instagram-feed buttoncolor=#000]</code></td>
2063
+ </tr>
2064
+ <tr>
2065
+ <td>buttontextcolor</td>
2066
+ <td><?php _e("The text color of the button. Any hex color code.", 'instagram-feed'); ?></td>
2067
+ <td><code>[instagram-feed buttontextcolor=#fff]</code></td>
2068
+ </tr>
2069
+ <tr>
2070
+ <td>buttontext</td>
2071
+ <td><?php _e("The text used for the button.", 'instagram-feed'); ?></td>
2072
+ <td><code>[instagram-feed buttontext="Load More Photos"]</code></td>
2073
+ </tr>
2074
+
2075
+ <tr class="sbi_table_header"><td colspan=3><?php _e("'Follow on Instagram' Button Options", 'instagram-feed'); ?></td></tr>
2076
+ <tr>
2077
+ <td>showfollow</td>
2078
+ <td><?php _e("Whether to show the 'Follow on Instagram' button. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
2079
+ <td><code>[instagram-feed showfollow=false]</code></td>
2080
+ </tr>
2081
+ <tr>
2082
+ <td>followcolor</td>
2083
+ <td><?php _e("The background color of the button. Any hex color code.", 'instagram-feed'); ?></td>
2084
+ <td><code>[instagram-feed followcolor=#ff0000]</code></td>
2085
+ </tr>
2086
+ <tr>
2087
+ <td>followtextcolor</td>
2088
+ <td><?php _e("The text color of the button. Any hex color code.", 'instagram-feed'); ?></td>
2089
+ <td><code>[instagram-feed followtextcolor=#fff]</code></td>
2090
+ </tr>
2091
+ <tr>
2092
+ <td>followtext</td>
2093
+ <td><?php _e("The text used for the button.", 'instagram-feed'); ?></td>
2094
+ <td><code>[instagram-feed followtext="Follow me"]</code></td>
2095
+ </tr>
2096
+
2097
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Caption Options", 'instagram-feed'); ?></td></tr>
2098
+ <tr class="sbi_pro">
2099
+ <td>showcaption</td>
2100
+ <td><?php _e("Whether to show the photo caption. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
2101
+ <td><code>[instagram-feed showcaption=false]</code></td>
2102
+ </tr>
2103
+ <tr class="sbi_pro">
2104
+ <td>captionlength</td>
2105
+ <td><?php _e("The number of characters of the caption to display", 'instagram-feed'); ?></td>
2106
+ <td><code>[instagram-feed captionlength=50]</code></td>
2107
+ </tr>
2108
+ <tr class="sbi_pro">
2109
+ <td>captioncolor</td>
2110
+ <td><?php _e("The text color of the caption. Any hex color code.", 'instagram-feed'); ?></td>
2111
+ <td><code>[instagram-feed captioncolor=#000]</code></td>
2112
+ </tr>
2113
+ <tr class="sbi_pro">
2114
+ <td>captionsize</td>
2115
+ <td><?php _e("The size of the caption text. Any number.", 'instagram-feed'); ?></td>
2116
+ <td><code>[instagram-feed captionsize=24]</code></td>
2117
+ </tr>
2118
+
2119
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Likes &amp; Comments Options", 'instagram-feed'); ?></td></tr>
2120
+ <tr class="sbi_pro">
2121
+ <td>showlikes</td>
2122
+ <td><?php _e("Whether to show the Likes &amp; Comments. Options:", 'instagram-feed'); ?> 'true' or 'false'.</td>
2123
+ <td><code>[instagram-feed showlikes=false]</code></td>
2124
+ </tr>
2125
+ <tr class="sbi_pro">
2126
+ <td>likescolor</td>
2127
+ <td><?php _e("The color of the Likes &amp; Comments. Any hex color code.", 'instagram-feed'); ?></td>
2128
+ <td><code>[instagram-feed likescolor=#FF0000]</code></td>
2129
+ </tr>
2130
+ <tr class="sbi_pro">
2131
+ <td>likessize</td>
2132
+ <td><?php _e("The size of the Likes &amp; Comments. Any number.", 'instagram-feed'); ?></td>
2133
+ <td><code>[instagram-feed likessize=14]</code></td>
2134
+ </tr>
2135
+
2136
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Post Filtering Options", 'instagram-feed'); ?></td></tr>
2137
+ <tr class="sbi_pro">
2138
+ <td>excludewords</td>
2139
+ <td><?php _e("Remove posts which contain certain words or hashtags in the caption.", 'instagram-feed'); ?></td>
2140
+ <td><code>[instagram-feed excludewords="bad, words"]</code></td>
2141
+ </tr>
2142
+ <tr class="sbi_pro">
2143
+ <td>includewords</td>
2144
+ <td><?php _e("Only display posts which contain certain words or hashtags in the caption.", 'instagram-feed'); ?></td>
2145
+ <td><code>[instagram-feed includewords="sunshine"]</code></td>
2146
+ </tr>
2147
+
2148
+ <tr class="sbi_table_header"><td colspan=3><?php _e("Auto Load More on Scroll", 'instagram-feed'); ?></td></tr>
2149
+ <tr class="sbi_pro">
2150
+ <td>autoscroll</td>
2151
+ <td><?php _e("Load more posts automatically as the user scrolls down the page.", 'instagram-feed'); ?></td>
2152
+ <td><code>[instagram-feed autoscroll=true]</code></td>
2153
+ </tr>
2154
+ <tr class="sbi_pro">
2155
+ <td>autoscrolldistance</td>
2156
+ <td><?php _e("Distance before the end of feed or page that triggers the loading of more posts.", 'instagram-feed'); ?></td>
2157
+ <td><code>[instagram-feed autoscrolldistance=200]</code></td>
2158
+ </tr>
2159
+
2160
+ </tbody>
2161
+ </table>
2162
+
2163
+ <p><i class="fa fa-life-ring" aria-hidden="true"></i>&nbsp; <?php _e('Need help setting up the plugin? Check out our <a href="https://smashballoon.com/instagram-feed/free/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">setup directions</a>', 'instagram-feed'); ?></p>
2164
+
2165
+ <?php } //End Display tab ?>
2166
+
2167
+
2168
+ <?php if( $sbi_active_tab == 'support' ) { //Start Support tab ?>
2169
+
2170
+ <div class="sbi_support">
2171
+
2172
+ <br/>
2173
+ <h3 style="padding-bottom: 10px;"><?php _e("Need help?", 'instagram-feed'); ?></h3>
2174
+
2175
+ <p>
2176
+ <span class="sbi-support-title"><i class="fa fa-life-ring" aria-hidden="true"></i>&nbsp; <a
2177
+ href="https://smashballoon.com/instagram-feed/free/?utm_source=plugin-free&utm_campaign=sbi"
2178
+ target="_blank"><?php _e( 'Setup Directions', 'instagram-feed' ); ?></a></span>
2179
+ <?php _e( 'A step-by-step guide on how to setup and use the plugin.', 'instagram-feed' ); ?>
2180
+ </p>
2181
+
2182
+ <p>
2183
+ <span class="sbi-support-title"><i class="fa fa-youtube-play" aria-hidden="true"></i>&nbsp; <a
2184
+ href="https://www.youtube.com/embed/q6ZXVU4g970" target="_blank"
2185
+ id="sbi-play-support-video"><?php _e( 'Watch a Video', 'instagram-feed' ); ?></a></span>
2186
+ <?php _e( "Watch a short video demonstrating how to set up, customize and use the plugin.<br /><b>Please note</b> that the video shows the set up and use of the <b><a href='https://smashballoon.com/instagram-feed/?utm_source=plugin-free&utm_campaign=sbi' target='_blank'>Pro version</a></b> of the plugin, but the process is the same for this free version. The only difference is some of the features available.", 'instagram-feed' ); ?>
2187
+
2188
+ <iframe id="sbi-support-video"
2189
+ src="//www.youtube.com/embed/q6ZXVU4g970?theme=light&amp;showinfo=0&amp;controls=2" width="960"
2190
+ height="540" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
2191
+ </p>
2192
+
2193
+ <p>
2194
+ <span class="sbi-support-title"><i class="fa fa-question-circle" aria-hidden="true"></i>&nbsp; <a
2195
+ href="https://smashballoon.com/instagram-feed/support/faq/?utm_source=plugin-free&utm_campaign=sbi"
2196
+ target="_blank"><?php _e( 'FAQs and Docs', 'instagram-feed' ); ?></a></span>
2197
+ <?php _e( 'View our expansive library of FAQs and documentation to help solve your problem as quickly as possible.', 'instagram-feed' ); ?>
2198
+ </p>
2199
+
2200
+ <div class="sbi-support-faqs">
2201
+
2202
+ <ul>
2203
+ <li><b><?php _e( 'FAQs', 'instagram-feed' ); ?></b></li>
2204
+ <li>&bull;&nbsp; <?php _e( '<a href="https://smashballoon.com/my-photos-wont-load/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">My Instagram Feed Won\'t Load</a>', 'instagram-feed' ); ?></li>
2205
+ <li>&bull;&nbsp; <?php _e( '<a href="https://smashballoon.com/my-instagram-access-token-keep-expiring/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">My Access Token Keeps Expiring</a>', 'instagram-feed' ); ?></li>
2206
+ <li style="margin-top: 8px; font-size: 12px;"><a href="https://smashballoon.com/instagram-feed/support/faq/?utm_source=plugin-free&utm_campaign=sbi" target="_blank"><?php _e( 'See All', 'instagram-feed' ); ?><i class="fa fa-chevron-right" aria-hidden="true"></i></a></li>
2207
+ </ul>
2208
+
2209
+ <ul>
2210
+ <li><b><?php _e("Documentation", 'instagram-feed'); ?></b></li>
2211
+ <li>&bull;&nbsp; <?php _e( '<a href="https://smashballoon.com/instagram-feed/free?utm_source=plugin-free&utm_campaign=sbi" target="_blank">Installation and Configuration</a>', 'instagram-feed' ); ?></li>
2212
+ <li>&bull;&nbsp; <?php _e( '<a href="https://smashballoon.com/display-multiple-instagram-feeds/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">Displaying multiple feeds</a>', 'instagram-feed' ); ?></li>
2213
+ <li>&bull;&nbsp; <?php _e( '<a href="https://smashballoon.com/instagram-feed-faq/customization/?utm_source=plugin-free&utm_campaign=sbi" target="_blank">Customizing your Feed</a>', 'instagram-feed' ); ?></li>
2214
+ </ul>
2215
+ </div>
2216
+
2217
+ <p>
2218
+ <span class="sbi-support-title"><i class="fa fa-envelope" aria-hidden="true"></i>&nbsp; <a
2219
+ href="https://smashballoon.com/instagram-feed/support/?utm_source=plugin-free&utm_campaign=sbi"
2220
+ target="_blank"><?php _e( 'Request Support', 'instagram-feed' ); ?></a></span>
2221
+ <?php _e( 'Still need help? Submit a ticket and one of our support experts will get back to you as soon as possible.<br /><b>Important:</b> Please include your <b>System Info</b> below with all support requests.', 'instagram-feed' ); ?>
2222
+ </p>
2223
+ </div>
2224
+
2225
+ <hr />
2226
+
2227
+ <h3><?php _e('System Info &nbsp; <i style="color: #666; font-size: 11px; font-weight: normal;">Click the text below to select all</i>', 'instagram-feed'); ?></h3>
2228
+
2229
+
2230
+
2231
+
2232
+ <?php $sbi_options = get_option('sb_instagram_settings'); ?>
2233
+ <textarea readonly="readonly" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)." style="width: 100%; max-width: 960px; height: 500px; white-space: pre; font-family: Menlo,Monaco,monospace;">
2234
+ ## SITE/SERVER INFO: ##
2235
+ Site URL: <?php echo site_url() . "\n"; ?>
2236
+ Home URL: <?php echo home_url() . "\n"; ?>
2237
+ WordPress Version: <?php echo get_bloginfo( 'version' ) . "\n"; ?>
2238
+ PHP Version: <?php echo PHP_VERSION . "\n"; ?>
2239
+ Web Server Info: <?php echo $_SERVER['SERVER_SOFTWARE'] . "\n"; ?>
2240
+
2241
+ ## ACTIVE PLUGINS: ##
2242
+ <?php
2243
+ $plugins = get_plugins();
2244
+ $active_plugins = get_option( 'active_plugins', array() );
2245
+
2246
+ foreach ( $plugins as $plugin_path => $plugin ) {
2247
+ // If the plugin isn't active, don't show it.
2248
+ if ( ! in_array( $plugin_path, $active_plugins ) )
2249
+ continue;
2250
+
2251
+ echo $plugin['Name'] . ': ' . $plugin['Version'] ."\n";
2252
+ }
2253
+ ?>
2254
+
2255
+ ## PLUGIN SETTINGS: ##
2256
+ sb_instagram_plugin_type => Instagram Feed Free
2257
+ <?php
2258
+ foreach( $sbi_options as $key => $val ) {
2259
+ if ( is_array( $val ) ) {
2260
+ foreach ( $val as $item ) {
2261
+ if ( is_array( $item ) ) {
2262
+ foreach ( $item as $key2 => $val2 ) {
2263
+ echo esc_html( "$key2 => $val2" ) . "\n";
2264
+ }
2265
+ } else {
2266
+ echo esc_html( "$key => $item" ) . "\n";
2267
+ }
2268
+ }
2269
+ } else {
2270
+ echo esc_html( "$key => $val" ) . "\n";
2271
+ }
2272
+ }
2273
+ ?>
2274
+
2275
+ ##CACHES: ##
2276
+ <?php global $wpdb;
2277
+ $table_name = esc_sql( $wpdb->prefix . "options" );
2278
+ $result = $wpdb->get_results( "
2279
+ SELECT *
2280
+ FROM $table_name
2281
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
2282
+ LIMIT 1;
2283
+ ", ARRAY_A );
2284
+ if ( is_array($result) && count($result) > 0 ) {
2285
+ echo 'Most recent cache: ' . substr( $result[0]['option_value'], 0, 400 ) . "\n";
2286
+ } else {
2287
+ echo 'No feed caches found' . "\n";
2288
+ }
2289
+ ?>
2290
+
2291
+ ## API RESPONSE: ##
2292
+ <?php
2293
+ $con_accounts = isset( $sbi_options['connected_accounts'] ) ? $sbi_options['connected_accounts'] : array();
2294
+ $first_con_personal_account = array();
2295
+ $first_con_business_account = array();
2296
+
2297
+ if ( ! empty( $con_accounts ) ) {
2298
+ foreach ( $con_accounts as $account ) {
2299
+ $account_type = isset( $account['type'] ) && $account['type'] === 'business' ? 'business' : 'personal';
2300
+ if ( empty( $first_con_business_account ) && $account_type === 'business' ) {
2301
+ $first_con_business_account = $account;
2302
+ } elseif ( empty( $first_con_personal_account ) && $account_type === 'personal' ) {
2303
+ $first_con_personal_account = $account;
2304
+ }
2305
+ }
2306
+
2307
+ }
2308
+
2309
+ if ( ! empty( $first_con_personal_account ) ) {
2310
+ echo '*PERSONAL ACCOUNT*';
2311
+ echo "\n";
2312
+ $connection = new SB_Instagram_API_Connect( $first_con_personal_account, 'header' );
2313
+ $connection->connect();
2314
+ if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
2315
+ foreach ( $connection->get_data() as $key => $item ) {
2316
+ if ( is_array ( $item ) ) {
2317
+ foreach ( $item as $key2 => $item2 ) {
2318
+ echo $key2 . ' => ' . esc_html( $item2 ) . "\n";
2319
+ }
2320
+ } else {
2321
+ echo $key . ' => ' . esc_html( $item ) . "\n";
2322
+ }
2323
+ }
2324
+ } else {
2325
+ if ( $connection->is_wp_error() ) {
2326
+ $response = $connection->get_wp_error();
2327
+ if ( isset( $response ) && isset( $response->errors ) ) {
2328
+ foreach ( $response->errors as $key => $item ) {
2329
+ echo $key . ' => ' . $item[0] . "\n";
2330
+ }
2331
+ }
2332
+ } else {
2333
+ $error = $connection->get_data();
2334
+ var_export( $error );
2335
+ }
2336
+ }
2337
+ echo "\n";
2338
+ } else {
2339
+ echo 'no connected personal accounts';
2340
+ echo "\n";
2341
+ }
2342
+ if ( ! empty( $first_con_business_account ) ) {
2343
+ echo '*BUSINESS ACCOUNT*';
2344
+ echo "\n";
2345
+ $connection = new SB_Instagram_API_Connect( $first_con_business_account, 'header' );
2346
+ $connection->connect();
2347
+ if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
2348
+ foreach ( $connection->get_data() as $key => $item ) {
2349
+ if ( is_array ( $item ) ) {
2350
+ foreach ( $item as $key2 => $item2 ) {
2351
+ echo $key2 . ' => ' . esc_html( $item2 ) . "\n";
2352
+ }
2353
+ } else {
2354
+ echo $key . ' => ' . esc_html( $item ) . "\n";
2355
+ }
2356
+ }
2357
+ } else {
2358
+ if ( $connection->is_wp_error() ) {
2359
+ $response = $connection->get_wp_error();
2360
+ if ( isset( $response ) && isset( $response->errors ) ) {
2361
+ foreach ( $response->errors as $key => $item ) {
2362
+ echo $key . ' => ' . $item[0] . "\n";
2363
+ }
2364
+ }
2365
+ } else {
2366
+ $error = $connection->get_data();
2367
+ var_export( $error );
2368
+ }
2369
+ }
2370
+ echo "\n";
2371
+ } else {
2372
+ echo 'no connected business accounts';
2373
+ echo "\n";
2374
+ } ?>
2375
+ ## Cron Events: ##
2376
+ <?php
2377
+ $cron = _get_cron_array();
2378
+ foreach ( $cron as $key => $data ) {
2379
+ $is_target = false;
2380
+ foreach ( $data as $key2 => $val ) {
2381
+ if ( strpos( $key2, 'sbi' ) !== false ) {
2382
+ $is_target = true;
2383
+ echo $key2;
2384
+ echo "\n";
2385
+ }
2386
+ }
2387
+ if ( $is_target) {
2388
+ echo date( "Y-m-d H:i:s", $key );
2389
+ echo "\n";
2390
+ echo 'Next Scheduled: ' . ((int)$key - time())/60 . ' minutes';
2391
+ echo "\n\n";
2392
+ }
2393
+ }
2394
+ ?>
2395
+ ## Cron Cache Report: ##
2396
+ <?php $cron_report = get_option( 'sbi_cron_report', array() );
2397
+ if ( ! empty( $cron_report ) ) {
2398
+ var_export( $cron_report );
2399
+ }
2400
+ echo "\n";
2401
+ ?>
2402
+
2403
+ ## Resizing: ##
2404
+ <?php $upload = wp_upload_dir();
2405
+ $upload_dir = $upload['basedir'];
2406
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
2407
+ if ( file_exists( $upload_dir ) ) {
2408
+ echo 'upload directory exists';
2409
+ } else {
2410
+ $created = wp_mkdir_p( $upload_dir );
2411
+
2412
+ if ( ! $created ) {
2413
+ echo 'cannot create upload directory';
2414
+ }
2415
+ }
2416
+ echo "\n";
2417
+ echo "\n";
2418
+
2419
+ $table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE );
2420
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
2421
+
2422
+ if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
2423
+ echo 'no feeds posts table';
2424
+ echo "\n";
2425
+ } else {
2426
+ $last_result = $wpdb->get_results( "SELECT * FROM $feeds_posts_table_name LIMIT 1;" );
2427
+ if ( is_array( $last_result ) && isset( $last_result[0] ) ) {
2428
+ echo '*FEEDS POSTS TABLE*';
2429
+ echo "\n";
2430
+
2431
+ foreach ( $last_result as $column ) {
2432
+
2433
+ foreach ( $column as $key => $value ) {
2434
+ echo $key . ' => ' . esc_html( $value ) . "\n";;
2435
+ }
2436
+ }
2437
+
2438
+ } else {
2439
+ echo 'feeds posts has no rows';
2440
+ echo "\n";
2441
+ }
2442
+ }
2443
+ echo "\n";
2444
+
2445
+ if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
2446
+ echo 'no posts table';
2447
+ echo "\n";
2448
+
2449
+ } else {
2450
+ $last_result = $wpdb->get_results( "SELECT * FROM $table_name LIMIT 1;" );
2451
+ if ( is_array( $last_result ) && isset( $last_result[0] ) ) {
2452
+ echo '*POSTS TABLE*';
2453
+ echo "\n";
2454
+ foreach ( $last_result as $column ) {
2455
+
2456
+ foreach ( $column as $key => $value ) {
2457
+ echo $key . ' => ' . esc_html( $value ) . "\n";;
2458
+ }
2459
+ }
2460
+
2461
+ } else {
2462
+ echo 'feeds posts has no rows';
2463
+ echo "\n";
2464
+ }
2465
+ }
2466
+ ?>
2467
+
2468
+ ## Error Log: ##
2469
+ <?php
2470
+ global $sb_instagram_posts_manager;
2471
+ $errors = $sb_instagram_posts_manager->get_errors();
2472
+ if ( ! empty( $errors ) ) :
2473
+ foreach ( $errors as $type => $error ) :
2474
+ echo $type . ': ' . $error[1] . "\n";
2475
+ endforeach;
2476
+ endif;
2477
+ $ajax_statuses = $sb_instagram_posts_manager->get_ajax_status();
2478
+ if ( ! $ajax_statuses['successful'] ) {
2479
+ ## AJAX Status ##
2480
+ echo 'test not successful';
2481
+ }
2482
+ ?>
2483
+ </textarea>
2484
+ <div><input id="sbi_reset_log" class="button-secondary" type="submit" value="<?php esc_attr_e( 'Reset Error Log' ); ?>" style="vertical-align: middle;"/></div>
2485
+
2486
+ <?php
2487
+ } //End Support tab
2488
+ ?>
2489
+
2490
+
2491
+ <div class="sbi_quickstart">
2492
+ <h3><i class="fa fa-rocket" aria-hidden="true"></i>&nbsp; <?php _e('Display your feed', 'instagram-feed'); ?></h3>
2493
+ <p><?php _e('Copy and paste this shortcode directly into the page, post or widget where you\'d like to display the feed:', 'instagram-feed'); ?> <input type="text" value="[instagram-feed]" size="15" readonly="readonly" style="text-align: center;" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)."></p>
2494
+ <p><?php _e('Find out how to display <a href="?page=sb-instagram-feed&amp;tab=display">multiple feeds</a>.', 'instagram-feed'); ?></p>
2495
+ </div>
2496
+
2497
+ <a href="https://smashballoon.com/instagram-feed/demo/?utm_source=plugin-free&utm_campaign=sbi" target="_blank" class="sbi-pro-notice">
2498
+ <img src="<?php echo SBI_PLUGIN_URL . 'img/instagram-pro-promo.png?2019'; ?>" alt="<?php esc_attr_e( 'Instagram Feed Pro', 'instagram-feed' ); ?>">
2499
+ </a>
2500
+
2501
+ <p class="sbi_plugins_promo dashicons-before dashicons-admin-plugins"> <?php _e('Check out our other free plugins: <a href="https://wordpress.org/plugins/custom-facebook-feed/" target="_blank">Facebook</a> and <a href="https://wordpress.org/plugins/custom-twitter-feeds/" target="_blank">Twitter</a>.', 'instagram-feed' ); ?></p>
2502
+
2503
+ <div class="sbi_share_plugin">
2504
+ <h3><?php _e('Like the plugin? Help spread the word!', 'instagram-feed'); ?></h3>
2505
+
2506
+ <button id="sbi_admin_show_share_links" class="button secondary" style="margin-bottom: 1px;"><i class="fa fa-share-alt" aria-hidden="true"></i>&nbsp;&nbsp;Share the plugin</button> <div id="sbi_admin_share_links"></div>
2507
+ </div>
2508
+
2509
+ </div> <!-- end #sbi_admin -->
2510
+
2511
+ <?php } //End Settings page
inc/class-sb-instagram-api-connect.php ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_API_Connect
4
+ *
5
+ * Connect to the Instagram API and return the results. It's possible
6
+ * to build the url from a connected account (includes access token,
7
+ * account id, account type), endpoint and parameters (hashtag, etc..)
8
+ * as well as a full url such as from the pagination data from some Instagram API requests.
9
+ *
10
+ * Errors from either the Instagram API or from the HTTP request are detected
11
+ * and can be handled.
12
+ *
13
+ * Primarily used in the SB_Instagram_Feed class to collect posts and data for
14
+ * the header. Can also be used for comments in the Pro version
15
+ *
16
+ * @since 2.0/5.0
17
+ */
18
+
19
+ if ( ! defined( 'ABSPATH' ) ) {
20
+ die( '-1' );
21
+ }
22
+
23
+ class SB_Instagram_API_Connect
24
+ {
25
+ /**
26
+ * @var string
27
+ */
28
+ private $url;
29
+
30
+ /**
31
+ * @var object
32
+ */
33
+ private $response;
34
+
35
+ /**
36
+ * SB_Instagram_API_Connect constructor.
37
+ *
38
+ * @param mixed|array|string $connected_account_or_url either the connected account
39
+ * data for this request or the complete url for the request
40
+ * @param string $endpoint (optional) is optional only if the complete url is provided
41
+ * otherwise is they key for the endpoint needed for the request (ex. "header")
42
+ * @param array $params (optional) used with the connected account and endpoint to add
43
+ * additional query parameters to the url if needed
44
+ *
45
+ * @since 2.0/5.0
46
+ */
47
+ public function __construct( $connected_account_or_url, $endpoint = '', $params = array() ) {
48
+ if ( is_array( $connected_account_or_url ) && isset( $connected_account_or_url['access_token'] ) ) {
49
+ $this->set_url( $connected_account_or_url, $endpoint, $params );
50
+ } elseif ( strpos( $connected_account_or_url, 'https' ) !== false ) {
51
+ $this->url = $connected_account_or_url;
52
+ } else {
53
+ $this->url = '';
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Returns the response from Instagram
59
+ *
60
+ * @return object
61
+ *
62
+ * @since 2.0/5.0
63
+ */
64
+ public function get_data() {
65
+ if (!empty($this->response['data'])) {
66
+ return $this->response['data'];
67
+ } else {
68
+ return $this->response;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Returns the error response and the url that was trying to be connected to
74
+ * or false if no error
75
+ *
76
+ * @return array|bool
77
+ *
78
+ * @since 2.0/5.0
79
+ */
80
+ public function get_wp_error() {
81
+ if ( $this->is_wp_error() ) {
82
+ return array( 'response' => $this->response, 'url' => $this->url );
83
+ } else {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Returns the full url for the next page of the API request
90
+ *
91
+ * @return string
92
+ *
93
+ * @since 2.0/5.0
94
+ */
95
+ public function get_next_page() {
96
+ if ( ! empty( $this->response['pagination']['next_url'] ) ) {
97
+ return $this->response['pagination']['next_url'];
98
+ } elseif ( ! empty( $this->response['paging']['next'] ) ) {
99
+ return $this->response['paging']['next'];
100
+ } else {
101
+ return '';
102
+ }
103
+ }
104
+
105
+ /**
106
+ * If url needs to be generated from the connected account, endpoint,
107
+ * and params, this function is used to do so.
108
+ *
109
+ * @param $url
110
+ */
111
+ public function set_url_from_args( $url ) {
112
+ $this->url = $url;
113
+ }
114
+
115
+ /**
116
+ * @return string
117
+ *
118
+ * @since 2.0/5.0
119
+ */
120
+ public function get_url() {
121
+ return $this->url;
122
+ }
123
+
124
+ /**
125
+ * If the server is unable to connect to the url, returns true
126
+ *
127
+ * @return bool
128
+ *
129
+ * @since 2.0/5.0
130
+ */
131
+ public function is_wp_error() {
132
+ return is_wp_error( $this->response );
133
+ }
134
+
135
+ /**
136
+ * If the server can connect but Instagram returns an error, returns true
137
+ *
138
+ * @return bool
139
+ *
140
+ * @since 2.0/5.0
141
+ */
142
+ public function is_instagram_error() {
143
+ return (isset( $this->response['meta']['error_type'] ) || isset( $this->response['error']['message'] ));
144
+ }
145
+
146
+ /**
147
+ * Connect to the Instagram API and record the response
148
+ *
149
+ * @since 2.0/5.0
150
+ */
151
+ public function connect() {
152
+ $args = array(
153
+ 'timeout' => 60,
154
+ 'sslverify' => false
155
+ );
156
+ $response = wp_remote_get( $this->url, $args );
157
+
158
+ if ( ! is_wp_error( $response ) ) {
159
+ // certain ways of representing the html for double quotes causes errors so replaced here.
160
+ $response = json_decode( str_replace( '%22', '&rdquo;', $response['body'] ), true );
161
+ }
162
+
163
+ $this->response = $response;
164
+ }
165
+
166
+ /**
167
+ * Determines how and where to record an error from Instagram's API response
168
+ *
169
+ * @param array $response response from the API request
170
+ * @param array $error_connected_account the connected account that is associated
171
+ * with the error
172
+ * @param string $request_type key used to determine the endpoint (ex. "header")
173
+ *
174
+ * @since 2.0/5.0
175
+ */
176
+ public static function handle_instagram_error( $response, $error_connected_account, $request_type ) {
177
+ global $sb_instagram_posts_manager;
178
+
179
+ $error_time = 300;
180
+ if ( isset( $response['meta']['error_type'] ) ) {
181
+ if ( $response['meta']['error_type'] === 'OAuthAccessTokenException' ) {
182
+ $options = get_option( 'sb_instagram_settings', array() );
183
+
184
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
185
+ $user_name = '';
186
+ foreach ( $connected_accounts as $connected_account ) {
187
+ if ( $connected_account['access_token'] === $error_connected_account['access_token'] ) {
188
+ $connected_accounts[ $connected_account['user_id'] ]['is_valid'] = false;
189
+ $connected_accounts[ $connected_account['user_id'] ]['last_checked'] = time();
190
+ if ( isset( $connected_account['username'] ) ) {
191
+ $user_name = $connected_account['username'];
192
+ } else {
193
+ $user_name = $connected_account['user_id'];
194
+ }
195
+ }
196
+ }
197
+
198
+ $options['connected_accounts'] = $connected_accounts;
199
+
200
+ update_option( 'sb_instagram_settings', $options );
201
+
202
+ $error = '<p><b>' . sprintf( __( 'Error: Access Token for %s is not valid or has expired.', 'instagram-feed' ), $user_name ) . ' ' . __( 'Feed will not update.', 'instagram-feed' ) . '</b>';
203
+ $error .= '<p>' . __( 'There\'s an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin\'s Settings page.<br />If you continue to have an issue with your Access Token then please see <a href="https://smashballoon.com/my-instagram-access-token-keep-expiring/" target="_blank" rel="noopener">this FAQ</a> for more information.', 'instagram-feed' );
204
+
205
+ $sb_instagram_posts_manager->add_frontend_error( 'at_' . $user_name, $error );
206
+
207
+ $error_time = 3600;
208
+ $account_id = $error_connected_account['user_id'];
209
+ } else {
210
+ $error = $response['meta']['error_message'];
211
+
212
+ $sb_instagram_posts_manager->add_frontend_error( $response['meta']['error_type'], $error );
213
+ }
214
+ } elseif ( isset( $response['error']['message'] ) ) {
215
+ if ( (int)$response['error']['code'] === 18 ) {
216
+ $options = get_option( 'sb_instagram_settings', array() );
217
+
218
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
219
+ $user_name = '';
220
+ $hashtag_refresh_time = time() + (7*24*60*60);
221
+ foreach ( $connected_accounts as $connected_account ) {
222
+ if ( $connected_account['access_token'] === $error_connected_account['access_token'] ) {
223
+ if ( ! isset( $connected_accounts[ $connected_account['user_id'] ]['hashtag_limit_reached'] ) ) {
224
+ $connected_accounts[ $connected_account['user_id'] ]['hashtag_limit_reached'] = time();
225
+ } else {
226
+ $hashtag_refresh_time = $connected_accounts[ $connected_account['user_id'] ]['hashtag_limit_reached'];
227
+ }
228
+ if ( isset( $connected_account['username'] ) ) {
229
+ $user_name = $connected_account['username'];
230
+ } else {
231
+ $user_name = $connected_account['user_id'];
232
+ }
233
+ }
234
+ }
235
+
236
+ $options['connected_accounts'] = $connected_accounts;
237
+
238
+ update_option( 'sb_instagram_settings', $options );
239
+ $date_format = get_option( 'date_format' );
240
+ $time_format = get_option( 'time_format' );
241
+ if ( $date_format && $time_format ) {
242
+ $date_time_format = $date_format . ' ' . $time_format;
243
+ } else {
244
+ $date_time_format = 'F j, Y g:i a';
245
+ }
246
+ $error = '<p><b>' . sprintf( __( 'Error: Hashtag limit of 30 unique hashtags per week has been reached.', 'instagram-feed' ), $user_name ) . ' ' . sprintf( __( 'Feed may not display until %s.', 'instagram-feed' ), date_i18n( $date_time_format, $hashtag_refresh_time ) ) . '</b>';
247
+ $error .= '<p>' . __( 'If you need to display more than 30 hashtag feeds on your site, consider connecting an additional business account from a separate Instagram and Facebook account.', 'instagram-feed' );
248
+
249
+ $sb_instagram_posts_manager->add_frontend_error( 'hashtag_limit_reached', $error );
250
+
251
+ } else if ( $response['error']['type'] === 'OAuthException' ) {
252
+ if ( $response['error']['code'] === 24 ) {
253
+ $error = '<p><b>' . __( 'Error: Hashtag does not exist.', 'instagram-feed' ) .'</b>';
254
+ $error .= '<p>' . __( 'Please make a post that uses this hashtag to display this feed.', 'instagram-feed' );
255
+
256
+ $sb_instagram_posts_manager->add_frontend_error( 'hashtag_error', $error );
257
+ } else {
258
+ $options = get_option( 'sb_instagram_settings', array() );
259
+
260
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
261
+ $user_name = '';
262
+ foreach ( $connected_accounts as $connected_account ) {
263
+ if ( $connected_account['access_token'] === $error_connected_account['access_token'] ) {
264
+ $connected_accounts[ $connected_account['user_id'] ]['is_valid'] = false;
265
+ $connected_accounts[ $connected_account['user_id'] ]['last_checked'] = time();
266
+ if ( isset( $connected_account['username'] ) ) {
267
+ $user_name = $connected_account['username'];
268
+ } else {
269
+ $user_name = $connected_account['user_id'];
270
+ }
271
+ }
272
+ }
273
+
274
+ $options['connected_accounts'] = $connected_accounts;
275
+
276
+ update_option( 'sb_instagram_settings', $options );
277
+
278
+ $error = '<p><b>' . sprintf( __( 'Error: Access Token for %s is not valid or has expired.', 'instagram-feed' ), $user_name ) . ' ' . __( 'Feed will not update.', 'instagram-feed' ) . '</b>';
279
+ $error .= '<p>' . __( 'There\'s an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin\'s Settings page.', 'instagram-feed' );
280
+
281
+ $sb_instagram_posts_manager->add_frontend_error( 'at_' . $user_name, $error );
282
+
283
+ $error_time = 3600;
284
+ $account_id = $error_connected_account['user_id'];
285
+ }
286
+
287
+ } else {
288
+ $error = $response['error']['message'];
289
+
290
+ $sb_instagram_posts_manager->add_frontend_error( $response['error']['type'], $error );
291
+ }
292
+
293
+ }
294
+
295
+ if ( ! empty( $account_id ) ) {
296
+ $sb_instagram_posts_manager->add_api_request_delay( $error_time, $account_id );
297
+ } else {
298
+ $sb_instagram_posts_manager->add_api_request_delay( $error_time );
299
+ }
300
+
301
+ }
302
+
303
+ /**
304
+ * Determines how and where to record an error connecting to a specified url
305
+ *
306
+ * @param $response
307
+ *
308
+ * @since 2.0/5.0
309
+ */
310
+ public static function handle_wp_remote_get_error( $response ) {
311
+ global $sb_instagram_posts_manager;
312
+
313
+ $message = sprintf( __( 'Error connecting to %s.', 'instagram-feed' ), $response['url'] ). ' ';
314
+ if ( isset( $response['response'] ) && isset( $response['response']->errors ) ) {
315
+ foreach ( $response['response']->errors as $key => $item ) {
316
+ $message .= ' '.$key . ' - ' . $item[0] . ' |';
317
+ }
318
+ }
319
+
320
+ $sb_instagram_posts_manager->add_api_request_delay( 300 );
321
+
322
+ $sb_instagram_posts_manager->add_error( 'connection', array( 'Error connecting', $message ) );
323
+ }
324
+
325
+ /**
326
+ * Sets the url for the API request based on the account information,
327
+ * type of data needed, and additional parameters.
328
+ *
329
+ * Overwritten in the Pro version.
330
+ *
331
+ * @param array $connected_account connected account to be used in the request
332
+ * @param string $endpoint_slug header or user
333
+ * @param array $params additional params related to the request
334
+ *
335
+ * @since 2.0/5.0
336
+ */
337
+ protected function set_url( $connected_account, $endpoint_slug, $params ) {
338
+ $account_type = isset( $connected_account['type'] ) ? $connected_account['type'] : 'personal';
339
+ $num = ! empty( $params['num'] ) ? (int)$params['num'] : 33;
340
+
341
+ if ( $account_type === 'personal' ) {
342
+ if ( $endpoint_slug === 'header' ) {
343
+ $url = 'https://api.instagram.com/v1/users/' . $connected_account['user_id'] . '?access_token=' . sbi_maybe_clean( $connected_account['access_token'] );
344
+ } else {
345
+ $num = min( $num, 33 );
346
+ $url = 'https://api.instagram.com/v1/users/' . $connected_account['user_id'] . '/media/recent?count='.$num.'&access_token=' . sbi_maybe_clean( $connected_account['access_token'] );
347
+ }
348
+ } else {
349
+ if ( $endpoint_slug === 'header' ) {
350
+ $url = 'https://graph.facebook.com/' . $connected_account['user_id'] . '?fields=biography,id,username,website,followers_count,media_count,profile_picture_url,name&access_token=' . sbi_maybe_clean( $connected_account['access_token'] );
351
+ } else {
352
+ $num = min( $num, 200 );
353
+ $url = 'https://graph.facebook.com/' . $connected_account['user_id'] . '/media?fields=media_url,thumbnail_url,caption,id,media_type,timestamp,username,comments_count,like_count,permalink,children{media_url,id,media_type,timestamp,permalink,thumbnail_url}&limit='.$num.'&access_token=' . sbi_maybe_clean( $connected_account['access_token'] );
354
+ }
355
+ }
356
+
357
+ $this->set_url_from_args( $url );
358
+ }
359
+
360
+ }
inc/class-sb-instagram-cron-updater.php ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Cron_Updater
4
+ *
5
+ * Finds all regular feed transients saved in the database and updates
6
+ * each cached feed in the background using WP Cron. This is set up with the
7
+ * "sbi_cron_updater" function in the if-functions.php file. The "display_instagram"
8
+ * function will trigger a single feed update if no transient is found
9
+ * for the feed
10
+ *
11
+ * @since 2.0/5.0
12
+ */
13
+
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ die( '-1' );
16
+ }
17
+
18
+ class SB_Instagram_Cron_Updater
19
+ {
20
+ /**
21
+ * Find and loop through all feed cache transients and update the post and
22
+ * header caches
23
+ *
24
+ * Overwritten in the Pro version
25
+ *
26
+ * @since 2.0/5.0
27
+ */
28
+ public static function do_feed_updates() {
29
+ $feed_caches = SB_Instagram_Cron_Updater::get_feed_cache_option_names();
30
+ shuffle( $feed_caches );
31
+ $settings = sbi_get_database_settings();
32
+
33
+ // this is outputted in system info
34
+ $report = array(
35
+ 'notes' => array(
36
+ 'time_ran' => date( 'Y-m-d H:i:s' ),
37
+ 'num_found_transients' => count( $feed_caches )
38
+ )
39
+ );
40
+
41
+ foreach ( $feed_caches as $feed_cache ) {
42
+
43
+ $feed_id = str_replace( '_transient_', '', $feed_cache['option_name'] );
44
+ $report[ $feed_id ] = array();
45
+
46
+ $transient = get_transient( $feed_id );
47
+
48
+ if ( $transient ) {
49
+ $feed_data = json_decode( $transient, true );
50
+
51
+ // shortcode attributes are saved in order to recreate the feed is needed
52
+ $atts = isset( $feed_data['atts'] ) ? $feed_data['atts'] : false;
53
+ $last_retrieve = isset( $feed_data['last_retrieve'] ) ? (int)$feed_data['last_retrieve'] : 0;
54
+ // the last approximate time the feed was requested to be displayed on a page is recorded
55
+ // in order to stop updating feeds not in use.
56
+ $last_requested = isset( $feed_data['last_requested'] ) ? (int)$feed_data['last_requested'] : false;
57
+ $report[ $feed_id ]['last_retrieve'] = date( 'Y-m-d H:i:s', $last_retrieve );
58
+ if ( $atts !== false ) {
59
+
60
+ if ( ! $last_requested || $last_requested > (time() - 60*60*24*30) ) {
61
+ $instagram_feed_settings = new SB_Instagram_Settings( $atts, $settings );
62
+
63
+ if ( empty( $settings['connected_accounts'] ) && empty( $atts['accesstoken'] ) ) {
64
+ $report[ $feed_id ]['did_update'] = 'no - no connected account';
65
+ } else {
66
+ SB_Instagram_Cron_Updater::do_single_feed_cron_update( $instagram_feed_settings, $feed_data, $atts );
67
+
68
+ $report[ $feed_id ]['did_update'] = 'yes';
69
+ }
70
+ } else {
71
+ $report[ $feed_id ]['did_update'] = 'no - not recently requested';
72
+ }
73
+
74
+
75
+ } else {
76
+ $report[ $feed_id ]['did_update'] = 'no - missing atts';
77
+ }
78
+
79
+ } else {
80
+ $report[ $feed_id ]['did_update'] = 'no - no transient found';
81
+ }
82
+
83
+ }
84
+
85
+ update_option( 'sbi_cron_report', $report, false );
86
+ }
87
+
88
+ /**
89
+ * Update a single feed cache based on settings. Local image storing and
90
+ * resizing is done in the background here as well unless this is the initial
91
+ * time the feed is created and no cached data exists yet.
92
+ *
93
+ * Overwritten in the Pro version
94
+ *
95
+ * @param array $instagram_feed_settings associative array generated from
96
+ * the sb_instagram_settings class
97
+ * @param array $feed_data post, header, shortcode settings, and other info
98
+ * associated with the feed that is saved in the cache
99
+ * @param array $atts shortcode settings
100
+ * @param bool $include_resize whether or not to resize images during the update since
101
+ * images can also be resized with an ajax call when the feed is viewed on the frontend
102
+ *
103
+ * @since 2.0/5.0
104
+ */
105
+ public static function do_single_feed_cron_update( $instagram_feed_settings, $feed_data, $atts, $include_resize = true ) {
106
+ $instagram_feed_settings->set_feed_type_and_terms();
107
+ $instagram_feed_settings->set_transient_name();
108
+ $transient_name = $instagram_feed_settings->get_transient_name();
109
+ $settings = $instagram_feed_settings->get_settings();
110
+ $feed_type_and_terms = $instagram_feed_settings->get_feed_type_and_terms();
111
+
112
+ $instagram_feed = new SB_Instagram_Feed( $transient_name );
113
+
114
+ while ( $instagram_feed->need_posts( $settings['num'] ) && $instagram_feed->can_get_more_posts() ) {
115
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
116
+ }
117
+
118
+ $to_cache = array(
119
+ 'atts' => $atts,
120
+ 'last_requested' => $feed_data['last_requested'],
121
+ 'last_retrieve' => time()
122
+ );
123
+
124
+ $instagram_feed->set_cron_cache( $to_cache, $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
125
+
126
+ if ( $instagram_feed->need_header( $settings, $feed_type_and_terms ) ) {
127
+ $instagram_feed->set_remote_header_data( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
128
+
129
+ $instagram_feed->cache_header_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
130
+ }
131
+
132
+ if ( $include_resize ) {
133
+ $post_data = $instagram_feed->get_post_data();
134
+ $post_data = array_slice( $post_data, 0, $settings['num'] );
135
+
136
+ $post_set = new SB_Instagram_Post_Set( $post_data, $transient_name );
137
+
138
+ $post_set->maybe_save_update_and_resize_images_for_posts();
139
+ }
140
+
141
+ }
142
+
143
+ /**
144
+ * Retrieve option name column values for all feed cache transients
145
+ *
146
+ * @return array
147
+ *
148
+ * @since 2.0/5.0
149
+ */
150
+ public static function get_feed_cache_option_names() {
151
+ global $wpdb;
152
+ $feed_caches = array();
153
+
154
+ $results = $wpdb->get_results( "
155
+ SELECT option_name
156
+ FROM $wpdb->options
157
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
158
+ AND `option_name` NOT LIKE ('%\_transient\_sbi\_header%');", ARRAY_A );
159
+
160
+ if ( isset( $results[0] ) ) {
161
+ $feed_caches = $results;
162
+ }
163
+
164
+ return $feed_caches;
165
+ }
166
+
167
+ /**
168
+ * Start cron jobs based on user's settings for cron cache update frequency.
169
+ * This is triggered when settings are saved on the "Configure" tab.
170
+ *
171
+ * @param string $sbi_cache_cron_interval arbitrary name from one of the
172
+ * settings on the "Configure" tab
173
+ * @param string $sbi_cache_cron_time hour of the day (1 = 1:00)
174
+ * @param string $sbi_cache_cron_am_pm am or pm (time of day)
175
+ *
176
+ * @since 2.0/5.0
177
+ */
178
+ public static function start_cron_job( $sbi_cache_cron_interval, $sbi_cache_cron_time, $sbi_cache_cron_am_pm ) {
179
+ wp_clear_scheduled_hook( 'sbi_feed_update' );
180
+
181
+ if ( $sbi_cache_cron_interval === '12hours' || $sbi_cache_cron_interval === '24hours' ) {
182
+ $relative_time_now = time() + sbi_get_utc_offset();
183
+ $base_day = strtotime( date( 'Y-m-d', $relative_time_now ) );
184
+ $add_time = $sbi_cache_cron_am_pm === 'pm' ? (int)$sbi_cache_cron_time + 12 : (int)$sbi_cache_cron_time;
185
+ $utc_start_time = $base_day + (($add_time * 60 * 60) - sbi_get_utc_offset());
186
+
187
+ if ( $utc_start_time < time() ) {
188
+ if ( $sbi_cache_cron_interval === '12hours' ) {
189
+ $utc_start_time += 60*60*12;
190
+ } else {
191
+ $utc_start_time += 60*60*24;
192
+ }
193
+ }
194
+
195
+ if ( $sbi_cache_cron_interval === '12hours' ) {
196
+ wp_schedule_event( $utc_start_time, 'twicedaily', 'sbi_feed_update' );
197
+ } else {
198
+ wp_schedule_event( $utc_start_time, 'daily', 'sbi_feed_update' );
199
+ }
200
+
201
+ } else {
202
+
203
+ if ( $sbi_cache_cron_interval === '30mins' ) {
204
+ wp_schedule_event( time(), 'sbi30mins', 'sbi_feed_update' );
205
+ } else {
206
+ wp_schedule_event( time(), 'hourly', 'sbi_feed_update' );
207
+ }
208
+ }
209
+
210
+ }
211
+
212
+ }
inc/class-sb-instagram-display-elements.php ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Display_Elements
4
+ *
5
+ * Used to make certain parts of the html in the feed templates
6
+ * abstract.
7
+ *
8
+ * @since 2.0/5.0
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ die( '-1' );
13
+ }
14
+
15
+ class SB_Instagram_Display_Elements
16
+ {
17
+ /**
18
+ * Images are hidden initially with the new/transition classes
19
+ * except if the js image loading is disabled using the plugin
20
+ * settings
21
+ *
22
+ * @param $settings
23
+ *
24
+ * @return string
25
+ *
26
+ * @since 2.0/5.0
27
+ */
28
+ public static function get_item_classes( $settings ) {
29
+ if ( !$settings['disable_js_image_loading'] ) {
30
+ return ' sbi_new sbi_transition';
31
+ } else {
32
+ return ' sbi_no_js';
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Overwritten in the Pro version.
38
+ *
39
+ * @param string $type key of the kind of icon needed
40
+ * @param string $icon_type svg or font
41
+ *
42
+ * @return string the complete html for the icon
43
+ *
44
+ * @since 2.0/5.0
45
+ */
46
+ public static function get_icon( $type, $icon_type ) {
47
+ return self::get_basic_icons( $type, $icon_type );
48
+ }
49
+
50
+ /**
51
+ * Returns the best media url for an image based on settings.
52
+ * By default a white placeholder image is loaded and replaced
53
+ * with the most optimal image size based on the actual dimensions
54
+ * of the image element in the feed.
55
+ *
56
+ * @param array $post data for an individual post
57
+ * @param array $settings
58
+ * @param array $resized_images (optional) not yet used but
59
+ * can pass in existing resized images to use in the source
60
+ *
61
+ * @return string
62
+ *
63
+ * @since 2.0/5.0
64
+ */
65
+ public static function get_optimum_media_url( $post, $settings, $resized_images = array() ) {
66
+ $media_url = '';
67
+ $optimum_res = $settings['imageres'];
68
+ $account_type = isset( $post['images'] ) ? 'personal' : 'business';
69
+
70
+ // only use the placeholder if it will be replaced using JS
71
+ if ( !$settings['disable_js_image_loading'] ) {
72
+ return trailingslashit( SBI_PLUGIN_URL ) . 'img/placeholder.png';
73
+ } elseif ( $settings['imageres'] === 'auto' ) {
74
+ $optimum_res = 'full';
75
+ $settings['imageres'] = 'full';
76
+ }
77
+
78
+ if ( $account_type === 'personal' ) {
79
+ switch ( $optimum_res ) {
80
+ case 'thumb' :
81
+ $media_url = $post['images']['thumbnail']['url'];
82
+ break;
83
+ case 'medium' :
84
+ $media_url = $post['images']['low_resolution']['url'];
85
+ break;
86
+ default :
87
+ $media_url = $post['images']['standard_resolution']['url'];
88
+ }
89
+ } else {
90
+ $post_id = SB_Instagram_Parse::get_post_id( $post );
91
+
92
+ // use resized images if exists
93
+ if ( $optimum_res === 'full' && isset( $resized_images[ $post_id ]['id'] ) && $resized_images[ $post_id ]['id'] !== 'pending' && $resized_images[ $post_id ]['id'] !== 'video' ) {
94
+ $media_url = 'uploads_dir' . $resized_images[ $post_id ]['id'] . 'full.jpg';
95
+ } else {
96
+ $permalink = SB_Instagram_Parse::get_permalink( $post );
97
+ if ( substr_count( $permalink, '/' ) > 5 ) {
98
+ $permalink_array = explode( '/', $permalink );
99
+ $perm_id = $permalink_array[ count( $permalink_array ) - 2 ];
100
+ $permalink = 'https://www.instagram.com/p/' . $perm_id . '/';
101
+ }
102
+
103
+ if ( ($post['media_type'] === 'CAROUSEL_ALBUM' || $post['media_type'] === 'VIDEO') && ($optimum_res === 'lightbox' || $optimum_res === 'full')) {
104
+ $media_url = $permalink . 'media?size=l';
105
+ } else {
106
+ switch ($optimum_res) {
107
+ case 'thumb' :
108
+ $media_url = $permalink . 'media?size=t';
109
+ break;
110
+ case 'medium' :
111
+ $media_url = $permalink . 'media?size=m';
112
+ break;
113
+ default :
114
+ $media_url = $post['media_url'];
115
+ }
116
+ }
117
+ }
118
+
119
+ }
120
+
121
+ return $media_url;
122
+ }
123
+
124
+ /**
125
+ * Images are normally styles with the imgLiquid plugin
126
+ * with JavaScript. If this is disabled, the plugin will
127
+ * attempt to square all images using CSS.
128
+ *
129
+ * @param array $post
130
+ * @param array $settings
131
+ *
132
+ * @return string
133
+ *
134
+ * @since 2.0/5.0
135
+ */
136
+ public static function get_sbi_photo_style_element( $post, $settings ) {
137
+ if ( !$settings['disable_js_image_loading'] ) {
138
+ return '';
139
+ } else {
140
+ $full_res_image = SB_Instagram_Display_Elements::get_optimum_media_url( $post, $settings );
141
+ /*
142
+ * By setting the height to "0" the bottom padding can be used
143
+ * as a percent to square the images. Since it needs to be a percent
144
+ * this guesses what the percent would be based on static padding.
145
+ */
146
+ $padding_bottom = '100%';
147
+ if ( $settings['imagepaddingunit'] === '%' ) {
148
+ $padding_bottom = 100 - ($settings['imagepadding'] * 2) . '%';
149
+ } else {
150
+ $padding_percent = $settings['imagepadding'] > 0 ? 100 - ($settings['cols'] / 2 * $settings['imagepadding'] / 5) : 100;
151
+ $padding_bottom = $padding_percent . '%';
152
+ }
153
+ return ' style="background-image: url(&quot;' . esc_url( $full_res_image ) . '&quot;); background-size: cover; background-position: center center; background-repeat: no-repeat; opacity: 1;height: 0;padding-bottom: ' . esc_attr( $padding_bottom ) . ';"';
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Creates a style attribute that contains all of the styles for
159
+ * the main feed div.
160
+ *
161
+ * @param $settings
162
+ *
163
+ * @return string
164
+ */
165
+ public static function get_feed_style( $settings ) {
166
+
167
+ $styles = '';
168
+ if ( ! empty( $settings['imagepadding'] )
169
+ || ! empty( $settings['background'] )
170
+ || ! empty( $settings['width'] )
171
+ || ! empty( $settings['height'] ) ) {
172
+ $styles = ' style="';
173
+ if ( ! empty( $settings['imagepadding'] ) ) {
174
+ $styles .= 'padding-bottom: ' . ((int)$settings['imagepadding'] * 2) . esc_attr( $settings['imagepaddingunit'] ) . ';';
175
+ }
176
+ if ( ! empty( $settings['background'] ) ) {
177
+ $styles .= 'background-color: rgb(' . esc_attr( sbi_hextorgb( $settings['background'] ) ). ');';
178
+ }
179
+ if ( ! empty( $settings['width'] ) ) {
180
+ $styles .= 'width: ' . (int)$settings['width'] . esc_attr( $settings['widthunit'] ) . ';';
181
+ }
182
+ if ( ! empty( $settings['height'] ) ) {
183
+ $styles .= 'height: ' . (int)$settings['height'] . esc_attr( $settings['heightunit'] ) . ';';
184
+ }
185
+ $styles .= '"';
186
+ }
187
+ return $styles;
188
+ }
189
+
190
+ /**
191
+ * Creates a style attribute for the sbi_images div
192
+ *
193
+ * @param $settings
194
+ *
195
+ * @return string
196
+ */
197
+ public static function get_sbi_images_style( $settings ) {
198
+ if ( ! empty ( $settings['imagepadding'] ) ) {
199
+ return 'style="padding: '.(int)$settings['imagepadding'] . esc_attr( $settings['imagepaddingunit'] ) . ';"';
200
+ }
201
+ return '';
202
+ }
203
+
204
+ /**
205
+ * Creates a style attribute for the header. Can be used in
206
+ * several places based on the header style
207
+ *
208
+ * @param $settings
209
+ *
210
+ * @return string
211
+ */
212
+ public static function get_header_text_color_styles( $settings ) {
213
+ if ( ! empty( $settings['headercolor'] ) ) {
214
+ return 'style="color: rgb(' . esc_attr( sbi_hextorgb( $settings['headercolor'] ) ). ');"';
215
+ }
216
+ return '';
217
+ }
218
+
219
+ /**
220
+ * Creates a style attribute for the follow button. Can be in
221
+ * the feed footer or in a boxed header.
222
+ *
223
+ * @param $settings
224
+ *
225
+ * @return string
226
+ */
227
+ public static function get_follow_styles( $settings ) {
228
+ $styles = '';
229
+ if ( ! empty( $settings['followcolor'] ) || ! empty( $settings['followtextcolor'] ) ) {
230
+ $styles = 'style="';
231
+ if ( ! empty( $settings['followcolor'] ) ) {
232
+ $styles .= 'background: rgb(' . esc_attr( sbi_hextorgb( $settings['followcolor'] ) ) . ');';
233
+ }
234
+ if ( ! empty( $settings['followtextcolor'] ) ) {
235
+ $styles .= 'color: rgb(' . esc_attr( sbi_hextorgb( $settings['followtextcolor'] ) ). ');';
236
+ }
237
+ $styles .= '"';
238
+ }
239
+ return $styles;
240
+ }
241
+
242
+ /**
243
+ * Creates a style attribute for styling the load more button.
244
+ *
245
+ * @param $settings
246
+ *
247
+ * @return string
248
+ */
249
+ public static function get_load_button_styles( $settings ) {
250
+ $styles = '';
251
+ if ( ! empty( $settings['buttoncolor'] ) || ! empty( $settings['buttontextcolor'] ) ) {
252
+ $styles = 'style="';
253
+ if ( ! empty( $settings['buttoncolor'] ) ) {
254
+ $styles .= 'background: rgb(' . esc_attr( sbi_hextorgb( $settings['buttoncolor'] ) ) . ');';
255
+ }
256
+ if ( ! empty( $settings['buttontextcolor'] ) ) {
257
+ $styles .= 'color: rgb(' . esc_attr( sbi_hextorgb( $settings['buttontextcolor'] ) ). ');';
258
+ }
259
+ $styles .= '"';
260
+ }
261
+ return $styles;
262
+ }
263
+
264
+ /**
265
+ * Returns the html for an icon based on the kind requested
266
+ *
267
+ * @param string $type kind of icon needed (ex "video" is a play button
268
+ * @param string $icon_type svg or font
269
+ *
270
+ * @return string
271
+ *
272
+ * @since 2.0/5.0
273
+ */
274
+ protected static function get_basic_icons( $type, $icon_type ) {
275
+ if ( $type === 'carousel' ) {
276
+ if ( $icon_type === 'svg' ) {
277
+ return '<svg class="svg-inline--fa fa-clone fa-w-16 sbi_lightbox_carousel_icon" aria-hidden="true" data-fa-proƒcessed="" data-prefix="far" data-icon="clone" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
278
+ <path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path>
279
+ </svg>';
280
+ } else {
281
+ return '<i class="fa fa-clone sbi_carousel_icon" aria-hidden="true"></i>';
282
+ }
283
+
284
+ } elseif ( $type === 'video' ) {
285
+ if ( $icon_type === 'svg' ) {
286
+ return '<svg style="color: rgba(255,255,255,1)" class="svg-inline--fa fa-play fa-w-14 sbi_playbtn" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="play" role="presentation" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"></path></svg>';
287
+ } else {
288
+ return '<i class="fa fa-play sbi_playbtn" aria-hidden="true"></i>';
289
+ }
290
+ } elseif ( $type === 'instagram' ) {
291
+ if ( $icon_type === 'svg' ) {
292
+ return '<svg class="svg-inline--fa fa-instagram fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="instagram" role="img" viewBox="0 0 448 512">
293
+ <path fill="currentColor" d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"></path>
294
+ </svg>';
295
+ } else {
296
+ return '<i class="fa fab fa-instagram" aria-hidden="true"></i>';
297
+ }
298
+ } elseif ( $type === 'newlogo' ) {
299
+ if ( $icon_type === 'svg' ) {
300
+ return '<svg class="sbi_new_logo fa-instagram fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="instagram" role="img" viewBox="0 0 448 512">
301
+ <path fill="currentColor" d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"></path>
302
+ </svg>';
303
+ } else {
304
+ return '<i class="sbi_new_logo"></i>';
305
+ }
306
+ } else {
307
+ return '';
308
+ }
309
+ }
310
+
311
+ }
inc/class-sb-instagram-feed.php ADDED
@@ -0,0 +1,1281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Feed
4
+ *
5
+ * Retrieves data and generates the html for each feed. The
6
+ * "display_instagram" function in the if-functions.php file
7
+ * is where this class is primarily used.
8
+ *
9
+ * @since 2.0/4.0
10
+ */
11
+
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ die( '-1' );
14
+ }
15
+
16
+ class SB_Instagram_Feed
17
+ {
18
+ /**
19
+ * @var string
20
+ */
21
+ private $regular_feed_transient_name;
22
+
23
+ /**
24
+ * @var string
25
+ */
26
+ private $header_transient_name;
27
+
28
+ /**
29
+ * @var string
30
+ */
31
+ private $backup_feed_transient_name;
32
+
33
+ /**
34
+ * @var string
35
+ */
36
+ private $backup_header_transient_name;
37
+
38
+ /**
39
+ * @var array
40
+ */
41
+ private $post_data;
42
+
43
+ /**
44
+ * @var
45
+ */
46
+ private $header_data;
47
+
48
+ /**
49
+ * @var array
50
+ */
51
+ private $next_pages;
52
+
53
+ /**
54
+ * @var array
55
+ */
56
+ private $transient_atts;
57
+
58
+ /**
59
+ * @var int
60
+ */
61
+ private $last_retrieve;
62
+
63
+ /**
64
+ * @var bool
65
+ */
66
+ private $should_paginate;
67
+
68
+ /**
69
+ * @var int
70
+ */
71
+ private $num_api_calls;
72
+
73
+ /**
74
+ * @var array
75
+ */
76
+ private $image_ids_post_set;
77
+
78
+ /**
79
+ * @var bool
80
+ */
81
+ private $should_use_backup;
82
+
83
+ /**
84
+ * @var array
85
+ */
86
+ private $report;
87
+
88
+ /**
89
+ * SB_Instagram_Feed constructor.
90
+ *
91
+ * @param string $transient_name ID of this feed
92
+ * generated in the SB_Instagram_Settings class
93
+ */
94
+ public function __construct( $transient_name ) {
95
+ $this->regular_feed_transient_name = $transient_name;
96
+ $this->backup_feed_transient_name = SBI_BACKUP_PREFIX . $transient_name;
97
+
98
+ $sbi_header_transient_name = str_replace( 'sbi_', 'sbi_header_', $transient_name );
99
+ $sbi_header_transient_name = substr($sbi_header_transient_name, 0, 44);
100
+ $this->header_transient_name = $sbi_header_transient_name;
101
+ $this->backup_header_transient_name = SBI_BACKUP_PREFIX . $sbi_header_transient_name;
102
+
103
+ $this->post_data = array();
104
+ $this->next_pages = array();
105
+ $this->should_paginate = true;
106
+
107
+ // this is a count of how many api calls have been made for each feed
108
+ // type and term.
109
+ // By default the limit is 10
110
+ $this->num_api_calls = 0;
111
+ $this->max_api_calls = apply_filters( 'sbi_max_concurrent_api_calls', 10 );
112
+ $this->should_use_backup = false;
113
+
114
+ // used for errors and the sbi_debug report
115
+ $this->report = array();
116
+ }
117
+
118
+ /**
119
+ * @return array
120
+ *
121
+ * @since 2.0/5.0
122
+ */
123
+ public function get_post_data() {
124
+ return $this->post_data;
125
+ }
126
+
127
+ /**
128
+ * @return array
129
+ *
130
+ * @since 2.0/5.0
131
+ */
132
+ public function set_post_data( $post_data ) {
133
+ $this->post_data = $post_data;
134
+ }
135
+
136
+ /**
137
+ * @return array
138
+ *
139
+ * @since 2.0/5.0
140
+ */
141
+ public function get_next_pages() {
142
+ return $this->next_pages;
143
+ }
144
+
145
+ /**
146
+ * Checks the database option related the transient expiration
147
+ * to ensure it will be available when the page loads
148
+ *
149
+ * @return bool
150
+ *
151
+ * @since 2.0/4.0
152
+ */
153
+ public function regular_cache_exists() {
154
+ //Check whether the cache transient exists in the database and is available for more than one more minute
155
+ $transient_exists = get_transient( $this->regular_feed_transient_name );
156
+
157
+ return $transient_exists;
158
+ }
159
+
160
+ /**
161
+ * Checks the database option related the header transient
162
+ * expiration to ensure it will be available when the page loads
163
+ *
164
+ * @return bool
165
+ *
166
+ * @since 2.0/5.0
167
+ */
168
+ public function regular_header_cache_exists() {
169
+ $header_transient = get_transient( $this->header_transient_name );
170
+
171
+ return $header_transient;
172
+ }
173
+
174
+ /**
175
+ * @return bool
176
+ *
177
+ * @since 2.0/5.0
178
+ */
179
+ public function should_use_backup() {
180
+ return $this->should_use_backup;
181
+ }
182
+
183
+ /**
184
+ * The header is only displayed when the setting is enabled and
185
+ * an account has been connected
186
+ *
187
+ * @param array $settings settings specific to this feed
188
+ * @param array $feed_types_and_terms organized settings related to feed data
189
+ * (ex. 'user' => array( 'smashballoon', 'custominstagramfeed' )
190
+ *
191
+ * @return bool
192
+ *
193
+ * @since 2.0/5.0
194
+ */
195
+ public function need_header( $settings, $feed_types_and_terms ) {
196
+ $showheader = ($settings['showheader'] === 'on' || $settings['showheader'] === 'true' || $settings['showheader'] === true);
197
+ return ($showheader && isset( $feed_types_and_terms['users'] ));
198
+ }
199
+
200
+ /**
201
+ * Use the transient name to retrieve cached data for header
202
+ *
203
+ * @since 2.0/5.0
204
+ */
205
+ public function set_header_data_from_cache() {
206
+ $header_cache = get_transient( $this->header_transient_name );
207
+
208
+ $header_cache = json_decode( $header_cache, true );
209
+
210
+ if ( ! empty( $header_cache ) ) {
211
+ $this->header_data = $header_cache;
212
+ }
213
+ }
214
+
215
+ public function set_header_data( $header_data ) {
216
+ $this->header_data = $header_data;
217
+ }
218
+
219
+ /**
220
+ * @since 2.0/5.0
221
+ */
222
+ public function get_header_data() {
223
+ return $this->header_data;
224
+ }
225
+
226
+ /**
227
+ * Sets the post data, pagination data, shortcode atts used (cron cache),
228
+ * and timestamp of last retrieval from transient (cron cache)
229
+ *
230
+ * @param array $atts available for cron caching
231
+ *
232
+ * @since 2.0/5.0
233
+ */
234
+ public function set_post_data_from_cache( $atts = array() ) {
235
+ $transient_data = get_transient( $this->regular_feed_transient_name );
236
+
237
+ $transient_data = json_decode( $transient_data, true );
238
+
239
+ if ( $transient_data ) {
240
+ $post_data = isset( $transient_data['data'] ) ? $transient_data['data'] : array();
241
+ $this->post_data = $post_data;
242
+ $this->next_pages = isset( $transient_data['pagination'] ) ? $transient_data['pagination'] : array();
243
+
244
+ if ( isset( $transient_data['atts'] ) ) {
245
+ $this->transient_atts = $transient_data['atts'];
246
+ $this->last_retrieve = $transient_data['last_retrieve'];
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Sets post data from a permanent database backup of feed
253
+ * if it was created
254
+ *
255
+ * @since 2.0/5.0
256
+ * @since 2.0/5.1.2 if backup feed data used, header data also set from backup
257
+ */
258
+ public function maybe_set_post_data_from_backup() {
259
+ $backup_data = get_option( $this->backup_feed_transient_name, false );
260
+
261
+ if ( $backup_data ) {
262
+ $backup_data = json_decode( $backup_data, true );
263
+
264
+ $post_data = isset( $backup_data['data'] ) ? $backup_data['data'] : array();
265
+ $this->post_data = $post_data;
266
+ $this->next_pages = isset( $backup_data['pagination'] ) ? $backup_data['pagination'] : array();
267
+
268
+ if ( isset( $backup_data['atts'] ) ) {
269
+ $this->transient_atts = $backup_data['atts'];
270
+ $this->last_retrieve = $backup_data['last_retrieve'];
271
+ }
272
+
273
+ $this->maybe_set_header_data_from_backup();
274
+
275
+ return true;
276
+ } else {
277
+ $this->add_report( 'no backup post data found' );
278
+
279
+ return false;
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Sets header data from a permanent database backup of feed
285
+ * if it was created
286
+ *
287
+ * @since 2.0/5.0
288
+ */
289
+ public function maybe_set_header_data_from_backup() {
290
+ $backup_header_data = get_option( $this->backup_header_transient_name, false );
291
+
292
+ if ( ! empty( $backup_header_data ) ) {
293
+ $backup_header_data = json_decode( $backup_header_data, true );
294
+ $this->header_data = $backup_header_data;
295
+
296
+ return true;
297
+ } else {
298
+ $this->add_report( 'no backup header data found' );
299
+
300
+ return false;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Returns recorded image IDs for this post set
306
+ * for use with image resizing
307
+ *
308
+ * @return array
309
+ *
310
+ * @since 2.0/5.0
311
+ */
312
+ public function get_image_ids_post_set() {
313
+ return $this->image_ids_post_set;
314
+ }
315
+
316
+ /**
317
+ * Retrieves data related to resized images from custom
318
+ * tables using either a number, offset, and transient name
319
+ * or the ids of the posts.
320
+ *
321
+ * Retrieving by offset and transient name not used currently
322
+ * but may be needed in future updates.
323
+ *
324
+ * @param array/int $num_or_array_of_ids post ids from the Instagram
325
+ * API
326
+ * @param int $offset number of records to skip
327
+ * @param string $transient_name ID of the feed
328
+ *
329
+ * @return array
330
+ *
331
+ * @since 2.0/5.0
332
+ */
333
+ public static function get_resized_images_source_set( $num_or_array_of_ids, $offset = 0, $transient_name = '' ) {
334
+ global $sb_instagram_posts_manager;
335
+
336
+ if ( $sb_instagram_posts_manager->image_resizing_disabled() ) {
337
+ return array();
338
+ }
339
+
340
+ global $wpdb;
341
+
342
+ $posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
343
+ $feeds_posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
344
+
345
+ $feed_id_array = explode( '#', $transient_name );
346
+ $feed_id = $feed_id_array[0];
347
+
348
+ if ( is_array( $num_or_array_of_ids ) ) {
349
+ $ids = $num_or_array_of_ids;
350
+
351
+ $id_string = '"' . implode( '","', $ids ) . '"';
352
+ $results = $wpdb->get_results( "
353
+ SELECT p.media_id, p.instagram_id, p.aspect_ratio, p.sizes
354
+ FROM $posts_table_name AS p
355
+ INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
356
+ AND p.instagram_id IN($id_string)
357
+ AND p.images_done = 1", ARRAY_A );
358
+
359
+ $return = array();
360
+ if ( !empty( $results ) && is_array( $results ) ) {
361
+
362
+ foreach ( $results as $result ) {
363
+ $sizes = maybe_unserialize( $result['sizes'] );
364
+ if ( ! is_array( $sizes ) ) {
365
+ $sizes = array( 'full' => 640 );
366
+ }
367
+ $return[ $result['instagram_id'] ] = array(
368
+ 'id' => $result['media_id'],
369
+ 'ratio' => $result['aspect_ratio'],
370
+ 'sizes' => $sizes
371
+ );
372
+ }
373
+
374
+ }
375
+ } else {
376
+ $num = $num_or_array_of_ids;
377
+
378
+ $results = $wpdb->get_results( $wpdb->prepare( "
379
+ SELECT p.media_id, p.instagram_id, p.aspect_ratio, p.sizes
380
+ FROM $posts_table_name AS p
381
+ INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
382
+ WHERE f.feed_id = %s
383
+ AND p.images_done = 1
384
+ ORDER BY p.time_stamp
385
+ DESC LIMIT %d, %d", $feed_id, $offset, (int)$num ), ARRAY_A );
386
+
387
+ $return = array();
388
+ if ( !empty( $results ) && is_array( $results ) ) {
389
+
390
+ foreach ( $results as $result ) {
391
+ $sizes = maybe_unserialize( $result['sizes'] );
392
+ if ( ! is_array( $sizes ) ) {
393
+ $sizes = array( 'full' => 640 );
394
+ }
395
+ $return[ $result['instagram_id'] ] = array(
396
+ 'id' => $result['media_id'],
397
+ 'ratio' => $result['aspect_ratio'],
398
+ 'sizes' => $sizes
399
+ );
400
+ }
401
+
402
+ }
403
+ }
404
+
405
+
406
+ return $return;
407
+ }
408
+
409
+ public static function update_last_requested( $array_of_ids ) {
410
+ if ( empty( $array_of_ids ) ) {
411
+ return;
412
+ }
413
+
414
+ global $wpdb;
415
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
416
+ $id_string = "'" . implode( "','", $array_of_ids ) . "'";
417
+
418
+ $query = $wpdb->query( $wpdb->prepare( "UPDATE $table_name
419
+ SET last_requested = %s
420
+ WHERE instagram_id IN ({$id_string});", date( 'Y-m-d H:i:s' ) ) );
421
+ }
422
+
423
+ /**
424
+ * Cron caching needs additional data saved in the transient
425
+ * to work properly. This function checks to make sure it's present
426
+ *
427
+ * @return bool
428
+ *
429
+ * @since 2.0/5.0
430
+ */
431
+ public function need_to_start_cron_job() {
432
+ return (( ! empty( $this->post_data ) && ! isset( $this->transient_atts )) || empty( $this->post_data ));
433
+ }
434
+
435
+ /**
436
+ * Checks to see if there are enough posts available to create
437
+ * the current page of the feed
438
+ *
439
+ * @param int $num
440
+ * @param int $offset
441
+ *
442
+ * @return bool
443
+ *
444
+ * @since 2.0/5.0
445
+ */
446
+ public function need_posts( $num, $offset = 0 ) {
447
+ $num_existing_posts = is_array( $this->post_data ) ? count( $this->post_data ) : 0;
448
+ $num_needed_for_page = (int)$num + (int)$offset;
449
+
450
+ ($num_existing_posts < $num_needed_for_page) ? $this->add_report( 'need more posts' ) : $this->add_report( 'have enough posts' );
451
+
452
+ return ($num_existing_posts < $num_needed_for_page);
453
+ }
454
+
455
+ /**
456
+ * Checks to see if there are additional pages available for any of the
457
+ * accounts in the feed and that the max conccurrent api request limit
458
+ * has not been reached
459
+ *
460
+ * @return bool
461
+ *
462
+ * @since 2.0/5.0
463
+ */
464
+ public function can_get_more_posts() {
465
+ $one_type_and_term_has_more_ages = $this->next_pages !== false;
466
+ $max_concurrent_api_calls_not_met = $this->num_api_calls < $this->max_api_calls;
467
+ $max_concurrent_api_calls_not_met ? $this->add_report( 'max conccurrent requests not met' ) : $this->add_report( 'max concurrent met' );
468
+ $one_type_and_term_has_more_ages ? $this->add_report( 'more pages available' ) : $this->add_report( 'no next page' );
469
+
470
+ return ($one_type_and_term_has_more_ages && $max_concurrent_api_calls_not_met);
471
+ }
472
+
473
+ /**
474
+ * Appends one filtered API request worth of posts for each feed term
475
+ *
476
+ * @param $settings
477
+ * @param array $feed_types_and_terms organized settings related to feed data
478
+ * (ex. 'user' => array( 'smashballoon', 'custominstagramfeed' )
479
+ * @param array $connected_accounts_for_feed connected account data for the
480
+ * feed types and terms
481
+ *
482
+ * @since 2.0/5.0
483
+ * @since 2.0/5.1 added logic to make a second attempt at an API connection
484
+ * @since 2.0/5.1.2 remote posts only retrieved if API requests are not
485
+ * delayed, terms shuffled if there are more than 5
486
+ */
487
+ public function add_remote_posts( $settings, $feed_types_and_terms, $connected_accounts_for_feed ) {
488
+ $new_post_sets = array();
489
+ $next_pages = $this->next_pages;
490
+ global $sb_instagram_posts_manager;
491
+
492
+ $num = apply_filters( 'sbi_num_in_request', $settings['minnum'], $settings );
493
+
494
+ $params = array(
495
+ 'num' => $num
496
+ );
497
+
498
+ $one_successful_connection = false;
499
+ $next_page_found = false;
500
+
501
+ foreach ( $feed_types_and_terms as $type => $terms ) {
502
+ if ( is_array( $terms ) && count( $terms ) > 5 ) {
503
+ shuffle( $terms );
504
+ }
505
+ foreach ( $terms as $term_and_params ) {
506
+ $term = $term_and_params['term'];
507
+ $params = array_merge( $params, $term_and_params['params'] );
508
+ $connected_account_for_term = $connected_accounts_for_feed[ $term ];
509
+
510
+ $api_requests_delayed = $sb_instagram_posts_manager->are_current_api_request_delays( $connected_account_for_term['user_id'] );
511
+
512
+ if ( ! $api_requests_delayed
513
+ && (! isset( $next_pages[ $term . '_' . $type ] ) || $next_pages[ $term . '_' . $type ] !== false) ) {
514
+ if ( ! empty( $next_pages[ $term . '_' . $type ] ) ) {
515
+ $connection = $this->make_api_connection( $next_pages[ $term . '_' . $type ] );
516
+ } else {
517
+ $connection = $this->make_api_connection( $connected_account_for_term, $type, $params );
518
+ }
519
+ $this->add_report( 'api call made for ' . $term . ' - ' . $type );
520
+
521
+ $connection->connect();
522
+ $this->num_api_calls++;
523
+
524
+ if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
525
+ $one_successful_connection = true;
526
+
527
+ $data = $connection->get_data();
528
+
529
+ if ( !$connected_account_for_term['is_valid'] ) {
530
+ $this->add_report( 'clearing invalid token' );
531
+ $this->clear_expired_access_token_notice( $connected_account_for_term );
532
+ }
533
+
534
+ if ( isset( $data[0]['id'] ) ) {
535
+ $post_set = $this->filter_posts( $data, $settings );
536
+
537
+ $new_post_sets[] = $post_set;
538
+ }
539
+
540
+ $next_page = $connection->get_next_page();
541
+ if ( ! empty( $next_page ) ) {
542
+ $next_pages[ $term . '_' . $type ] = $next_page;
543
+ $next_page_found = true;
544
+ } else {
545
+ $next_pages[ $term . '_' . $type ] = false;
546
+ }
547
+ } else {
548
+
549
+ if ( $this->can_try_another_request( $type, $connected_accounts_for_feed[ $term ] ) ) {
550
+ $this->add_report( 'trying other accounts' );
551
+ $i = 0;
552
+ $attempted = array( $connected_accounts_for_feed[ $term ]['user_id'] );
553
+ $success = false;
554
+ $different = true;
555
+ $error = false;
556
+
557
+ while ( $different
558
+ && ! $success
559
+ && $this->can_try_another_request( $type, $connected_accounts_for_feed[ $term ], $i ) ) {
560
+ $different = $this->get_different_connected_account( $type, $attempted );
561
+ $this->add_report( 'trying the account ' . $different['user_id'] );
562
+
563
+ if ( $different ) {
564
+ $connected_accounts_for_feed[ $term ] = $this->get_different_connected_account( $type, $attempted );
565
+ $attempted[] = $connected_accounts_for_feed[ $term ]['user_id'];
566
+ if ( ! empty( $next_pages[ $term . '_' . $type ] ) ) {
567
+ $connection = $this->make_api_connection( $next_pages[ $term . '_' . $type ] );
568
+ } else {
569
+ $connection = $this->make_api_connection( $connected_accounts_for_feed[ $term ], $type, $params );
570
+ }
571
+ $connection->connect();
572
+ $this->num_api_calls++;
573
+ if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
574
+ $one_successful_connection = true;
575
+ $data = $connection->get_data();
576
+ if ( isset( $data[0]['id'] ) ) {
577
+ $post_set = $this->filter_posts( $data, $settings );
578
+ $new_post_sets[] = $post_set;
579
+ }
580
+ $next_page = $connection->get_next_page();
581
+ if ( ! empty( $next_page ) ) {
582
+ $next_pages[ $term . '_' . $type ] = $next_page;
583
+ $next_page_found = true;
584
+ } else {
585
+ $next_pages[ $term . '_' . $type ] = false;
586
+ }
587
+ } else {
588
+ if ( $connection->is_wp_error() ) {
589
+ $error = $connection->get_wp_error();
590
+ } else {
591
+ $error = $connection->get_data();
592
+ }
593
+ }
594
+ $i++;
595
+ }
596
+ }
597
+
598
+ if ( ! $success && $error ) {
599
+ if ( is_wp_error( $error ) ) {
600
+ SB_Instagram_API_Connect::handle_wp_remote_get_error( $error );
601
+ } else {
602
+ SB_Instagram_API_Connect::handle_instagram_error( $error, $connected_accounts_for_feed[ $term ], $type );
603
+ }
604
+ $next_pages[ $term . '_' . $type ] = false;
605
+ }
606
+ } else {
607
+
608
+ if ( $connection->is_wp_error() ) {
609
+ SB_Instagram_API_Connect::handle_wp_remote_get_error( $connection->get_wp_error() );
610
+ } else {
611
+ SB_Instagram_API_Connect::handle_instagram_error( $connection->get_data(), $connected_accounts_for_feed[ $term ], $type );
612
+ }
613
+
614
+ $next_pages[ $term . '_' . $type ] = false;
615
+ }
616
+ }
617
+ } elseif ( $api_requests_delayed ) {
618
+ $this->add_report( 'delaying API request for ' . $term . ' - ' . $type );
619
+
620
+ $error = '<p><b>' . sprintf( __( 'Error: API requests are being delayed for this account.', 'instagram-feed' ), $connected_account_for_term['username'] ) . ' ' . __( 'New posts will not be retrieved.', 'instagram-feed' ) . '</b>';
621
+ $error .= '<p>' . __( 'There may be an issue with the Instagram Access Token that you are using. Your server might also be unable to connect to Instagram at this time.', 'instagram-feed' );
622
+
623
+ $sb_instagram_posts_manager->add_frontend_error( 'at_' . $connected_account_for_term['username'], $error );
624
+ }
625
+
626
+ }
627
+ }
628
+
629
+ if ( ! $one_successful_connection ) {
630
+ $this->should_use_backup = true;
631
+ }
632
+ $posts = $this->merge_posts( $new_post_sets, $settings );
633
+
634
+ $posts = $this->sort_posts( $posts, $settings );
635
+
636
+ if ( ! empty( $this->post_data ) && is_array( $this->post_data ) ) {
637
+ $posts = array_merge( $this->post_data, $posts );
638
+ }
639
+
640
+ $this->post_data = $posts;
641
+
642
+ if ( isset( $next_page_found ) && $next_page_found ) {
643
+ $this->next_pages = $next_pages;
644
+ } else {
645
+ $this->next_pages = false;
646
+ }
647
+ }
648
+
649
+ /**
650
+ * Connects to the Instagram API and records returned data
651
+ *
652
+ * @param $settings
653
+ * @param array $feed_types_and_terms organized settings related to feed data
654
+ * (ex. 'user' => array( 'smashballoon', 'custominstagramfeed' )
655
+ * @param array $connected_accounts_for_feed connected account data for the
656
+ * feed types and terms
657
+ *
658
+ * @since 2.0/5.0
659
+ */
660
+ public function set_remote_header_data( $settings, $feed_types_and_terms, $connected_accounts_for_feed ) {
661
+ $first_user = isset( $feed_types_and_terms['users'][0] ) ? $feed_types_and_terms['users'][0]['term'] : '';
662
+ $this->header_data = false;
663
+
664
+ if ( isset( $connected_accounts_for_feed[ $first_user ] ) ) {
665
+ $connection = new SB_Instagram_API_Connect( $connected_accounts_for_feed[ $first_user ], 'header', array() );
666
+
667
+ $connection->connect();
668
+
669
+ if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
670
+ $this->header_data = $connection->get_data();
671
+
672
+ if ( isset( $connected_accounts_for_feed[ $first_user ]['local_avatar'] ) && $connected_accounts_for_feed[ $first_user ]['local_avatar'] ) {
673
+ $upload = wp_upload_dir();
674
+ $resized_url = trailingslashit( $upload['baseurl'] ) . trailingslashit( SBI_UPLOADS_NAME );
675
+
676
+ $full_file_name = $resized_url . $this->header_data['username'] . '.jpg';
677
+ $this->header_data['local_avatar'] = $full_file_name;
678
+ }
679
+ } else {
680
+ if ( $connection->is_wp_error() ) {
681
+ SB_Instagram_API_Connect::handle_wp_remote_get_error( $connection->get_wp_error() );
682
+ } else {
683
+ SB_Instagram_API_Connect::handle_instagram_error( $connection->get_data(), $connected_accounts_for_feed[ $first_user ], 'header' );
684
+ }
685
+ }
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Stores feed data in a transient for a specified time
691
+ *
692
+ * @param int $cache_time
693
+ * @param bool $save_backup
694
+ *
695
+ * @since 2.0/5.0
696
+ * @since 2.0/5.1 duplicate posts removed
697
+ */
698
+ public function cache_feed_data( $cache_time, $save_backup = true ) {
699
+ if ( ! empty( $this->post_data ) || ! empty( $this->next_pages ) ) {
700
+ $this->remove_duplicate_posts();
701
+ $this->trim_posts_to_max();
702
+
703
+ $to_cache = array(
704
+ 'data' => $this->post_data,
705
+ 'pagination' => $this->next_pages
706
+ );
707
+
708
+ set_transient( $this->regular_feed_transient_name, wp_json_encode( $to_cache ), $cache_time );
709
+
710
+ if ( $save_backup ) {
711
+ update_option( $this->backup_feed_transient_name, wp_json_encode( $to_cache ), false );
712
+ }
713
+ } else {
714
+ $this->add_report( 'no data not caching' );
715
+ }
716
+ }
717
+
718
+ /**
719
+ * Stores feed data with additional data specifically for cron caching
720
+ *
721
+ * @param array $to_cache feed data with additional things like the shortcode
722
+ * settings, when the cache was last requested, when new posts were last retrieved
723
+ * @param int $cache_time how long the cache will last
724
+ * @param bool $save_backup whether or not to also save this as a permanent cache
725
+ *
726
+ * @since 2.0/5.0
727
+ * @since 2.0/5.1 duplicate posts removed, cache set trimmed to a maximum
728
+ */
729
+ public function set_cron_cache( $to_cache, $cache_time, $save_backup = true ) {
730
+ $this->remove_duplicate_posts();
731
+ $this->trim_posts_to_max();
732
+
733
+ $to_cache['data'] = isset( $to_cache['data'] ) ? $to_cache['data'] : $this->post_data;
734
+ $to_cache['pagination'] = isset( $to_cache['next_pages'] ) ? $to_cache['next_pages'] : $this->next_pages;
735
+ $to_cache['atts'] = isset( $to_cache['atts'] ) ? $to_cache['atts'] : $this->transient_atts;
736
+ $to_cache['last_requested'] = isset( $to_cache['last_requested'] ) ? $to_cache['last_requested'] : time();
737
+ $to_cache['last_retrieve'] = isset( $to_cache['last_retrieve'] ) ? $to_cache['last_retrieve'] : $this->last_retrieve;
738
+
739
+ set_transient( $this->regular_feed_transient_name, wp_json_encode( $to_cache ), $cache_time );
740
+
741
+ if ( $save_backup ) {
742
+ update_option( $this->backup_feed_transient_name, wp_json_encode( $to_cache ), false );
743
+ }
744
+ }
745
+
746
+ /**
747
+ * Stores header data for a specified time as a transient
748
+ *
749
+ * @param int $cache_time
750
+ * @param bool $save_backup
751
+ *
752
+ * @since 2.0/5.0
753
+ */
754
+ public function cache_header_data( $cache_time, $save_backup = true ) {
755
+ if ( $this->header_data ) {
756
+ set_transient( $this->header_transient_name, wp_json_encode( $this->header_data ), $cache_time );
757
+
758
+ if ( $save_backup ) {
759
+ update_option( $this->backup_header_transient_name, wp_json_encode( $this->header_data ), false );
760
+ }
761
+ }
762
+ }
763
+
764
+ /**
765
+ * Used to randomly trigger an updating of the last requested data for cron caching
766
+ *
767
+ * @return bool
768
+ *
769
+ * @since 2.0/5.0
770
+ */
771
+ public function should_update_last_requested() {
772
+ return (rand( 1, 20 ) === 20);
773
+ }
774
+
775
+ /**
776
+ * Determines if pagination can and should be used based on settings and available feed data
777
+ *
778
+ * @param array $settings
779
+ * @param int $offset
780
+ *
781
+ * @return bool
782
+ *
783
+ * @since 2.0/5.0
784
+ */
785
+ public function should_use_pagination( $settings, $offset = 0 ) {
786
+ $posts_available = count( $this->post_data ) - ($offset + $settings['num']);
787
+ $show_loadmore_button_by_settings = ($settings['showbutton'] == 'on' || $settings['showbutton'] == 'true' || $settings['showbutton'] == true ) && $settings['showbutton'] !== 'false';
788
+
789
+ if ( $show_loadmore_button_by_settings ) {
790
+ // used for permanent and whitelist feeds
791
+ if ( $this->feed_is_complete( $settings, $offset ) ) {
792
+ $this->add_report( 'no pagination, feed complete' );
793
+ return false;
794
+ }
795
+ if ( $posts_available > 0 ) {
796
+ $this->add_report( 'do pagination, posts available' );
797
+ return true;
798
+ }
799
+ $pages = $this->next_pages;
800
+
801
+ if ( $pages && ! $this->should_use_backup() ) {
802
+ foreach ( $pages as $page ) {
803
+ if ( ! empty( $page ) ) {
804
+ return true;
805
+ }
806
+ }
807
+ }
808
+
809
+ }
810
+
811
+
812
+ $this->add_report( 'no pagination, no posts available' );
813
+
814
+ return false;
815
+ }
816
+
817
+ /**
818
+ * Generates the HTML for the feed if post data is available. Although it seems
819
+ * some of the variables ar not used they are set here to hide where they
820
+ * come from when used in the feed templates.
821
+ *
822
+ * @param array $settings
823
+ * @param array $atts
824
+ * @param array $feed_types_and_terms organized settings related to feed data
825
+ * (ex. 'user' => array( 'smashballoon', 'custominstagramfeed' )
826
+ * @param array $connected_accounts_for_feed connected account data for the
827
+ * feed types and terms
828
+ *
829
+ * @return false|string
830
+ *
831
+ * @since 2.0/5.0
832
+ */
833
+ public function get_the_feed_html( $settings, $atts, $feed_types_and_terms, $connected_accounts_for_feed ) {
834
+ global $sb_instagram_posts_manager;
835
+
836
+ if ( empty( $this->post_data ) && ! empty( $connected_accounts_for_feed ) ) {
837
+ $error = '<p><b>' . __( 'Error: No posts found.', 'instagram-feed' ) . '</b>';
838
+ $error .= '<p>' . __( 'Make sure this account has posts available on instagram.com.', 'instagram-feed' ) . '</p>';
839
+
840
+ $sb_instagram_posts_manager->add_frontend_error( 'noposts', $error );
841
+ }
842
+ $posts = array_slice( $this->post_data, 0, $settings['minnum'] );
843
+ $header_data = ! empty( $this->header_data ) ? $this->header_data : false;
844
+
845
+ $first_user = ! empty( $feed_types_and_terms['users'][0] ) ? $feed_types_and_terms['users'][0]['term'] : false;
846
+ $first_username = false;
847
+ if ( $first_user ) {
848
+ $first_username = isset( $connected_accounts_for_feed[ $first_user ]['username'] ) ? $connected_accounts_for_feed[ $first_user ]['username'] : $first_user;
849
+ }
850
+ $use_pagination = $this->should_use_pagination( $settings, 0 );
851
+
852
+ $feed_id = $this->regular_feed_transient_name;
853
+ $shortcode_atts = ! empty( $atts ) ? wp_json_encode( $atts ) : '{}';
854
+
855
+ $settings['header_outside'] = false;
856
+ $settings['header_inside'] = false;
857
+ if ( $header_data && $settings['showheader'] ) {
858
+ $settings['header_inside'] = true;
859
+ }
860
+
861
+ $other_atts = '';
862
+
863
+ $classes = array();
864
+ if ( empty( $settings['widthresp'] ) || $settings['widthresp'] == 'on' || $settings['widthresp'] == 'true' || $settings['widthresp'] === true ) {
865
+ if ( $settings['widthresp'] !== 'false' ) {
866
+ $classes[] = 'sbi_width_resp';
867
+ }
868
+ }
869
+ if ( ! empty( $settings['class'] ) ) {
870
+ $classes[] = esc_attr( $settings['class'] );
871
+ }
872
+ if ( ! empty( $settings['height'] )
873
+ && (((int)$settings['height'] < 100 && $settings['heightunit'] === '%') || $settings['heightunit'] === 'px') ) {
874
+ $classes[] = 'sbi_fixed_height';
875
+ }
876
+ if ( ! empty( $settings['disablemobile'] )
877
+ && ($settings['disablemobile'] == 'on' || $settings['disablemobile'] == 'true' || $settings['disablemobile'] == true) ) {
878
+ if ( $settings['disablemobile'] !== 'false' ) {
879
+ $classes[] = 'sbi_disable_mobile';
880
+ }
881
+ }
882
+
883
+ $additional_classes = '';
884
+ if ( ! empty( $classes ) ) {
885
+ $additional_classes = ' ' . implode( ' ', $classes );
886
+ }
887
+
888
+ $other_atts = $this->add_other_atts( $other_atts, $settings );
889
+
890
+ $flags = array();
891
+
892
+ if ( $settings['disable_resize'] ) {
893
+ $flags[] = 'resizeDisable';
894
+ } elseif ( $settings['favor_local'] ) {
895
+ $flags[] = 'favorLocal';
896
+ }
897
+
898
+ if ( $settings['disable_js_image_loading'] ) {
899
+ $flags[] = 'imageLoadDisable';
900
+ }
901
+ if ( $settings['ajax_post_load'] ) {
902
+ $flags[] = 'ajaxPostLoad';
903
+ }
904
+ if ( isset( $_GET['sbi_debug'] ) ) {
905
+ $flags[] = 'debug';
906
+ }
907
+
908
+ $ajax_test_status = $sb_instagram_posts_manager->get_ajax_status();
909
+
910
+ if ( $sb_instagram_posts_manager->maybe_start_ajax_test() && ! $ajax_test_status['successful'] ) {
911
+ $flags[] = 'testAjax';
912
+ } elseif ( $sb_instagram_posts_manager->should_add_ajax_test_notice() ) {
913
+ $error = '<p><b>' . __( 'Error: admin-ajax.php test was not successful. Some features may not be available.', 'instagram-feed' ) . '</b>';
914
+ $error .= '<p>' . __( sprintf( 'Please visit %s to troubleshoot.', '<a href="https://smashballoon.com/admin-ajax-requests-are-not-working/">'.__( 'this page', 'instagram-feed' ).'</a>' ), 'instagram-feed' ) . '</p>';
915
+
916
+ $sb_instagram_posts_manager->add_frontend_error( 'ajax', $error );
917
+ }
918
+
919
+ if ( ! empty( $flags ) ) {
920
+ $other_atts .= ' data-sbi-flags="' . implode(',', $flags ) . '"';
921
+ }
922
+
923
+ ob_start();
924
+ include sbi_get_feed_template_part( 'feed', $settings );
925
+ $html = ob_get_contents();
926
+ ob_get_clean();
927
+
928
+ if ( $settings['ajaxtheme'] ) {
929
+ $html .= $this->get_ajax_page_load_html();
930
+ }
931
+
932
+ return $html;
933
+ }
934
+
935
+ /**
936
+ * Additional options/settings added to the main div
937
+ * for the feed
938
+ *
939
+ * Overwritten in the Pro version
940
+ *
941
+ * @param $other_atts
942
+ * @param $settings
943
+ *
944
+ * @return string
945
+ */
946
+ protected function add_other_atts( $other_atts, $settings ) {
947
+ return '';
948
+ }
949
+
950
+ /**
951
+ * Generates HTML for individual sbi_item elements
952
+ *
953
+ * @param array $settings
954
+ * @param int $offset
955
+ * @param array $feed_types_and_terms organized settings related to feed data
956
+ * (ex. 'user' => array( 'smashballoon', 'custominstagramfeed' )
957
+ * @param array $connected_accounts_for_feed connected account data for the
958
+ * feed types and terms
959
+ *
960
+ * @return false|string
961
+ *
962
+ * @since 2.0/5.0
963
+ */
964
+ public function get_the_items_html( $settings, $offset, $feed_types_and_terms, $connected_accounts_for_feed ) {
965
+ if ( empty( $this->post_data ) ) {
966
+ ob_start();
967
+ $html = ob_get_contents();
968
+ ob_get_clean(); ?>
969
+ <p><?php _e( 'No posts found.', 'instagram-feed' ); ?></p>
970
+ <?php
971
+ $html = ob_get_contents();
972
+ ob_get_clean();
973
+ return $html;
974
+ }
975
+
976
+ $posts = array_slice( $this->post_data, $offset, $settings['num'] );
977
+
978
+ ob_start();
979
+
980
+ $this->posts_loop( $posts, $settings, $offset );
981
+
982
+ $html = ob_get_contents();
983
+ ob_get_clean();
984
+
985
+ return $html;
986
+ }
987
+
988
+ /**
989
+ * Overwritten in the Pro version
990
+ *
991
+ * @return object
992
+ */
993
+ public function make_api_connection( $connected_account_or_page, $type = NULL, $params = NULL ) {
994
+ return new SB_Instagram_API_Connect( $connected_account_or_page, $type, $params );
995
+ }
996
+
997
+ /**
998
+ * When the feed is loaded with AJAX, the JavaScript for the plugin
999
+ * needs to be triggered again. This function is a workaround that adds
1000
+ * the file and settings to the page whenever the feed is generated.
1001
+ *
1002
+ * @return string
1003
+ *
1004
+ * @since 2.0/5.0
1005
+ */
1006
+ public static function get_ajax_page_load_html() {
1007
+ $sbi_options = sbi_get_database_settings();
1008
+ $font_method = isset( $sbi_options['sbi_font_method'] ) ? $sbi_options['sbi_font_method'] : 'svg';
1009
+ $upload = wp_upload_dir();
1010
+ $resized_url = trailingslashit( $upload['baseurl'] ) . trailingslashit( SBI_UPLOADS_NAME );
1011
+
1012
+ $js_options = array(
1013
+ 'font_method' => $font_method,
1014
+ 'placeholder' => trailingslashit( SBI_PLUGIN_URL ) . 'img/placeholder.png',
1015
+ 'resized_url' => $resized_url
1016
+ );
1017
+
1018
+ $encoded_options = wp_json_encode( $js_options );
1019
+
1020
+ $js_option_html = '<script type="text/javascript">var sb_instagram_js_options = ' . $encoded_options . ';</script>';
1021
+ $js_option_html .= "<script type='text/javascript' src='" . trailingslashit( SBI_PLUGIN_URL ) . 'js/sb-instagram.min.js?ver=' . SBIVER . "'></script>";
1022
+
1023
+ return $js_option_html;
1024
+ }
1025
+
1026
+ /**
1027
+ * Adds recorded strings to an array
1028
+ *
1029
+ * @param $to_add
1030
+ *
1031
+ * @since 2.0/5.0
1032
+ */
1033
+ public function add_report( $to_add ) {
1034
+ $this->report[] = $to_add;
1035
+ }
1036
+
1037
+ /**
1038
+ * @return array
1039
+ *
1040
+ * @since 2.0/5.0
1041
+ */
1042
+ public function get_report() {
1043
+ return $this->report;
1044
+ }
1045
+
1046
+ /**
1047
+ * Used for filtering a single API request worth of posts
1048
+ *
1049
+ * Overwritten in the Pro version
1050
+ *
1051
+ * @param array $post_set a single set of post data from the api
1052
+ *
1053
+ * @return mixed|array
1054
+ *
1055
+ * @since 2.0/5.0
1056
+ */
1057
+ protected function filter_posts( $post_set, $settings = array() ) {
1058
+ // array_unique( $post_set, SORT_REGULAR);
1059
+
1060
+ return $post_set;
1061
+ }
1062
+
1063
+ protected function remove_duplicate_posts() {
1064
+ $posts = $this->post_data;
1065
+ $ids_in_feed = array();
1066
+ $non_duplicate_posts = array();
1067
+ $removed = array();
1068
+
1069
+ foreach ( $posts as $post ) {
1070
+ $post_id = SB_Instagram_Parse::get_post_id( $post );
1071
+ if ( ! in_array( $post_id, $ids_in_feed, true ) ) {
1072
+ $ids_in_feed[] = $post_id;
1073
+ $non_duplicate_posts[] = $post;
1074
+ } else {
1075
+ $removed[] = $post_id;
1076
+ }
1077
+ }
1078
+
1079
+ $this->add_report( 'removed duplicates: ' . implode(', ', $removed ) );
1080
+ $this->set_post_data( $non_duplicate_posts );
1081
+ }
1082
+
1083
+ /**
1084
+ * Used for limiting the cache size
1085
+ *
1086
+ * @since 2.0/5.1.1
1087
+ */
1088
+ protected function trim_posts_to_max() {
1089
+ if ( ! is_array( $this->post_data ) ) {
1090
+ return;
1091
+ }
1092
+
1093
+ $max = apply_filters( 'sbi_max_cache_size', 500 );
1094
+ $this->set_post_data( array_slice( $this->post_data , 0, $max ) );
1095
+
1096
+ }
1097
+
1098
+ /**
1099
+ * Used for permanent feeds or white list feeds to
1100
+ * stop pagination if all posts are already added
1101
+ *
1102
+ * Overwritten in the Pro version
1103
+ *
1104
+ * @param array $settings
1105
+ * @param int $offset
1106
+ *
1107
+ * @return bool
1108
+ *
1109
+ * @since 2.0/5.0
1110
+ */
1111
+ protected function feed_is_complete( $settings, $offset = 0 ) {
1112
+ return false;
1113
+ }
1114
+
1115
+ /**
1116
+ * @param $connected_account_for_term
1117
+ *
1118
+ * @since 2.0/5.1.2
1119
+ */
1120
+ private function clear_expired_access_token_notice( $connected_account_for_term ) {
1121
+ $sbi_options = get_option( 'sb_instagram_settings' );
1122
+ $ca_to_save = isset( $sbi_options['connected_accounts'] ) ? $sbi_options['connected_accounts'] : array();
1123
+
1124
+ if ( ! empty( $ca_to_save ) && ! empty( $connected_account_for_term ) ) {
1125
+
1126
+ foreach ( $ca_to_save as $account ) {
1127
+ if ( $connected_account_for_term['access_token'] === $account['access_token'] ) {
1128
+ $ca_to_save[ $account['user_id'] ]['is_valid'] = true;
1129
+ }
1130
+ }
1131
+
1132
+ $sbi_options['connected_accounts'] = $ca_to_save;
1133
+
1134
+ update_option( 'sb_instagram_settings', $sbi_options );
1135
+ }
1136
+ }
1137
+
1138
+ /**
1139
+ * Iterates through post data and tracks the index of the current post.
1140
+ * The actual post ids of the posts are stored in an array so the plugin
1141
+ * can search for local images that may be available.
1142
+ *
1143
+ * @param array $posts final filtered post data for the feed
1144
+ * @param array $settings
1145
+ * @param int $offset
1146
+ *
1147
+ * @since 2.0/5.0
1148
+ */
1149
+ private function posts_loop( $posts, $settings, $offset = 0 ) {
1150
+
1151
+ $image_ids = array();
1152
+ $post_index = $offset;
1153
+ $icon_type = $settings['font_method'];
1154
+
1155
+ foreach ( $posts as $post ) {
1156
+ $image_ids[] = SB_Instagram_Parse::get_post_id( $post );
1157
+ $account_type = SB_Instagram_Parse::get_account_type( $post );
1158
+ include sbi_get_feed_template_part( 'item', $settings );
1159
+ $post_index++;
1160
+ }
1161
+
1162
+ $this->image_ids_post_set = $image_ids;
1163
+ }
1164
+
1165
+ /**
1166
+ * Uses array of API request results and merges them based on how
1167
+ * the feed should be sorted. Mixed feeds are always sorted alternating
1168
+ * since there is no post date for hashtag feeds.
1169
+ *
1170
+ * @param array $post_sets an array of single API request worth
1171
+ * of posts
1172
+ * @param array $settings
1173
+ *
1174
+ * @return array
1175
+ *
1176
+ * @since 2.0/5.0
1177
+ */
1178
+ private function merge_posts( $post_sets, $settings ) {
1179
+ $merged_posts = array();
1180
+ if ( $settings['sortby'] === 'alternate' ) {
1181
+ // don't bother merging posts if there is only one post set
1182
+ if ( isset( $post_sets[1] ) ) {
1183
+ $min_cycles = max( 1, (int)$settings['num'] );
1184
+ for( $i = 0; $i <= $min_cycles; $i++ ) {
1185
+ foreach ( $post_sets as $post_set ) {
1186
+ if ( isset( $post_set[ $i ] ) && isset( $post_set[ $i ]['id'] ) ) {
1187
+ $merged_posts[] = $post_set[ $i ];
1188
+ }
1189
+ }
1190
+ }
1191
+ } else {
1192
+ $merged_posts = isset( $post_sets[0] ) ? $post_sets[0] : array();
1193
+ }
1194
+ } else {
1195
+ // don't bother merging posts if there is only one post set
1196
+ if ( isset( $post_sets[1] ) ) {
1197
+ foreach ( $post_sets as $post_set ) {
1198
+ if ( isset( $post_set[0]['id'] ) ) {
1199
+ $merged_posts = array_merge( $merged_posts, $post_set );
1200
+ }
1201
+ }
1202
+ } else {
1203
+ $merged_posts = isset( $post_sets[0] ) ? $post_sets[0] : array();
1204
+ }
1205
+ }
1206
+
1207
+
1208
+ return $merged_posts;
1209
+ }
1210
+
1211
+ /**
1212
+ * Sorts a post set based on sorting settings. Sorting by "alternate"
1213
+ * is done when merging posts for efficiency's sake so the post set is
1214
+ * just returned as it is.
1215
+ *
1216
+ * @param array $post_set
1217
+ * @param array $settings
1218
+ *
1219
+ * @return mixed|array
1220
+ *
1221
+ * @since 2.0/5.0
1222
+ */
1223
+ private function sort_posts( $post_set, $settings ) {
1224
+ if ( empty( $post_set ) ) {
1225
+ return $post_set;
1226
+ }
1227
+
1228
+ // sorting done with "merge_posts" to be more efficient
1229
+ if ( $settings['sortby'] === 'alternate' ) {
1230
+ return $post_set;
1231
+ } elseif ( $settings['sortby'] !== 'random' ) {
1232
+ // compares posted on dates of posts
1233
+ usort($post_set, 'sbi_date_sort' );
1234
+
1235
+ return $post_set;
1236
+ } else {
1237
+ /*
1238
+ * randomly selects posts in a random order. Cache saves posts
1239
+ * in this random order so paginating does not cause some posts to show up
1240
+ * twice or not at all
1241
+ */
1242
+ usort($post_set, 'sbi_rand_sort' );
1243
+
1244
+ return $post_set;
1245
+ }
1246
+ }
1247
+
1248
+ /**
1249
+ * Can trigger a second attempt at getting posts from the API
1250
+ *
1251
+ * Overwritten in the Pro version
1252
+ *
1253
+ * @param string $type
1254
+ * @param array $connected_account_with_error
1255
+ * @param int $attempts
1256
+ *
1257
+ * @return bool
1258
+ *
1259
+ * @since 2.0/5.1.1
1260
+ */
1261
+ protected function can_try_another_request( $type, $connected_account_with_error, $attempts = 0 ) {
1262
+ return false;
1263
+ }
1264
+
1265
+ /**
1266
+ * returns a second connected account if it exists
1267
+ *
1268
+ * Overwritten in the Pro version
1269
+ *
1270
+ * @param string $type
1271
+ * @param array $attempted_connected_accounts
1272
+ *
1273
+ * @return bool
1274
+ *
1275
+ * @since 2.0/5.1.1
1276
+ */
1277
+ protected function get_different_connected_account( $type, $attempted_connected_accounts ) {
1278
+ return false;
1279
+ }
1280
+
1281
+ }
inc/class-sb-instagram-parse.php ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Parse
4
+ *
5
+ * The structure of the data coming from the Instagram API is different
6
+ * for the old API vs the new graph API. This class is used to parse
7
+ * whatever structure the data has as well as use this to generate
8
+ * parts of the html used for image sources.
9
+ *
10
+ * @since 2.0/5.0
11
+ */
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ die( '-1' );
15
+ }
16
+
17
+ class SB_Instagram_Parse
18
+ {
19
+ /**
20
+ * @param $post array
21
+ *
22
+ * @return mixed
23
+ *
24
+ * @since 2.0/5.0
25
+ */
26
+ public static function get_post_id( $post ) {
27
+ return $post['id'];
28
+ }
29
+
30
+ /**
31
+ * @param $post array
32
+ *
33
+ * @return string
34
+ *
35
+ * @since 2.0/5.0
36
+ */
37
+ public static function get_account_type( $post ) {
38
+ if (isset( $post['media_type'] ) ) {
39
+ return 'business';
40
+ } else {
41
+ return 'personal';
42
+ }
43
+ }
44
+
45
+ /**
46
+ * @param $post array
47
+ *
48
+ * @return false|int
49
+ *
50
+ * @since 2.0/5.0
51
+ */
52
+ public static function get_timestamp( $post ) {
53
+ $timestamp = 0;
54
+ if ( isset( $post['created_time'] ) ) {
55
+ $timestamp = $post['created_time'];
56
+ } else if ( isset( $post['timestamp'] ) ) {
57
+ // some date formatting functions have trouble with the "T", "+", and extra zeroes added by Instagram
58
+ $remove_plus = trim( str_replace( array('T', '+', ' 0000' ), ' ', $post['timestamp'] ) );
59
+ $timestamp = strtotime( $remove_plus );
60
+ }
61
+
62
+ return $timestamp;
63
+ }
64
+
65
+ /**
66
+ * @param $post array
67
+ *
68
+ * @return string
69
+ *
70
+ * @since 2.0/5.0
71
+ */
72
+ public static function get_media_type( $post ) {
73
+ if ( isset( $post['type'] ) ) {
74
+ return $post['type'];
75
+ }
76
+
77
+ return strtolower( str_replace( '_ALBUM','', $post['media_type'] ) );
78
+ }
79
+
80
+ /**
81
+ * @param $post array
82
+ *
83
+ * @return mixed
84
+ *
85
+ * @since 2.0/5.0
86
+ */
87
+ public static function get_permalink( $post ) {
88
+ if ( isset( $post['permalink'] ) ) {
89
+ return $post['permalink'];
90
+ }
91
+
92
+ return $post['link'];
93
+ }
94
+
95
+ /**
96
+ * @param array $post
97
+ * @param string $resolution
98
+ *
99
+ * @return string
100
+ *
101
+ * @since 2.0/5.0
102
+ */
103
+ public static function get_media_url( $post, $resolution = 'lightbox' ) {
104
+ $account_type = isset( $post['images'] ) ? 'personal' : 'business';
105
+
106
+ if ( $account_type === 'personal' ) {
107
+
108
+ return $post['images']['standard_resolution']['url'];
109
+ } else {
110
+ if ($post['media_type'] === 'CAROUSEL_ALBUM' || $post['media_type'] === 'VIDEO') {
111
+ if ( isset( $post['thumbnail_url'] ) ) {
112
+ return $post['thumbnail_url'];
113
+ } elseif ( $post['media_type'] === 'CAROUSEL_ALBUM' && isset( $post['media_url'] ) ) {
114
+ return $post['media_url'];
115
+ } else {
116
+ $permalink = SB_Instagram_Parse::fix_permalink( SB_Instagram_Parse::get_permalink( $post ) );
117
+
118
+ return $permalink . 'media?size=l';
119
+ }
120
+ } else {
121
+ return $post['media_url'];
122
+ }
123
+ }
124
+
125
+ }
126
+
127
+ /**
128
+ * Uses the existing data for the indvidual instagram post to
129
+ * set the best image sources for each resolution size. Due to
130
+ * random bugs or just how the API works, different post types
131
+ * need special treatment.
132
+ *
133
+ * @param array $post
134
+ * @param array $resized_images
135
+ *
136
+ * @return array
137
+ *
138
+ * @since 2.0/5.0
139
+ */
140
+ public static function get_media_src_set( $post, $resized_images = array() ) {
141
+ $media_urls = array(
142
+ '150' => '',
143
+ '320' => '',
144
+ '640' => ''
145
+ );
146
+ $account_type = isset( $post['images'] ) ? 'personal' : 'business';
147
+
148
+
149
+ if ( $account_type === 'personal' ) {
150
+ $media_urls['150'] = $post['images']['thumbnail']['url'];
151
+ $media_urls['320'] = $post['images']['low_resolution']['url'];
152
+ $media_urls['640'] = $post['images']['standard_resolution']['url'];
153
+ } else {
154
+ $post_id = SB_Instagram_Parse::get_post_id( $post );
155
+
156
+ // use resized images if exists
157
+ if ( isset( $resized_images[ $post_id ]['id'] ) && $resized_images[ $post_id ]['id'] !== 'pending' && $resized_images[ $post_id ]['id'] !== 'video' ) {
158
+ $media_urls['640'] = 'uploads_dir' . $resized_images[ $post_id ]['id'] . 'full.jpg';
159
+ }
160
+
161
+ $permalink = SB_Instagram_Parse::fix_permalink( SB_Instagram_Parse::get_permalink( $post ) );
162
+
163
+ if ( ($post['media_type'] === 'CAROUSEL_ALBUM' || $post['media_type'] === 'VIDEO') && ($media_urls['640'] === '' || $media_urls['640'] === 'video' || $media_urls['640'] === 'pending')) {
164
+ $media_urls['640'] = $permalink . 'media?size=l';
165
+ } else {
166
+ $media_urls['640'] = $post['media_url'];
167
+ }
168
+ $media_urls['150'] = $permalink . 'media?size=t';
169
+ $media_urls['320'] = $permalink . 'media?size=m';
170
+
171
+
172
+ }
173
+
174
+ return $media_urls;
175
+ }
176
+
177
+ /**
178
+ * A default can be set in the case that the user doesn't use captions
179
+ * for posts as this is also used as the alt text for the image.
180
+ *
181
+ * @param $post
182
+ * @param string $default
183
+ *
184
+ * @return string
185
+ *
186
+ * @since 2.0/5.0
187
+ */
188
+ public static function get_caption( $post, $default = '' ) {
189
+ $caption = $default;
190
+ if ( ! empty( $post['caption'] ) && ! is_array( $post['caption'] ) ) {
191
+ $caption = $post['caption'];
192
+ } elseif ( ! empty( $post['caption']['text'] ) ) {
193
+ $caption = $post['caption']['text'];
194
+ }
195
+
196
+ return $caption;
197
+ }
198
+
199
+ /**
200
+ * @param array $header_data
201
+ *
202
+ * @return string
203
+ *
204
+ * @since 2.0/5.0
205
+ */
206
+ public static function get_username( $header_data ) {
207
+ if ( isset( $header_data['username'] ) ) {
208
+ return $header_data['username'];
209
+ } elseif ( isset( $header_data['user'] ) ) {
210
+ return $header_data['user']['username'];
211
+ } elseif ( isset( $header_data['data'] ) ) {
212
+ return $header_data['data']['username'];
213
+ }
214
+ return '';
215
+ }
216
+
217
+ /**
218
+ * @param array $header_data
219
+ * @param array $settings
220
+ *
221
+ * @return string
222
+ *
223
+ * @since 2.0/5.0
224
+ */
225
+ public static function get_avatar( $header_data, $settings = array( 'favor_local' => false ) ) {
226
+ if ( $settings['favor_local'] && ! empty( $header_data['local_avatar'] ) ) {
227
+ return $header_data['local_avatar'];
228
+ } else {
229
+ if ( isset( $header_data['profile_picture'] ) ) {
230
+ return $header_data['profile_picture'];
231
+ } elseif ( isset( $header_data['profile_picture_url'] ) ) {
232
+ return $header_data['profile_picture_url'];
233
+ } elseif ( isset( $header_data['user'] ) ) {
234
+ return $header_data['user']['profile_picture'];
235
+ } elseif ( isset( $header_data['data'] ) ) {
236
+ return $header_data['data']['profile_picture'];
237
+ }
238
+ }
239
+
240
+ return '';
241
+ }
242
+
243
+ /**
244
+ * The full name attached to the user account
245
+ *
246
+ * @param array $header_data
247
+ *
248
+ * @return string
249
+ *
250
+ * @since 2.0/5.0
251
+ */
252
+ public static function get_name( $header_data ) {
253
+ if ( isset( $header_data['name'] ) ) {
254
+ return $header_data['name'];
255
+ } elseif ( isset( $header_data['data'] ) ) {
256
+ return $header_data['data']['full_name'];
257
+ }
258
+ return '';
259
+ }
260
+
261
+ /**
262
+ * There seems to be occasional bugs with the Instagram API
263
+ * and permalinks. This corrects it.
264
+ *
265
+ * @param string $permalink
266
+ *
267
+ * @return string
268
+ *
269
+ * @since 2.0/5.0
270
+ */
271
+ protected static function fix_permalink( $permalink ) {
272
+ if ( substr_count( $permalink, '/' ) > 5 ) {
273
+ $permalink_array = explode( '/', $permalink );
274
+ $perm_id = $permalink_array[ count( $permalink_array ) - 2 ];
275
+ $permalink = 'https://www.instagram.com/p/' . $perm_id . '/';
276
+ }
277
+
278
+ return $permalink;
279
+ }
280
+ }
inc/class-sb-instagram-post-set.php ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Post_Set
4
+ *
5
+ * Useful for iterating over an array of posts and resizing images for
6
+ * them or updating data in the custom database tables.
7
+ *
8
+ * @since 2.0/4.0
9
+ */
10
+
11
+ // Don't load directly
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ die( '-1' );
14
+ }
15
+
16
+ class SB_Instagram_Post_Set {
17
+ /**
18
+ * @var array
19
+ */
20
+ private $post_data;
21
+
22
+ /**
23
+ * @var array
24
+ */
25
+ private $resized_image_data_for_set;
26
+
27
+ /**
28
+ * @var string|null
29
+ */
30
+ private $upload_dir;
31
+
32
+ /**
33
+ * @var string|null
34
+ */
35
+ private $upload_url;
36
+
37
+ /**
38
+ * @var bool
39
+ */
40
+ private $transient_name;
41
+
42
+ /**
43
+ * @var null
44
+ */
45
+ private $fill_in_timestamp;
46
+
47
+ /**
48
+ * @var
49
+ */
50
+ private $first_post_top_time_stamp;
51
+
52
+ /**
53
+ * SB_Instagram_Post_Set constructor.
54
+ *
55
+ * @param array $post_data
56
+ * @param bool $transient_name
57
+ * @param null $fill_in_timestamp (optional)
58
+ * @param array $image_sizes (optional) sizes to create for personal and business account
59
+ * currently thumb, low, and full can be set
60
+ * @param null $upload_dir (optional)
61
+ * @param null $upload_url (optional)
62
+ *
63
+ * @since 2.0/4.0
64
+ */
65
+ public function __construct( $post_data, $transient_name = false, $fill_in_timestamp = NULL, $image_sizes = array( 'personal' => array( 'low' => 320 ), 'business' => array( 'full' => 640, 'low' => 320 ) ), $upload_dir = NULL, $upload_url = NULL ) {
66
+ $this->post_data = $post_data;
67
+
68
+ $this->image_sizes = $image_sizes;
69
+
70
+ if ( ! isset( $upload_dir ) || ! isset( $upload_url ) ) {
71
+ $upload = wp_upload_dir();
72
+ $upload_dir = $upload['basedir'];
73
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
74
+
75
+ $upload_url = trailingslashit( $upload['baseurl'] ) . SBI_UPLOADS_NAME;
76
+ }
77
+
78
+ $this->upload_dir = $upload_dir;
79
+
80
+ $this->upload_url = $upload_url;
81
+
82
+ $this->transient_name = $transient_name;
83
+
84
+ $this->fill_in_timestamp = $fill_in_timestamp;
85
+ }
86
+
87
+ /**
88
+ * @return array
89
+ *
90
+ * @since 2.0/4.0
91
+ */
92
+ public function get_post_data() {
93
+ if ( is_array( $this->post_data ) ) {
94
+ return $this->post_data;
95
+ } else {
96
+ return array();
97
+ }
98
+ }
99
+
100
+ /**
101
+ * @return array
102
+ *
103
+ * @since 2.0/4.0
104
+ */
105
+ public function get_resized_image_data_for_set() {
106
+ return $this->resized_image_data_for_set;
107
+ }
108
+
109
+ /**
110
+ * Loop through set of posts and update or create resized images based on
111
+ * whether or not they have been created and whether or not a record has been
112
+ * saved for this feed id
113
+ *
114
+ * @since 2.0/4.0
115
+ */
116
+ public function maybe_save_update_and_resize_images_for_posts() {
117
+ global $sb_instagram_posts_manager;
118
+
119
+ $posts_iterated_through = 0;
120
+ $number_resized = 0;
121
+ $number_updated = 0;
122
+ $resized_image_data_for_set = array();
123
+ $resizing_disabled = $sb_instagram_posts_manager->image_resizing_disabled() || $sb_instagram_posts_manager->max_resizing_per_time_period_reached();
124
+ $is_top_post_feed = (substr( $this->transient_name, 4, 1 ) === '+');
125
+
126
+ foreach ( $this->post_data as $single_instagram_post_data ) {
127
+
128
+ if ( $posts_iterated_through < 60 ) {
129
+ $single_post = new SB_Instagram_Post( $single_instagram_post_data['id'] );
130
+ $single_post->set_instagram_api_data( $single_instagram_post_data );
131
+ $resized_image_data_for_set[ $single_instagram_post_data['id'] ] = array();
132
+
133
+ if ( $is_top_post_feed ) {
134
+ if ( empty( $this->first_post_top_time_stamp ) ) {
135
+ $this_post_top_time_stamp = $single_post->get_top_time_stamp();
136
+ if ( empty( $this_post_top_time_stamp ) ) {
137
+ $this->first_post_top_time_stamp = $this->fill_in_timestamp;
138
+ } else {
139
+ $this->first_post_top_time_stamp = $single_post->get_top_time_stamp();
140
+ }
141
+ }
142
+ }
143
+
144
+ if ( ! $resizing_disabled ) {
145
+ if ( (! $single_post->exists_in_posts_table() || ! $single_post->images_done_resizing()) && $number_resized < 30 ) {
146
+
147
+ if ( $sb_instagram_posts_manager->max_total_records_reached() ) {
148
+ $sb_instagram_posts_manager->delete_least_used_image();
149
+ }
150
+
151
+ if ( ! $single_post->images_done_resizing() && $single_post->exists_in_posts_table() ) {
152
+ $single_post->resize_and_save_image( $this->image_sizes, $this->upload_dir, $this->upload_url );
153
+ } else {
154
+ if ( $is_top_post_feed ) {
155
+ if ( $single_post->save_in_db( $this->transient_name, date( 'Y-m-d H:i:s', strtotime( $this->first_post_top_time_stamp ) - (120 * $posts_iterated_through) - 1 ) ) ) {
156
+ $single_post->resize_and_save_image( $this->image_sizes, $this->upload_dir, $this->upload_url );
157
+ }
158
+ } else {
159
+ if ( $single_post->save_in_db( $this->transient_name, date( 'Y-m-d H:i:s', strtotime( $this->fill_in_timestamp ) - (120 * $posts_iterated_through) ) ) ) {
160
+ $single_post->resize_and_save_image( $this->image_sizes, $this->upload_dir, $this->upload_url );
161
+ }
162
+ }
163
+ }
164
+
165
+ $number_resized++;
166
+ } else {
167
+ if ( $is_top_post_feed ) {
168
+ $single_post->update_db_data( true, $this->transient_name, $this->image_sizes, $this->upload_dir, $this->upload_url, date( 'Y-m-d H:i:s', strtotime( $this->first_post_top_time_stamp ) - (120 * $posts_iterated_through) ) );
169
+ } else {
170
+ $single_post->update_db_data( true, $this->transient_name, $this->image_sizes, $this->upload_dir, $this->upload_url );
171
+ }
172
+ if ( ! $single_post->exists_in_feeds_posts_table( $this->transient_name ) ) {
173
+ $single_post->insert_sbi_instagram_feeds_posts( $this->transient_name );
174
+ }
175
+ $number_updated++;
176
+ }
177
+
178
+ $resized_image_data_for_set[ $single_instagram_post_data['id'] ] = $single_post->get_resized_image_array();
179
+ }
180
+ }
181
+
182
+ $posts_iterated_through++;
183
+ }
184
+
185
+ $this->resized_image_data_for_set = $resized_image_data_for_set;
186
+ }
187
+
188
+ }
inc/class-sb-instagram-post.php ADDED
@@ -0,0 +1,535 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Post
4
+ *
5
+ * Primarily used for resizing and storing images, this class
6
+ * performs certain tasks with data for a single post.
7
+ *
8
+ * Currently used only by the SB_Instagram_Post_Set class
9
+ *
10
+ * @since 2.0/4.0
11
+ */
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ die( '-1' );
15
+ }
16
+
17
+ class SB_Instagram_Post
18
+ {
19
+ /**
20
+ * @var string
21
+ */
22
+ private $instagram_post_id;
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ private $instagram_api_data;
28
+
29
+ /**
30
+ * @var string
31
+ */
32
+ private $db_id;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ private $media_id;
38
+
39
+ /**
40
+ * @var string
41
+ */
42
+ private $top_time_stamp;
43
+
44
+ /**
45
+ * @var bool|int
46
+ */
47
+ private $images_done;
48
+
49
+ /**
50
+ * @var array
51
+ */
52
+ private $resized_image_array;
53
+
54
+ /**
55
+ * SB_Instagram_Post constructor.
56
+ *
57
+ * @param string $instagram_post_id from the Instagram API
58
+ */
59
+ public function __construct( $instagram_post_id ) {
60
+ global $wpdb;
61
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
62
+
63
+ $feed_id_match = $wpdb->get_results( $wpdb->prepare( "SELECT id, media_id, top_time_stamp, images_done FROM $table_name WHERE instagram_id = %s LIMIT 1", $instagram_post_id ), ARRAY_A );
64
+
65
+ $this->db_id = ! empty( $feed_id_match ) ? $feed_id_match[0]['id'] : '';
66
+ $this->media_id = ! empty( $feed_id_match ) ? $feed_id_match[0]['media_id'] : '';
67
+ $this->top_time_stamp = ! empty( $feed_id_match ) && isset( $feed_id_match[0]['top_time_stamp'] ) ? $feed_id_match[0]['top_time_stamp'] : '';
68
+ $this->images_done = ! empty( $feed_id_match ) && isset( $feed_id_match[0]['images_done'] ) ? $feed_id_match[0]['images_done'] === '1' : 0;
69
+
70
+ $this->instagram_post_id = $instagram_post_id;
71
+ }
72
+
73
+ /**
74
+ * Whether or not this post has already been saved in the custom table
75
+ *
76
+ * @return bool
77
+ *
78
+ * @since 2.0/4.0
79
+ */
80
+ public function exists_in_posts_table() {
81
+ return ! empty( $this->db_id );
82
+ }
83
+
84
+ /**
85
+ * Whether or not resized image files have already been recorded as being created
86
+ * in the database table
87
+ *
88
+ * @return bool|int
89
+ *
90
+ * @since 2.0/4.0
91
+ */
92
+ public function images_done_resizing() {
93
+ return $this->images_done;
94
+ }
95
+
96
+ /**
97
+ * @param array $instagram_api_data
98
+ *
99
+ * @since 2.0/4.0
100
+ */
101
+ public function set_instagram_api_data( $instagram_api_data ) {
102
+ $this->instagram_api_data = $instagram_api_data;
103
+ }
104
+
105
+ /**
106
+ * Used for sorting top posts since they don't have a posted on date
107
+ *
108
+ * @return string
109
+ *
110
+ * @since 2.0/4.0
111
+ */
112
+ public function get_top_time_stamp() {
113
+ return $this->top_time_stamp;
114
+ }
115
+
116
+ /**
117
+ * Record newly created images so they can be returned and used right away.
118
+ *
119
+ * Not used in version 2.0/5.0 but can be used to resize and use
120
+ * images "on the fly" when the feed is being displayed.
121
+ *
122
+ * @param string $key
123
+ * @param string $val
124
+ *
125
+ * @since 2.0/4.0
126
+ */
127
+ public function add_resized_image_to_obj_array( $key, $val ) {
128
+ $this->resized_image_array[ $key ] = $val;
129
+ }
130
+
131
+ /**
132
+ * Used to save information about the post before image resizing is done to
133
+ * prevent a potentially storing multiple entries for the same post
134
+ *
135
+ * @param mixed|string|bool $transient_name (optional)
136
+ * @param null $timestamp_override (optional)
137
+ *
138
+ * @return bool
139
+ *
140
+ * @since 2.0/4.0
141
+ */
142
+ public function save_in_db( $transient_name = false, $timestamp_override = NULL ) {
143
+ global $wpdb;
144
+
145
+ $parsed_data = $this->get_parsed_post_data();
146
+
147
+ $timestamp = ! empty( $timestamp_override ) && empty( $parsed_data['timestamp'] ) ? $timestamp_override : $parsed_data['timestamp'];
148
+
149
+ $entry_data = array(
150
+ "'" . date( 'Y-m-d H:i:s' ) . "'",
151
+ "'" . esc_sql( $parsed_data['id'] ) . "'",
152
+ "'" . esc_sql( $timestamp ) . "'",
153
+ "'" . esc_sql( wp_json_encode( $this->instagram_api_data ) ) . "'",
154
+ "'pending'",
155
+ "'pending'",
156
+ 0,
157
+ "'".date( 'Y-m-d H:i:s' )."'"
158
+ );
159
+
160
+ $entry_string = implode( ',',$entry_data );
161
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
162
+
163
+ $timestamp_column = 'time_stamp';
164
+ if ( substr( $transient_name, 4, 1 ) === '+') {
165
+ $timestamp_column = 'top_time_stamp';
166
+ }
167
+
168
+ $error = $wpdb->query( "INSERT INTO $table_name
169
+ (created_on,instagram_id,$timestamp_column,json_data,media_id,sizes,images_done,last_requested) VALUES ($entry_string);" );
170
+
171
+ if ( $error !== false ) {
172
+ $this->db_id = $wpdb->insert_id;
173
+ $this->insert_sbi_instagram_feeds_posts( $transient_name );
174
+ } else {
175
+ // log error
176
+ }
177
+
178
+ return true;
179
+ }
180
+
181
+ /**
182
+ * Uses the post's data to get a relevant full size image url and resize it
183
+ *
184
+ * @param array $image_sizes
185
+ * @param string $upload_dir
186
+ * @param string $upload_url
187
+ *
188
+ * @since 2.0/4.0
189
+ * @since 2.0/5.0 loop through assoc array (res setting => desired width of image) to
190
+ * accommodate personal accounts and possible
191
+ * custom sizes in the future
192
+ */
193
+ public function resize_and_save_image( $image_sizes, $upload_dir, $upload_url ) {
194
+ if ( isset( $this->instagram_api_data['id'] ) ) {
195
+ $image_source_set = SB_Instagram_Parse::get_media_src_set( $this->instagram_api_data );
196
+ $account_type = SB_Instagram_Parse::get_account_type( $this->instagram_api_data );
197
+ $image_sizes_to_make = isset( $image_sizes[ $account_type ] ) ? $image_sizes[ $account_type ] : array();
198
+ // if it's a personal account or a weird url, the post id is used, otherwise the last part of the image url is used
199
+ if ( $account_type === 'business' ) {
200
+ $new_file_name = explode( '?', SB_Instagram_Parse::get_media_url( $this->instagram_api_data, 'lightbox' ) );
201
+ if ( strlen( basename( $new_file_name[0], '.jpg' ) ) > 10 ) {
202
+ $new_file_name = basename( $new_file_name[0], '.jpg' );
203
+ } else {
204
+ $new_file_name = $this->instagram_api_data['id'];
205
+ }
206
+ } else {
207
+ $new_file_name = $this->instagram_api_data['id'];
208
+ }
209
+
210
+ // the process is considered a success if one image is successfully resized
211
+ $one_successful_image_resize = false;
212
+
213
+ foreach ( $image_sizes_to_make as $res_setting => $image_size ) {
214
+ $file_name = isset( $image_source_set[ $image_size ] ) ? $image_source_set[ $image_size ] : SB_Instagram_Parse::get_media_url( $this->instagram_api_data, 'lightbox' );
215
+ if ( ! empty( $file_name ) ) {
216
+
217
+ $sizes = array(
218
+ 'height' => 1,
219
+ 'width' => 1
220
+ );
221
+
222
+
223
+ $suffix = $res_setting;
224
+
225
+ $this_image_file_name = $new_file_name . $suffix . '.jpg';
226
+
227
+ $image_editor = wp_get_image_editor( $file_name );
228
+
229
+ // not uncommon for the image editor to not work using it this way
230
+ if ( ! is_wp_error( $image_editor ) ) {
231
+ $sizes = $image_editor->get_size();
232
+
233
+ $image_editor->resize( $image_size, null );
234
+
235
+ $full_file_name = trailingslashit( $upload_dir ) . $this_image_file_name;
236
+
237
+ $saved_image = $image_editor->save( $full_file_name );
238
+
239
+ if ( ! $saved_image ) {
240
+ global $sb_instagram_posts_manager;
241
+
242
+ $sb_instagram_posts_manager->add_error( 'image_editor_save', array(
243
+ __( 'Error saving edited image.', 'instagram-feed' ),
244
+ $full_file_name
245
+ ) );
246
+ } else {
247
+ $one_successful_image_resize = true;
248
+ }
249
+ } else {
250
+ global $sb_instagram_posts_manager;
251
+
252
+ $message = __( 'Error editing image.', 'instagram-feed' );
253
+ if ( isset( $image_editor ) && isset( $image_editor->errors ) ) {
254
+ foreach ( $image_editor->errors as $key => $item ) {
255
+ $message .= ' ' . $key . '- ' . $item[0] . ' |';
256
+ }
257
+ }
258
+
259
+ $sb_instagram_posts_manager->add_error( 'image_editor', array( $file_name, $message ) );
260
+ }
261
+
262
+ }
263
+
264
+
265
+ }
266
+
267
+ if ( $one_successful_image_resize ) {
268
+ $aspect_ratio = round( $sizes['width'] / $sizes['height'], 2 );
269
+
270
+ $this->update_sbi_instagram_posts( array(
271
+ 'media_id' => $new_file_name,
272
+ 'sizes' => maybe_serialize( $image_sizes_to_make ),
273
+ 'aspect_ratio' => $aspect_ratio,
274
+ 'images_done' => 1
275
+ ) );
276
+
277
+ $this->add_resized_image_to_obj_array( 'id', $new_file_name );
278
+ } else {
279
+ // an error status means that image resizing won't be attempted again for this post
280
+ $this->update_sbi_instagram_posts( array(
281
+ 'media_id' => 'error',
282
+ 'sizes' => maybe_serialize( $image_sizes_to_make ),
283
+ 'aspect_ratio' => 1,
284
+ 'images_done' => 1
285
+ ) );
286
+ }
287
+
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Return relevant data for resized images for this post
293
+ *
294
+ * @return array
295
+ *
296
+ * @since 2.0/4.0
297
+ */
298
+ public function get_resized_image_array() {
299
+ if ( empty( $this->resized_image_array ) ) {
300
+ global $wpdb;
301
+
302
+ $posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
303
+ $stored = $wpdb->get_results( $wpdb->prepare( "SELECT media_id, aspect_ratio FROM $posts_table_name
304
+ WHERE instagram_id = %s
305
+ LIMIT 1", $this->instagram_post_id ), ARRAY_A );
306
+
307
+ if ( isset( $stored[0] ) ) {
308
+ $return = array(
309
+ 'id' => $stored[0]['media_id'],
310
+ 'ratio' => $stored[0]['aspect_ratio']
311
+ );
312
+ $this->resized_image_array = $return;
313
+ return $return;
314
+ } else {
315
+ return array();
316
+ }
317
+ } else {
318
+ return $this->resized_image_array;
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Controls whether or not the database record will be updated for this post.
324
+ * Called after images are successfully created.
325
+ *
326
+ * @param bool $update_last_requested
327
+ * @param bool $transient_name
328
+ * @param array $image_sizes
329
+ * @param string $upload_dir
330
+ * @param string $upload_url
331
+ * @param bool $timestamp_for_update
332
+ *
333
+ * @return bool
334
+ *
335
+ * @since 2.0/4.0
336
+ */
337
+ public function update_db_data( $update_last_requested = true, $transient_name = false, $image_sizes, $upload_dir, $upload_url, $timestamp_for_update = false ) {
338
+
339
+ if ( empty( $this->db_id ) ) {
340
+ return false;
341
+ }
342
+
343
+ $to_update = array(
344
+ 'json_data' => wp_json_encode( $this->instagram_api_data )
345
+ );
346
+
347
+ if ( $update_last_requested ) {
348
+ $to_update['last_requested'] = date( 'Y-m-d H:i:s' );
349
+ }
350
+
351
+ if ( $timestamp_for_update ) {
352
+ $to_update['top_time_stamp'] = $timestamp_for_update;
353
+ }
354
+
355
+ if ( $transient_name ) {
356
+ $this->maybe_add_feed_id( $transient_name );
357
+ }
358
+
359
+ if ( $this->media_id === 'pending' ) {
360
+ $this->resize_and_save_image( $image_sizes, $upload_dir, $upload_url );
361
+ } else {
362
+ $this->update_sbi_instagram_posts( $to_update );
363
+ }
364
+
365
+ return true;
366
+ }
367
+
368
+ /**
369
+ * Updates columns that need to be updated in the posts types table.
370
+ * Called after images successfully resized and if any information
371
+ * needs to be updated.
372
+ *
373
+ * @param array $to_update assoc array of columns and values to update
374
+ *
375
+ * @since 2.0/4.0
376
+ */
377
+ public function update_sbi_instagram_posts( $to_update ) {
378
+ global $wpdb;
379
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
380
+
381
+ foreach ( $to_update as $column => $value ) {
382
+ $query = $wpdb->query( $wpdb->prepare( "UPDATE $table_name
383
+ SET $column = %s
384
+ WHERE id = %d;", $value, $this->db_id ) );
385
+
386
+ if ( $query === false ) {
387
+ global $sb_instagram_posts_manager;
388
+ $error = $wpdb->last_error;
389
+ $query = $wpdb->last_query;
390
+
391
+ $sb_instagram_posts_manager->add_error( 'database_update_post', array( __( 'Error updating post.', 'instagram-feed' ), $error . '<br><code>' . $query . '</code>' ) );
392
+ }
393
+ }
394
+
395
+ }
396
+
397
+ /**
398
+ * Checks database for matching record for post and feed ID.
399
+ * There shouldn't be duplicate records
400
+ *
401
+ * @param string $transient_name
402
+ *
403
+ * @return bool
404
+ *
405
+ * @since 2.0/4.1
406
+ */
407
+ public function exists_in_feeds_posts_table( $transient_name ) {
408
+ global $wpdb;
409
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
410
+ $feed_id_array = explode( '#', $transient_name );
411
+ $feed_id = $feed_id_array[0];
412
+ $results = $wpdb->get_results( $wpdb->prepare( "SELECT feed_id FROM $table_name WHERE instagram_id = %s AND feed_id = %s LIMIT 1", $this->instagram_post_id, $feed_id ), ARRAY_A );
413
+
414
+ return isset( $results[0]['feed_id'] );
415
+ }
416
+
417
+ /**
418
+ * Add a record of this post being used for the specified transient name (feed id)
419
+ *
420
+ * @param string $transient_name
421
+ *
422
+ * @return int
423
+ *
424
+ * @since 2.0/4.0
425
+ */
426
+ public function insert_sbi_instagram_feeds_posts( $transient_name ) {
427
+ global $wpdb;
428
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
429
+ // the number is removed from the transient name for backwards compatibilty.
430
+ $feed_id_array = explode( '#', $transient_name );
431
+ $feed_id = $feed_id_array[0];
432
+
433
+ $entry_data = array(
434
+ $this->db_id,
435
+ "'" . esc_sql( $this->instagram_api_data['id'] ) . "'",
436
+ "'" . esc_sql( $feed_id ) . "'"
437
+ );
438
+ $entry_string = implode( ',',$entry_data );
439
+
440
+ $error = $wpdb->query( "INSERT INTO $table_name
441
+ (id,instagram_id,feed_id) VALUES ($entry_string);" );
442
+
443
+ if ( $error !== false ) {
444
+ return $wpdb->insert_id;
445
+ } else {
446
+ global $sb_instagram_posts_manager;
447
+ $error = $wpdb->last_error;
448
+ $query = $wpdb->last_query;
449
+
450
+ $sb_instagram_posts_manager->add_error( 'database_insert_post', array( __( 'Error inserting post.', 'instagram-feed' ), $error . '<br><code>' . $query . '</code>' ) );
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Uses the saved json for the post to be used for updating records
456
+ *
457
+ * @param bool $all
458
+ *
459
+ * @return array
460
+ *
461
+ * @since 2.0/4.0
462
+ */
463
+ private function get_parsed_post_data( $all = true ) {
464
+
465
+ $instagram_post_id = isset( $this->instagram_api_data['id'] ) ? $this->instagram_api_data['id'] : '';
466
+ $comments_count = isset( $this->instagram_api_data['comments_count'] ) ? $this->instagram_api_data['comments_count'] : '';
467
+ $like_count = isset( $this->instagram_api_data['like_count'] ) ? $this->instagram_api_data['like_count'] : '';
468
+
469
+ $parsed_data = array(
470
+ 'comments_count' => $comments_count,
471
+ 'like_count' => $like_count
472
+ );
473
+
474
+ if ( $all ) {
475
+ $caption = isset( $this->instagram_api_data['caption'] ) ? $this->instagram_api_data['caption'] : '';
476
+ $media_url = isset( $this->instagram_api_data['media_url'] ) ? $this->instagram_api_data['media_url'] : '';
477
+ $media_type = isset( $this->instagram_api_data['media_type'] ) ? $this->instagram_api_data['media_type'] : '';
478
+
479
+ $timestamp = '';
480
+ if ( isset( $this->instagram_api_data['timestamp'] ) ) {
481
+ $timestamp_parts = explode( ' ', $this->instagram_api_data['timestamp'] );
482
+ $timestamp = str_replace( 'T', ' ', $timestamp_parts[0] );
483
+ }
484
+
485
+ $username = isset( $this->instagram_api_data['username'] ) ? $this->instagram_api_data['username'] : '';
486
+ $permalink = isset( $this->instagram_api_data['permalink'] ) ? $this->instagram_api_data['permalink'] : '';
487
+ $children = isset( $this->instagram_api_data['children'] ) ? wp_json_encode( $this->instagram_api_data['children'] ) : '';
488
+
489
+ $parsed_data['caption'] = $caption;
490
+ $parsed_data['media_url'] = $media_url;
491
+ $parsed_data['id'] = $instagram_post_id;
492
+ $parsed_data['media_type'] = $media_type;
493
+ $parsed_data['timestamp'] = $timestamp;
494
+ $parsed_data['username'] = $username;
495
+ $parsed_data['permalink'] = $permalink;
496
+ $parsed_data['children'] = $children;
497
+ }
498
+
499
+ return $parsed_data;
500
+ }
501
+
502
+ /**
503
+ * If a record hasn't been made for this transient name/feed id,
504
+ * make a record
505
+ *
506
+ * @param string $feed_id
507
+ *
508
+ * @since 2.0/4.0
509
+ */
510
+ private function maybe_add_feed_id( $feed_id ) {
511
+
512
+ if ( empty( $this->instagram_post_id ) ) {
513
+ return;
514
+ }
515
+
516
+ global $wpdb;
517
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
518
+ // the number is removed from the transient name for backwards compatibilty.
519
+ $feed_id_array = explode( '#', $feed_id );
520
+ $feed_id = $feed_id_array[0];
521
+
522
+ $feed_id_match = $wpdb->get_col( $wpdb->prepare( "SELECT feed_id FROM $table_name WHERE feed_id = %s AND instagram_id = %s", $feed_id, $this->instagram_post_id ) );
523
+
524
+ if ( ! isset( $feed_id_match[0] ) ) {
525
+ $entry_data = array(
526
+ $this->db_id,
527
+ "'" . esc_sql( $this->instagram_post_id ) . "'",
528
+ "'" . esc_sql( $feed_id ) . "'"
529
+ );
530
+ $entry_string = implode( ',',$entry_data );
531
+ $error = $wpdb->query( "INSERT INTO $table_name
532
+ (id,instagram_id,feed_id) VALUES ($entry_string);" );
533
+ }
534
+ }
535
+ }
inc/class-sb-instagram-posts-manager.php ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Posts_Manager
4
+ *
5
+ * Set as a global object to record and report errors as well
6
+ * as control aspects of image resizing
7
+ *
8
+ * @since 2.0/4.0
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ die( '-1' );
13
+ }
14
+
15
+ class SB_Instagram_Posts_Manager
16
+ {
17
+ /**
18
+ * @var mixed|void
19
+ */
20
+ var $sbi_options;
21
+
22
+ /**
23
+ * @var int
24
+ */
25
+ var $limit;
26
+
27
+ /**
28
+ * @var array
29
+ */
30
+ var $errors;
31
+
32
+ /**
33
+ * @var array
34
+ */
35
+ var $frontend_errors;
36
+
37
+ /**
38
+ * @var bool
39
+ */
40
+ var $resizing_tables_exist;
41
+
42
+ /**
43
+ * SB_Instagram_Posts_Manager constructor.
44
+ */
45
+ public function __construct() {
46
+ $this->sbi_options = get_option( 'sb_instagram_settings' );
47
+ $this->errors = get_option( 'sb_instagram_errors', array() );
48
+ $this->ajax_status = get_option( 'sb_instagram_ajax_status', array( 'tested' => false, 'successful' => false ) );
49
+ $this->frontend_errors = array();
50
+ }
51
+
52
+ /**
53
+ * @return array
54
+ *
55
+ * @since 2.0/5.0
56
+ */
57
+ public function get_ajax_status() {
58
+ return $this->ajax_status;
59
+ }
60
+
61
+ /**
62
+ * @param $to_update
63
+ *
64
+ * @since 2.0/5.0
65
+ */
66
+ public function update_ajax_status( $to_update ) {
67
+ foreach ( $to_update as $key => $value ) {
68
+ $this->ajax_status[ $key ] = $value;
69
+ }
70
+
71
+ update_option( 'sb_instagram_ajax_status', $this->ajax_status );
72
+ }
73
+
74
+ /**
75
+ * When the plugin is first installed and used, an AJAX call to admin-ajax.php
76
+ * is made to verify that it's available
77
+ *
78
+ * @param bool $force_check
79
+ *
80
+ * @return bool
81
+ *
82
+ * @since 2.0/5.0
83
+ */
84
+ public function maybe_start_ajax_test( $force_check = false ) {
85
+ if ( ! $this->ajax_status['tested'] || $force_check ) {
86
+ set_transient( 'sb_instagram_doing_ajax_test', 'yes', 60*60 );
87
+ $this->update_ajax_status( array( 'tested' => true ) );
88
+ return true;
89
+ }
90
+
91
+ return false;
92
+ }
93
+
94
+ /**
95
+ * Called if a successful admin ajax request is made
96
+ *
97
+ * @since 2.0/5.0
98
+ */
99
+ public function update_successful_ajax_test() {
100
+ $this->update_ajax_status( array( 'successful' => true ) );
101
+ }
102
+
103
+ /**
104
+ * @return bool
105
+ *
106
+ * @since 2.0/5.0
107
+ */
108
+ public function should_add_ajax_test_notice() {
109
+ return ($this->ajax_status['tested'] && ! $this->ajax_status['successful'] && get_transient( 'sb_instagram_doing_ajax_test' ) !== 'yes');
110
+ }
111
+
112
+ /**
113
+ * The plugin has a limit on how many post records can be stored and
114
+ * images resized to avoid overloading servers. This function deletes the post that
115
+ * has the longest time passed since it was retrieved.
116
+ *
117
+ * @since 2.0/4.0
118
+ */
119
+ public function delete_least_used_image() {
120
+ global $wpdb;
121
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
122
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
123
+
124
+ $max = isset( $this->limit ) && $this->limit > 1 ? $this->limit : 1;
125
+
126
+ $oldest_posts = $wpdb->get_results( "SELECT id, media_id FROM $table_name ORDER BY last_requested ASC LIMIT $max", ARRAY_A );
127
+
128
+ $upload = wp_upload_dir();
129
+ $file_suffixes = array( 'thumb', 'low', 'full' );
130
+
131
+ foreach ( $oldest_posts as $post ) {
132
+
133
+ foreach ( $file_suffixes as $file_suffix ) {
134
+ $file_name = trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) . $post['media_id'] . $file_suffix . '.jpg';
135
+ if ( is_file( $file_name ) ) {
136
+ unlink( $file_name );
137
+ }
138
+ }
139
+
140
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $post['id'] ) );
141
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $feeds_posts_table_name WHERE record_id = %d", $post['id'] ) );
142
+ }
143
+
144
+ }
145
+
146
+ /**
147
+ * Calculates how many records are in the database and whether or not it exceeds the limit
148
+ *
149
+ * @return bool
150
+ *
151
+ * @since 2.0/4.0
152
+ */
153
+ public function max_total_records_reached() {
154
+ global $wpdb;
155
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
156
+
157
+ $num_records = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" );
158
+
159
+ if ( !isset( $this->limit ) && (int)$num_records > SBI_MAX_RECORDS ) {
160
+ $this->limit = (int)$num_records - SBI_MAX_RECORDS;
161
+ }
162
+
163
+ return ((int)$num_records > SBI_MAX_RECORDS);
164
+ }
165
+
166
+ /**
167
+ * The plugin caps how many new images are created in a 15 minute window to
168
+ * avoid overloading servers
169
+ *
170
+ * @return bool
171
+ *
172
+ * @since 2.0/4.0
173
+ */
174
+ public function max_resizing_per_time_period_reached() {
175
+ global $wpdb;
176
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
177
+
178
+ $fifteen_minutes_ago = date( 'Y-m-d H:i:s', time() - 15 * 60 );
179
+
180
+ $num_new_records = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE created_on > '$fifteen_minutes_ago'" );
181
+
182
+ return ((int)$num_new_records > 100);
183
+ }
184
+
185
+ /**
186
+ * @return bool
187
+ *
188
+ * @since 2.0/4.0
189
+ */
190
+ public function image_resizing_disabled() {
191
+ $disable_resizing = isset( $this->sbi_options['sb_instagram_disable_resize'] ) ? $this->sbi_options['sb_instagram_disable_resize'] === 'on' || $this->sbi_options['sb_instagram_disable_resize'] === true : false;
192
+
193
+ if ( ! $disable_resizing ) {
194
+ $disable_resizing = isset( $this->resizing_tables_exist ) ? ! $this->resizing_tables_exist : ! $this->does_resizing_tables_exist();
195
+ }
196
+
197
+ return $disable_resizing;
198
+ }
199
+
200
+ /**
201
+ * Used to skip image resizing if the tables were never successfully
202
+ * created
203
+ *
204
+ * @return bool
205
+ *
206
+ * @since 2.0/5.0
207
+ */
208
+ public function does_resizing_tables_exist() {
209
+ global $wpdb;
210
+
211
+ $table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE );
212
+
213
+ if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
214
+ $this->resizing_tables_exist = false;
215
+
216
+ return false;
217
+ }
218
+
219
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
220
+
221
+ if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
222
+ $this->resizing_tables_exist = false;
223
+
224
+ return false;
225
+ }
226
+
227
+ return true;
228
+ }
229
+
230
+ /**
231
+ * Resets the custom tables and deletes all image files
232
+ *
233
+ * @since 2.0/4.0
234
+ */
235
+ public function delete_all_sbi_instagram_posts() {
236
+ $upload = wp_upload_dir();
237
+
238
+ global $wpdb;
239
+
240
+ $posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
241
+
242
+ $image_files = glob( trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) . '*' ); // get all file names
243
+ foreach ( $image_files as $file ) { // iterate files
244
+ if ( is_file( $file ) ) {
245
+ unlink( $file );
246
+ }
247
+ }
248
+
249
+ $options = get_option( 'sb_instagram_settings', array() );
250
+ $connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
251
+
252
+ foreach ( $connected_accounts as $account_id => $data ) {
253
+
254
+ if ( isset( $data['local_avatar'] ) ) {
255
+ $connected_accounts[ $account_id ]['local_avatar'] = false;
256
+ }
257
+
258
+ }
259
+
260
+ $options['connected_accounts'] = $connected_accounts;
261
+
262
+ update_option( 'sb_instagram_settings', $options );
263
+
264
+ //Delete tables
265
+ $wpdb->query( "DROP TABLE IF EXISTS $posts_table_name" );
266
+
267
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
268
+ $wpdb->query( "DROP TABLE IF EXISTS $feeds_posts_table_name" );
269
+
270
+ $table_name = $wpdb->prefix . "options";
271
+
272
+ $wpdb->query( "
273
+ DELETE
274
+ FROM $table_name
275
+ WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
276
+ " );
277
+ $wpdb->query( "
278
+ DELETE
279
+ FROM $table_name
280
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
281
+ " );
282
+ delete_option( 'sbi_hashtag_ids' );
283
+
284
+ $upload = wp_upload_dir();
285
+ $upload_dir = $upload['basedir'];
286
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
287
+ if ( ! file_exists( $upload_dir ) ) {
288
+ $created = wp_mkdir_p( $upload_dir );
289
+ if ( $created ) {
290
+ $this->remove_error( 'upload_dir' );
291
+ } else {
292
+ $this->add_error( 'upload_dir', array( __( 'There was an error creating the folder for storing resized images.', 'instagram-feed' ), $upload_dir ) );
293
+ }
294
+ } else {
295
+ $this->remove_error( 'upload_dir' );
296
+ }
297
+
298
+ sbi_create_database_table();
299
+ }
300
+
301
+ /**
302
+ * @return array
303
+ *
304
+ * @since 2.0/4.0
305
+ */
306
+ public function get_errors() {
307
+ return $this->errors;
308
+ }
309
+
310
+ /**
311
+ * @param $type
312
+ * @param $message_array
313
+ *
314
+ * @since 2.0/4.0
315
+ */
316
+ public function add_error( $type, $message_array ) {
317
+ $this->errors[ $type ] = $message_array;
318
+
319
+ update_option( 'sb_instagram_errors', $this->errors, false );
320
+ }
321
+
322
+ /**
323
+ * @param $type
324
+ *
325
+ * @since 2.0/4.0
326
+ */
327
+ public function remove_error( $type ) {
328
+ if ( isset( $this->errors[ $type ] ) ) {
329
+ unset( $this->errors[ $type ] );
330
+
331
+ update_option( 'sb_instagram_errors', $this->errors, false );
332
+ }
333
+ }
334
+
335
+ /**
336
+ * @param $type
337
+ * @param $message
338
+ *
339
+ * @since 2.0/5.0
340
+ */
341
+ public function add_frontend_error( $type, $message ) {
342
+ $this->frontend_errors[ $type ] = $message;
343
+ }
344
+
345
+ /**
346
+ * @return array
347
+ *
348
+ * @since 2.0/5.0
349
+ */
350
+ public function get_frontend_errors() {
351
+ return $this->frontend_errors;
352
+ }
353
+
354
+ /**
355
+ * @return array
356
+ *
357
+ * @since 2.0/5.0
358
+ */
359
+ public function reset_frontend_errors() {
360
+ return $this->frontend_errors = array();
361
+ }
362
+
363
+ /**
364
+ * @since 2.0/5.1.2
365
+ */
366
+ public function add_api_request_delay( $time_in_seconds = 300, $account_id = false ) {
367
+ if ( $account_id ) {
368
+ set_transient( SBI_USE_BACKUP_PREFIX . 'sbi_' . $account_id, '1', $time_in_seconds );
369
+ } else {
370
+ set_transient( SBI_USE_BACKUP_PREFIX . 'sbi_delay_requests', '1', $time_in_seconds );
371
+ }
372
+ }
373
+
374
+ /**
375
+ * @since 2.0/5.1.2
376
+ */
377
+ public function are_current_api_request_delays( $account_id = false ) {
378
+ $is_delay = (get_transient( SBI_USE_BACKUP_PREFIX . 'sbi_delay_requests' ) !== false);
379
+
380
+ if ( $is_delay ) {
381
+ $error = '<p><b>' . sprintf( __( 'Error: API requests are being delayed.', 'instagram-feed' ) ) . ' ' . __( 'New posts will not be retrieved.', 'instagram-feed' ) . '</b>';
382
+ $error .= '<p>' . __( 'There may be an issue with the Instagram access token that you are using. Your server might also be unable to connect to Instagram at this time.', 'instagram-feed' );
383
+
384
+ $this->add_frontend_error( 'api_delay', $error );
385
+
386
+ }
387
+
388
+ if ( ! $is_delay && $account_id ) {
389
+ $is_delay = (get_transient( SBI_USE_BACKUP_PREFIX . 'sbi_' . $account_id ) !== false);
390
+ }
391
+
392
+ return $is_delay;
393
+ }
394
+ }
inc/class-sb-instagram-settings.php ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SB_Instagram_Settings
4
+ *
5
+ * Creates organized settings from shortcode settings and settings
6
+ * from the options table.
7
+ *
8
+ * Also responsible for creating transient names/feed ids based on
9
+ * feed settings
10
+ *
11
+ * @since 2.0/5.0
12
+ */
13
+
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ die( '-1' );
16
+ }
17
+
18
+ class SB_Instagram_Settings {
19
+ /**
20
+ * @var array
21
+ */
22
+ protected $atts;
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ protected $db;
28
+
29
+ /**
30
+ * @var array
31
+ */
32
+ protected $settings;
33
+
34
+ /**
35
+ * @var array
36
+ */
37
+ protected $feed_type_and_terms;
38
+
39
+ /**
40
+ * @var array
41
+ */
42
+ protected $connected_accounts;
43
+
44
+ /**
45
+ * @var array
46
+ */
47
+ protected $connected_accounts_in_feed;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ protected $transient_name;
53
+
54
+ /**
55
+ * SB_Instagram_Settings constructor.
56
+ *
57
+ * Overwritten in the Pro version.
58
+ *
59
+ * @param array $atts shortcode settings
60
+ * @param array $db settings from the wp_options table
61
+ */
62
+ public function __construct( $atts, $db ) {
63
+ $this->atts = $atts;
64
+ $this->db = $db;
65
+
66
+ $this->connected_accounts = isset( $db['connected_accounts'] ) ? $db['connected_accounts'] : array();
67
+
68
+ $this->settings = shortcode_atts(
69
+ array(
70
+ 'id' => isset( $db['sb_instagram_user_id'] ) ? $db['sb_instagram_user_id'] : '',
71
+ 'width' => isset( $db['sb_instagram_width'] ) ? $db['sb_instagram_width'] : '',
72
+ 'widthunit' => isset( $db['sb_instagram_width_unit'] ) ? $db['sb_instagram_width_unit'] : '',
73
+ 'widthresp' => isset( $db['sb_instagram_feed_width_resp'] ) ? $db['sb_instagram_feed_width_resp'] : '',
74
+ 'height' => isset( $db['sb_instagram_height'] ) ? $db['sb_instagram_height'] : '',
75
+ 'heightunit' => isset( $db['sb_instagram_height_unit'] ) ? $db['sb_instagram_height_unit'] : '',
76
+ 'sortby' => isset( $db['sb_instagram_sort'] ) ? $db['sb_instagram_sort'] : '',
77
+ 'num' => isset( $db['sb_instagram_num'] ) ? $db['sb_instagram_num'] : '',
78
+ 'nummobile' => isset($db[ 'sb_instagram_nummobile' ]) ? $db[ 'sb_instagram_nummobile' ] : '',
79
+ 'cols' => isset( $db['sb_instagram_cols'] ) ? $db['sb_instagram_cols'] : '',
80
+ 'disablemobile' => isset( $db['sb_instagram_disable_mobile'] ) ? $db['sb_instagram_disable_mobile'] : '',
81
+ 'imagepadding' => isset( $db['sb_instagram_image_padding'] ) ? $db['sb_instagram_image_padding'] : '',
82
+ 'imagepaddingunit' => isset( $db['sb_instagram_image_padding_unit'] ) ? $db['sb_instagram_image_padding_unit'] : '',
83
+ 'background' => isset( $db['sb_instagram_background'] ) ? $db['sb_instagram_background'] : '',
84
+ 'showbutton' => isset( $db['sb_instagram_show_btn'] ) ? $db['sb_instagram_show_btn'] : '',
85
+ 'buttoncolor' => isset( $db['sb_instagram_btn_background'] ) ? $db['sb_instagram_btn_background'] : '',
86
+ 'buttontextcolor' => isset( $db['sb_instagram_btn_text_color'] ) ? $db['sb_instagram_btn_text_color'] : '',
87
+ 'buttontext' => isset( $db['sb_instagram_btn_text'] ) ? $db['sb_instagram_btn_text'] : '',
88
+ 'imageres' => isset( $db['sb_instagram_image_res'] ) ? $db['sb_instagram_image_res'] : '',
89
+ 'showfollow' => isset( $db['sb_instagram_show_follow_btn'] ) ? $db['sb_instagram_show_follow_btn'] : '',
90
+ 'followcolor' => isset( $db['sb_instagram_folow_btn_background'] ) ? $db['sb_instagram_folow_btn_background'] : '',
91
+ 'followtextcolor' => isset( $db['sb_instagram_follow_btn_text_color'] ) ? $db['sb_instagram_follow_btn_text_color'] : '',
92
+ 'followtext' => isset( $db['sb_instagram_follow_btn_text'] ) ? $db['sb_instagram_follow_btn_text'] : '',
93
+ 'showheader' => isset( $db['sb_instagram_show_header'] ) ? $db['sb_instagram_show_header'] : '',
94
+ 'headersize' => isset( $db['sb_instagram_header_size'] ) ? $db['sb_instagram_header_size'] : '',
95
+ 'showbio' => isset( $db['sb_instagram_show_bio'] ) ? $db['sb_instagram_show_bio'] : '',
96
+ 'headercolor' => isset( $db['sb_instagram_header_color'] ) ? $db['sb_instagram_header_color'] : '',
97
+ 'class' => '',
98
+ 'ajaxtheme' => isset( $db['sb_instagram_ajax_theme'] ) ? $db['sb_instagram_ajax_theme'] : '',
99
+ 'cachetime' => isset( $db['sb_instagram_cache_time'] ) ? $db['sb_instagram_cache_time'] : '',
100
+ 'media' => isset( $db['sb_instagram_media_type'] ) ? $db['sb_instagram_media_type'] : '',
101
+ 'headeroutside' => isset($db[ 'sb_instagram_outside_scrollable' ]) ? $db[ 'sb_instagram_outside_scrollable' ] : '',
102
+ 'accesstoken' => '',
103
+ 'user' => isset( $db['sb_instagram_user'] ) ? $db['sb_instagram_user'] : false,
104
+ 'feedid' => isset( $db['sb_instagram_feed_id'] ) ? $db['sb_instagram_feed_id'] : false,
105
+ 'resizeprocess' => isset( $db['sb_instagram_resizeprocess'] ) ? $db['sb_instagram_resizeprocess'] : 'background',
106
+ ), $atts );
107
+
108
+ $this->settings['minnum'] = max( (int)$this->settings['num'], (int)$this->settings['nummobile'] );
109
+ $this->settings['disable_resize'] = isset( $db['sb_instagram_disable_resize'] ) && ($db['sb_instagram_disable_resize'] === 'on');
110
+ $this->settings['favor_local'] = isset( $db['sb_instagram_favor_local'] ) && ($db['sb_instagram_favor_local'] === 'on');
111
+ $this->settings['backup_cache_enabled'] = ! isset( $db['sb_instagram_backup'] ) || ($db['sb_instagram_backup'] === 'on');
112
+ $this->settings['font_method'] = isset( $db['sbi_font_method'] ) ? $db['sbi_font_method'] : 'svg';
113
+ $this->settings['headeroutside'] = ($this->settings['headeroutside'] === true || $this->settings['headeroutside'] === 'on' || $this->settings['headeroutside'] === 'true');
114
+ $this->settings['disable_js_image_loading'] = isset( $db['disable_js_image_loading'] ) && ($db['disable_js_image_loading'] === 'on');
115
+ $this->settings['ajax_post_load'] = isset( $db['sb_ajax_initial'] ) && ($db['sb_ajax_initial'] === 'on');
116
+
117
+ switch ( $db['sbi_cache_cron_interval'] ) {
118
+ case '30mins' :
119
+ $this->settings['sbi_cache_cron_interval'] = 60*30;
120
+ break;
121
+ case '1hour' :
122
+ $this->settings['sbi_cache_cron_interval'] = 60*60;
123
+ break;
124
+ default :
125
+ $this->settings['sbi_cache_cron_interval'] = 60*60*12;
126
+ }
127
+
128
+
129
+ global $sb_instagram_posts_manager;
130
+
131
+ if ( $sb_instagram_posts_manager->are_current_api_request_delays() ) {
132
+ $this->settings['alwaysUseBackup'] = true;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @return array
138
+ *
139
+ * @since 2.0/5.0
140
+ */
141
+ public function get_settings() {
142
+ return $this->settings;
143
+ }
144
+
145
+ /**
146
+ * The plugin will output settings on the frontend for debugging purposes.
147
+ * Safe settings to display are added here.
148
+ *
149
+ * @return array
150
+ *
151
+ * @since 2.0/5.0
152
+ */
153
+ public static function get_public_db_settings_keys() {
154
+ $public = array(
155
+ 'sb_instagram_user_id',
156
+ 'sb_instagram_cache_time',
157
+ 'sb_instagram_cache_time_unit',
158
+ 'sbi_caching_type',
159
+ 'sbi_cache_cron_interval',
160
+ 'sbi_cache_cron_time',
161
+ 'sbi_cache_cron_am_pm',
162
+ 'sb_instagram_width',
163
+ 'sb_instagram_width_unit',
164
+ 'sb_instagram_feed_width_resp',
165
+ 'sb_instagram_height',
166
+ 'sb_instagram_num',
167
+ 'sb_instagram_height_unit',
168
+ 'sb_instagram_cols',
169
+ 'sb_instagram_disable_mobile',
170
+ 'sb_instagram_image_padding',
171
+ 'sb_instagram_image_padding_unit',
172
+ 'sb_instagram_sort',
173
+ 'sb_instagram_background',
174
+ 'sb_instagram_show_btn',
175
+ 'sb_instagram_btn_background',
176
+ 'sb_instagram_btn_text_color',
177
+ 'sb_instagram_btn_text',
178
+ 'sb_instagram_image_res',
179
+ //Header
180
+ 'sb_instagram_show_header',
181
+ 'sb_instagram_header_size',
182
+ 'sb_instagram_header_color',
183
+ //Follow button
184
+ 'sb_instagram_show_follow_btn',
185
+ 'sb_instagram_folow_btn_background',
186
+ 'sb_instagram_follow_btn_text_color',
187
+ 'sb_instagram_follow_btn_text',
188
+ //Misc
189
+ 'sb_instagram_cron',
190
+ 'sb_instagram_backup',
191
+ 'sb_instagram_ajax_theme',
192
+ 'sb_instagram_disable_resize',
193
+ 'disable_js_image_loading',
194
+ 'enqueue_js_in_head',
195
+ 'sbi_font_method',
196
+ 'sb_instagram_disable_awesome'
197
+ );
198
+
199
+ return $public;
200
+ }
201
+
202
+ /**
203
+ * @return array
204
+ *
205
+ * @since 2.0/5.0
206
+ */
207
+ public function get_connected_accounts() {
208
+ return $this->connected_accounts;
209
+ }
210
+
211
+ /**
212
+ * @return array|bool
213
+ *
214
+ * @since 2.0/5.0
215
+ */
216
+ public function get_connected_accounts_in_feed() {
217
+ if ( isset( $this->connected_accounts_in_feed ) ) {
218
+ return $this->connected_accounts_in_feed;
219
+ } else {
220
+ return false;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * @return bool|string
226
+ *
227
+ * @since 2.0/5.0
228
+ */
229
+ public function get_transient_name() {
230
+ if ( isset( $this->transient_name ) ) {
231
+ return $this->transient_name;
232
+ } else {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Uses the feed types and terms as well as as some
239
+ * settings to create a semi-unique feed id used for
240
+ * caching and other features.
241
+ *
242
+ * Overwritten in the Pro version.
243
+ *
244
+ * @param string $transient_name
245
+ *
246
+ * @since 2.0/5.0
247
+ */
248
+ public function set_transient_name( $transient_name = '' ) {
249
+
250
+ if ( ! empty( $transient_name ) ) {
251
+ $this->transient_name = $transient_name;
252
+ } elseif ( ! empty( $this->settings['feedid'] ) ) {
253
+ $this->transient_name = 'sbi_' . $this->settings['feedid'];
254
+ } else {
255
+ $feed_type_and_terms = $this->feed_type_and_terms;
256
+
257
+ $sbi_transient_name = 'sbi_';
258
+
259
+ if ( isset( $feed_type_and_terms['users'] ) ) {
260
+ foreach ( $feed_type_and_terms['users'] as $term_and_params ) {
261
+ $user = $term_and_params['term'];
262
+ $connected_account = $this->connected_accounts_in_feed[ $user ];
263
+ if ( isset( $connected_account['type'] ) && $connected_account['type'] === 'business' ) {
264
+ $sbi_transient_name .= $connected_account['username'];
265
+ } else {
266
+ $sbi_transient_name .= $user;
267
+ }
268
+ }
269
+ }
270
+
271
+ $num = $this->settings['num'];
272
+
273
+ $num_length = strlen( $num ) + 1;
274
+
275
+ //Add both parts of the caching string together and make sure it doesn't exceed 45
276
+ $sbi_transient_name = substr( $sbi_transient_name, 0, 45 - $num_length );
277
+
278
+ $sbi_transient_name .= '#' . $num;
279
+
280
+ $this->transient_name = $sbi_transient_name;
281
+ }
282
+
283
+ }
284
+
285
+ /**
286
+ * @return array|bool
287
+ *
288
+ * @since 2.0/5.0
289
+ */
290
+ public function get_feed_type_and_terms() {
291
+ if ( isset( $this->feed_type_and_terms ) ) {
292
+ return $this->feed_type_and_terms;
293
+ } else {
294
+ return false;
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Based on the settings related to retrieving post data from the API,
300
+ * this setting is used to make sure all endpoints needed for the feed are
301
+ * connected and stored for easily looping through when adding posts
302
+ *
303
+ * Overwritten in the Pro version.
304
+ *
305
+ * @since 2.0/5.0
306
+ */
307
+ public function set_feed_type_and_terms() {
308
+ global $sb_instagram_posts_manager;
309
+
310
+ $connected_accounts_in_feed = array();
311
+ $feed_type_and_terms = array(
312
+ 'users' => array()
313
+ );
314
+ $usernames_included = array();
315
+
316
+ if ( ! empty( $this->atts['accesstoken'] ) && strpos( $this->atts['accesstoken'], '.' ) !== false ) {
317
+ $access_tokens = explode( ',', str_replace( ' ', '', $this->atts['accesstoken'] ) );
318
+
319
+ foreach ( $access_tokens as $access_token ) {
320
+ $split_token = explode( '.', $access_token );
321
+ $connected_accounts_in_feed[ $split_token[0] ] = array(
322
+ 'access_token' => $access_token,
323
+ 'user_id' => $split_token[0]
324
+ );
325
+ $feed_type_and_terms['users'][] = array(
326
+ 'term' => $split_token[0],
327
+ 'params' => array()
328
+ );
329
+ }
330
+
331
+ } elseif ( ! empty( $this->settings['user'] ) ) {
332
+ $user_array = is_array( $this->settings['user'] ) ? $this->settings['user'] : explode( ',', str_replace( ' ', '', $this->settings['user'] ) );
333
+ foreach ( $user_array as $user ) {
334
+ $user_found = false;
335
+ if ( isset( $this->connected_accounts[ $user ] ) ) {
336
+ if ( ! in_array( $this->connected_accounts[ $user ]['username'], $usernames_included, true ) ) {
337
+ $feed_type_and_terms['users'][] = array(
338
+ 'term' => $this->connected_accounts[ $user ]['user_id'],
339
+ 'params' => array()
340
+ );
341
+ $connected_accounts_in_feed[ $this->connected_accounts[ $user ]['user_id'] ] = $this->connected_accounts[ $user ];
342
+ $usernames_included[] = $this->connected_accounts[ $user ]['username'];
343
+ }
344
+ } else {
345
+
346
+ foreach ( $this->connected_accounts as $connected_account ) {
347
+ if ( strtolower( $user ) === strtolower( $connected_account['username'] ) ) {
348
+ if ( ! in_array( $connected_account['username'], $usernames_included, true ) ) {
349
+ if ( isset( $connected_account['type'] ) && $connected_account['type'] === 'business' ) {
350
+ $feed_type_and_terms['users'][] = array(
351
+ 'term' => $user,
352
+ 'params' => array()
353
+ );
354
+ $connected_accounts_in_feed[ $user ] = $connected_account;
355
+ } else {
356
+ $feed_type_and_terms['users'][] = array(
357
+ 'term' => $connected_account['user_id'],
358
+ 'params' => array()
359
+ );
360
+ $connected_accounts_in_feed[ $connected_account['user_id'] ] = $connected_account;
361
+ }
362
+ $usernames_included[] = $connected_account['username'];
363
+ $user_found = true;
364
+ }
365
+ }
366
+ }
367
+
368
+ if ( ! $user_found ) {
369
+ $error = '<p><b>' . sprintf( __( 'Error: There is no connected account for the user %s.', 'instagram-feed' ), $user ) . ' ' . __( 'Feed will not update.', 'instagram-feed' ) . '</b>';
370
+
371
+ $sb_instagram_posts_manager->add_frontend_error( 'no_connection_' . $user, $error );
372
+ }
373
+
374
+ }
375
+
376
+ }
377
+
378
+ } elseif ( ! empty( $this->settings['id'] ) ) {
379
+ $user_id_array = is_array( $this->settings['id'] ) ? $this->settings['id'] : explode( ',', str_replace( ' ', '', $this->settings['id'] ) );
380
+
381
+ foreach ( $user_id_array as $user ) {
382
+ $user_found = false;
383
+
384
+ if ( isset( $this->connected_accounts[ $user ] ) ) {
385
+ if ( ! in_array( $this->connected_accounts[ $user ]['username'], $usernames_included, true ) ) {
386
+ $feed_type_and_terms['users'][] = array(
387
+ 'term' => $this->connected_accounts[ $user ]['user_id'],
388
+ 'params' => array()
389
+ );
390
+ $connected_accounts_in_feed[ $this->connected_accounts[ $user ]['user_id'] ] = $this->connected_accounts[ $user ];
391
+ $usernames_included[] = $this->connected_accounts[ $user ]['username'];
392
+ }
393
+
394
+ } else {
395
+
396
+ foreach ( $this->connected_accounts as $connected_account ) {
397
+ if ( strtolower( $user ) === strtolower( $connected_account['username'] ) ) {
398
+ if ( ! in_array( $this->connected_accounts[ $user ]['username'], $usernames_included, true ) ) {
399
+ if ( isset( $connected_account['type'] ) && $connected_account['type'] === 'business' ) {
400
+ $feed_type_and_terms['users'][] = array(
401
+ 'term' => $user,
402
+ 'params' => array()
403
+ );
404
+ $connected_accounts_in_feed[ $user ] = $connected_account;
405
+ } else {
406
+ $feed_type_and_terms['users'][] = array(
407
+ 'term' => $connected_account['user_id'],
408
+ 'params' => array()
409
+ );
410
+ $connected_accounts_in_feed[ $connected_account['user_id'] ] = $connected_account;
411
+ }
412
+ $usernames_included[] = $this->connected_accounts[ $user ]['username'];
413
+ $user_found = true;
414
+ }
415
+ }
416
+ }
417
+
418
+ if ( ! $user_found ) {
419
+ $error = '<p><b>' . sprintf( __( 'Error: There is no connected account for the user %s', 'instagram-feed' ), $user ) . ' ' . __( 'Feed will not update.', 'instagram-feed' ) . '</b>';
420
+
421
+ $sb_instagram_posts_manager->add_frontend_error( 'no_connection_' . $user, $error );
422
+ }
423
+
424
+ }
425
+
426
+ }
427
+
428
+ } else {
429
+ foreach ( $this->connected_accounts as $connected_account ) {
430
+ if ( empty( $feed_type_and_terms['users'] ) ) {
431
+ if ( isset( $connected_account['type'] ) && $connected_account['type'] === 'business' ) {
432
+ $feed_type_and_terms['users'][] = array(
433
+ 'term' => $connected_account['username'],
434
+ 'params' => array()
435
+ );
436
+ $connected_accounts_in_feed[ $connected_account['username'] ] = $connected_account;
437
+ } else {
438
+ $feed_type_and_terms['users'][] = array(
439
+ 'term' => $connected_account['user_id'],
440
+ 'params' => array()
441
+ );
442
+ $connected_accounts_in_feed[ $connected_account['user_id'] ] = $connected_account;
443
+ }
444
+ }
445
+
446
+ }
447
+ }
448
+
449
+ $this->connected_accounts_in_feed = $connected_accounts_in_feed;
450
+ $this->feed_type_and_terms = $feed_type_and_terms;
451
+ }
452
+
453
+ /**
454
+ * @return float|int
455
+ *
456
+ * @since 2.0/5.0
457
+ */
458
+ public function get_cache_time_in_seconds() {
459
+ if ( $this->db['sbi_caching_type'] === 'background' ) {
460
+ return SBI_CRON_UPDATE_CACHE_TIME;
461
+ } else {
462
+ //If the caching time doesn't exist in the database then set it to be 1 hour
463
+ $cache_time = isset( $settings['sb_instagram_cache_time'] ) ? (int)$this->settings['sb_instagram_cache_time'] : 1;
464
+ $cache_time_unit = isset( $settings['sb_instagram_cache_time_unit'] ) ? $this->settings['sb_instagram_cache_time_unit'] : 'hours';
465
+
466
+ //Calculate the cache time in seconds
467
+ if ( $cache_time_unit == 'minutes' ) $cache_time_unit = 60;
468
+ if ( $cache_time_unit == 'hours' ) $cache_time_unit = 60*60;
469
+ if ( $cache_time_unit == 'days' ) $cache_time_unit = 60*60*24;
470
+ return $cache_time * $cache_time_unit;
471
+ }
472
+ }
473
+ }
inc/if-functions.php ADDED
@@ -0,0 +1,884 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Contains functions used primarily on the frontend but some also used in the
4
+ * admin area.
5
+ *
6
+ * - Function for the shortcode that displays the feed
7
+ * - AJAX call for pagination
8
+ * - All AJAX calls for image resizing triggering
9
+ * - Clearing page caches for caching plugins
10
+ * - Starting cron caching
11
+ * - Getting settings from the database
12
+ * - Displaying frontend errors
13
+ * - Enqueueing CSS and JS files for the feed
14
+ *
15
+ */
16
+ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
17
+
18
+ /**
19
+ * The main function the creates the feed from a shortcode.
20
+ * Can be safely added directly to templates using
21
+ * 'echo do_shortcode( "[instagram-feed]" );'
22
+ */
23
+ add_shortcode('instagram-feed', 'display_instagram');
24
+ function display_instagram( $atts = array() ) {
25
+
26
+ $database_settings = sbi_get_database_settings();
27
+
28
+ if ( $database_settings['sb_instagram_ajax_theme'] !== 'on' && $database_settings['sb_instagram_ajax_theme'] !== 'true' ) {
29
+ wp_enqueue_script( 'sb_instagram_scripts' );
30
+ }
31
+
32
+ if ( $database_settings['enqueue_css_in_shortcode'] === 'on' || $database_settings['enqueue_css_in_shortcode'] === 'true' ) {
33
+ wp_enqueue_style( 'sb_instagram_styles' );
34
+ }
35
+ $instagram_feed_settings = new SB_Instagram_Settings( $atts, $database_settings );
36
+
37
+ if ( empty( $database_settings['connected_accounts'] ) && empty( $atts['accesstoken'] ) ) {
38
+ $style = current_user_can( 'manage_instagram_feed_options' ) ? ' style="display: block;"' : '';
39
+ ob_start(); ?>
40
+ <div id="sbi_mod_error" <?php echo $style; ?>>
41
+ <span><?php _e('This error message is only visible to WordPress admins', 'instagram-feed' ); ?></span><br />
42
+ <p><b><?php _e( 'Error: No connected account.', 'instagram-feed' ); ?></b>
43
+ <p><?php _e( 'Please go to the Instagram Feed settings page to connect an account.', 'instagram-feed' ); ?></p>
44
+ </div>
45
+ <?php
46
+ $html = ob_get_contents();
47
+ ob_get_clean();
48
+ return $html;
49
+ }
50
+
51
+ $instagram_feed_settings->set_feed_type_and_terms();
52
+ $instagram_feed_settings->set_transient_name();
53
+ $transient_name = $instagram_feed_settings->get_transient_name();
54
+ $settings = $instagram_feed_settings->get_settings();
55
+ $feed_type_and_terms = $instagram_feed_settings->get_feed_type_and_terms();
56
+
57
+ $instagram_feed = new SB_Instagram_Feed( $transient_name );
58
+
59
+ if ( $database_settings['sbi_caching_type'] === 'background' ) {
60
+ $instagram_feed->add_report( 'background caching used' );
61
+ if ( $instagram_feed->regular_cache_exists() ) {
62
+ $instagram_feed->add_report( 'setting posts from cache' );
63
+ $instagram_feed->set_post_data_from_cache();
64
+ }
65
+
66
+ if ( $instagram_feed->need_to_start_cron_job() ) {
67
+ $instagram_feed->add_report( 'setting up feed for cron cache' );
68
+ $to_cache = array(
69
+ 'atts' => $atts,
70
+ 'last_requested' => time(),
71
+ );
72
+
73
+ $instagram_feed->set_cron_cache( $to_cache, $instagram_feed_settings->get_cache_time_in_seconds() );
74
+
75
+ SB_Instagram_Cron_Updater::do_single_feed_cron_update( $instagram_feed_settings, $to_cache, $atts, false );
76
+
77
+ $instagram_feed->set_post_data_from_cache();
78
+
79
+ } elseif ( $instagram_feed->should_update_last_requested() ) {
80
+ $instagram_feed->add_report( 'updating last requested' );
81
+ $to_cache = array(
82
+ 'last_requested' => time(),
83
+ );
84
+
85
+ $instagram_feed->set_cron_cache( $to_cache, $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
86
+ }
87
+
88
+ } elseif ( $instagram_feed->regular_cache_exists() ) {
89
+ $instagram_feed->add_report( 'page load caching used and regular cache exists' );
90
+ $instagram_feed->set_post_data_from_cache();
91
+
92
+ if ( $instagram_feed->need_posts( $settings['num'] ) && $instagram_feed->can_get_more_posts() ) {
93
+ while ( $instagram_feed->need_posts( $settings['num'] ) && $instagram_feed->can_get_more_posts() ) {
94
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
95
+ }
96
+ $instagram_feed->cache_feed_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
97
+ }
98
+
99
+ } else {
100
+ $instagram_feed->add_report( 'no feed cache found' );
101
+
102
+ while ( $instagram_feed->need_posts( $settings['num'] ) && $instagram_feed->can_get_more_posts() ) {
103
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
104
+ }
105
+
106
+ if ( ! $instagram_feed->should_use_backup() ) {
107
+ $instagram_feed->cache_feed_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
108
+ }
109
+
110
+ }
111
+
112
+ if ( $instagram_feed->should_use_backup() ) {
113
+ $instagram_feed->add_report( 'trying to use backup' );
114
+ $instagram_feed->maybe_set_post_data_from_backup();
115
+ $instagram_feed->maybe_set_header_data_from_backup();
116
+ }
117
+
118
+ // if need a header
119
+ if ( $instagram_feed->need_header( $settings, $feed_type_and_terms ) && ! $instagram_feed->should_use_backup() ) {
120
+ if ( $database_settings['sbi_caching_type'] === 'background' ) {
121
+ $instagram_feed->add_report( 'background header caching used' );
122
+ $instagram_feed->set_header_data_from_cache();
123
+ } elseif ( $instagram_feed->regular_header_cache_exists() ) {
124
+ // set_post_data_from_cache
125
+ $instagram_feed->add_report( 'page load caching used and regular header cache exists' );
126
+ $instagram_feed->set_header_data_from_cache();
127
+ } else {
128
+ $instagram_feed->add_report( 'no header cache exists' );
129
+ $instagram_feed->set_remote_header_data( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
130
+
131
+ $instagram_feed->cache_header_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
132
+ }
133
+ } else {
134
+ $instagram_feed->add_report( 'no header needed' );
135
+ }
136
+
137
+ if ( $settings['resizeprocess'] === 'page' ) {
138
+ $instagram_feed->add_report( 'resizing images for post set' );
139
+ $post_data = $instagram_feed->get_post_data();
140
+ $post_data = array_slice( $post_data, 0, $settings['num'] );
141
+
142
+ $post_set = new SB_Instagram_Post_Set( $post_data, $transient_name );
143
+
144
+ $post_set->maybe_save_update_and_resize_images_for_posts();
145
+ }
146
+
147
+ return $instagram_feed->get_the_feed_html( $settings, $atts, $instagram_feed_settings->get_feed_type_and_terms(), $instagram_feed_settings->get_connected_accounts_in_feed() );
148
+ }
149
+
150
+ /**
151
+ * For efficiency, local versions of image files available for the images actually displayed on the page
152
+ * are added at the end of the feed.
153
+ *
154
+ * @param object $instagram_feed
155
+ * @param string $feed_id
156
+ */
157
+ function sbi_add_resized_image_data( $instagram_feed, $feed_id ) {
158
+ global $sb_instagram_posts_manager;
159
+
160
+ if ( ! $sb_instagram_posts_manager->image_resizing_disabled() ) {
161
+ SB_Instagram_Feed::update_last_requested( $instagram_feed->get_image_ids_post_set() );
162
+ }
163
+ ?>
164
+ <span class="sbi_resized_image_data" data-feed-id="<?php echo esc_attr( $feed_id ); ?>" data-resized="<?php echo esc_attr( wp_json_encode( SB_Instagram_Feed::get_resized_images_source_set( $instagram_feed->get_image_ids_post_set(), 0, $feed_id ) ) ); ?>">
165
+ </span>
166
+ <?php
167
+ }
168
+ add_action( 'sbi_before_feed_end', 'sbi_add_resized_image_data', 10, 2 );
169
+
170
+ /**
171
+ * Called after the load more button is clicked using admin-ajax.php.
172
+ * Resembles "display_instagram"
173
+ */
174
+ function sbi_get_next_post_set() {
175
+ if ( ! isset( $_POST['feed_id'] ) || strpos( $_POST['feed_id'], 'sbi' ) === false ) {
176
+ die( 'invalid feed ID');
177
+ }
178
+
179
+ $feed_id = sanitize_text_field( $_POST['feed_id'] );
180
+ $atts_raw = isset( $_POST['atts'] ) ? json_decode( stripslashes( $_POST['atts'] ), true ) : array();
181
+ if ( is_array( $atts_raw ) ) {
182
+ array_map( 'sanitize_text_field', $atts_raw );
183
+ } else {
184
+ $atts_raw = array();
185
+ }
186
+ $atts = $atts_raw; // now sanitized
187
+
188
+ $offset = isset( $_POST['offset'] ) ? (int)$_POST['offset'] : 0;
189
+
190
+ $database_settings = sbi_get_database_settings();
191
+ $instagram_feed_settings = new SB_Instagram_Settings( $atts, $database_settings );
192
+
193
+ if ( empty( $database_settings['connected_accounts'] ) && empty( $atts['accesstoken'] ) ) {
194
+ die( 'error no connected account' );
195
+ }
196
+
197
+ $instagram_feed_settings->set_feed_type_and_terms();
198
+ $instagram_feed_settings->set_transient_name();
199
+ $transient_name = $instagram_feed_settings->get_transient_name();
200
+
201
+ if ( $transient_name !== $feed_id ) {
202
+ die( 'id does not match' );
203
+ }
204
+
205
+ $settings = $instagram_feed_settings->get_settings();
206
+ $current_image_resolution = isset( $_POST['current_resolution'] ) ? (int)$_POST['current_resolution'] : 640;
207
+
208
+ switch ( $current_image_resolution ) {
209
+ case 150 :
210
+ $settings['imageres'] = 'thumb';
211
+ break;
212
+ case 320 :
213
+ $settings['imageres'] = 'medium';
214
+ break;
215
+ default :
216
+ $settings['imageres'] = 'full';
217
+ }
218
+
219
+ $feed_type_and_terms = $instagram_feed_settings->get_feed_type_and_terms();
220
+
221
+ $instagram_feed = new SB_Instagram_Feed( $transient_name );
222
+ if ( $database_settings['sbi_caching_type'] === 'background' ) {
223
+ $instagram_feed->add_report( 'background caching used' );
224
+ if ( $instagram_feed->regular_cache_exists() ) {
225
+ $instagram_feed->add_report( 'setting posts from cache' );
226
+ $instagram_feed->set_post_data_from_cache();
227
+ }
228
+
229
+ if ( $instagram_feed->need_posts( $settings['num'], $offset ) && $instagram_feed->can_get_more_posts() ) {
230
+ while ( $instagram_feed->need_posts( $settings['num'], $offset ) && $instagram_feed->can_get_more_posts() ) {
231
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
232
+ }
233
+
234
+ if ( $instagram_feed->need_to_start_cron_job() ) {
235
+ $instagram_feed->add_report( 'needed to start cron job' );
236
+ $to_cache = array(
237
+ 'atts' => $atts,
238
+ 'last_requested' => time(),
239
+ );
240
+
241
+ $instagram_feed->set_cron_cache( $to_cache, $instagram_feed_settings->get_cache_time_in_seconds() );
242
+
243
+ } else {
244
+ $instagram_feed->add_report( 'updating last requested and adding to cache' );
245
+ $to_cache = array(
246
+ 'last_requested' => time(),
247
+ );
248
+
249
+ $instagram_feed->set_cron_cache( $to_cache, $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
250
+ }
251
+ }
252
+
253
+ } elseif ( $instagram_feed->regular_cache_exists() ) {
254
+ $instagram_feed->add_report( 'regular cache exists' );
255
+ $instagram_feed->set_post_data_from_cache();
256
+
257
+ if ( $instagram_feed->need_posts( $settings['num'], $offset ) && $instagram_feed->can_get_more_posts() ) {
258
+ while ( $instagram_feed->need_posts( $settings['num'], $offset ) && $instagram_feed->can_get_more_posts() ) {
259
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
260
+ }
261
+
262
+ $instagram_feed->add_report( 'adding to cache' );
263
+ $instagram_feed->cache_feed_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
264
+ }
265
+
266
+
267
+ } else {
268
+ $instagram_feed->add_report( 'no feed cache found' );
269
+
270
+ while ( $instagram_feed->need_posts( $settings['num'], $offset ) && $instagram_feed->can_get_more_posts() ) {
271
+ $instagram_feed->add_remote_posts( $settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed() );
272
+ }
273
+
274
+ if ( $instagram_feed->should_use_backup() ) {
275
+ $instagram_feed->add_report( 'trying to use a backup cache' );
276
+ $instagram_feed->maybe_set_post_data_from_backup();
277
+ } else {
278
+ $instagram_feed->add_report( 'transient gone, adding to cache' );
279
+ $instagram_feed->cache_feed_data( $instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled'] );
280
+ }
281
+
282
+ }
283
+
284
+ $feed_status = array( 'shouldPaginate' => $instagram_feed->should_use_pagination( $settings, $offset ) );
285
+
286
+ $return = array(
287
+ 'html' => $instagram_feed->get_the_items_html( $settings, $offset, $instagram_feed_settings->get_feed_type_and_terms(), $instagram_feed_settings->get_connected_accounts_in_feed() ),
288
+ 'feedStatus' => $feed_status,
289
+ 'report' => $instagram_feed->get_report(),
290
+ 'resizedImages' => SB_Instagram_Feed::get_resized_images_source_set( $instagram_feed->get_image_ids_post_set(), 0, $feed_id )
291
+ );
292
+
293
+ echo wp_json_encode( $return );
294
+
295
+ global $sb_instagram_posts_manager;
296
+
297
+ $sb_instagram_posts_manager->update_successful_ajax_test();
298
+
299
+ die();
300
+ }
301
+ add_action( 'wp_ajax_sbi_load_more_clicked', 'sbi_get_next_post_set' );
302
+ add_action( 'wp_ajax_nopriv_sbi_load_more_clicked', 'sbi_get_next_post_set' );
303
+
304
+ /**
305
+ * Posts that need resized images are processed after being sent to the server
306
+ * using AJAX
307
+ *
308
+ * @return string
309
+ */
310
+ function sbi_process_submitted_resize_ids() {
311
+ if ( ! isset( $_POST['feed_id'] ) || strpos( $_POST['feed_id'], 'sbi' ) === false ) {
312
+ die( 'invalid feed ID');
313
+ }
314
+
315
+ $feed_id = sanitize_text_field( $_POST['feed_id'] );
316
+ $images_need_resizing_raw = isset( $_POST['needs_resizing'] ) ? $_POST['needs_resizing'] : array();
317
+ if ( is_array( $images_need_resizing_raw ) ) {
318
+ array_map( 'sanitize_text_field', $images_need_resizing_raw );
319
+ } else {
320
+ $images_need_resizing_raw = array();
321
+ }
322
+ $images_need_resizing = $images_need_resizing_raw;
323
+
324
+ $atts_raw = isset( $_POST['atts'] ) ? json_decode( stripslashes( $_POST['atts'] ), true ) : array();
325
+ if ( is_array( $atts_raw ) ) {
326
+ array_map( 'sanitize_text_field', $atts_raw );
327
+ } else {
328
+ $atts_raw = array();
329
+ }
330
+ $atts = $atts_raw; // now sanitized
331
+
332
+ $offset = isset( $_POST['offset'] ) ? (int)$_POST['offset'] : 0;
333
+
334
+ $database_settings = sbi_get_database_settings();
335
+ $instagram_feed_settings = new SB_Instagram_Settings( $atts, $database_settings );
336
+
337
+ if ( empty( $database_settings['connected_accounts'] ) && empty( $atts['accesstoken'] ) ) {
338
+ return '<div class="sb_instagram_error"><p>' . __( 'Please connect an account on the Instagram Feed plugin Settings page.', 'instagram-feed' ) . '</p></div>';
339
+ }
340
+
341
+ $instagram_feed_settings->set_feed_type_and_terms();
342
+ $instagram_feed_settings->set_transient_name();
343
+ $transient_name = $instagram_feed_settings->get_transient_name();
344
+
345
+ if ( $transient_name !== $feed_id ) {
346
+ die( 'id does not match' );
347
+ }
348
+
349
+ sbi_resize_posts_by_id( $images_need_resizing, $transient_name, $instagram_feed_settings->get_settings() );
350
+
351
+ global $sb_instagram_posts_manager;
352
+
353
+ $sb_instagram_posts_manager->update_successful_ajax_test();
354
+
355
+ die();
356
+ }
357
+ add_action( 'wp_ajax_sbi_resized_images_submit', 'sbi_process_submitted_resize_ids' );
358
+ add_action( 'wp_ajax_nopriv_sbi_resized_images_submit', 'sbi_process_submitted_resize_ids' );
359
+
360
+ /**
361
+ * Used for testing if admin-ajax.php can be successfully reached using
362
+ * AJAX in the frontend
363
+ */
364
+ function sbi_update_successful_ajax() {
365
+
366
+ global $sb_instagram_posts_manager;
367
+
368
+ delete_transient( 'sb_instagram_doing_ajax_test' );
369
+
370
+ $sb_instagram_posts_manager->update_successful_ajax_test();
371
+
372
+ die();
373
+ }
374
+ add_action( 'wp_ajax_sbi_on_ajax_test_trigger', 'sbi_update_successful_ajax' );
375
+ add_action( 'wp_ajax_nopriv_sbi_on_ajax_test_trigger', 'sbi_update_successful_ajax' );
376
+
377
+ /**
378
+ * Outputs an organized error report for the front end.
379
+ * This hooks into the end of the feed before the closing div
380
+ *
381
+ * @param object $instagram_feed
382
+ * @param string $feed_id
383
+ */
384
+ function sbi_error_report( $instagram_feed, $feed_id ) {
385
+ global $sb_instagram_posts_manager;
386
+
387
+ $style = current_user_can( 'manage_instagram_feed_options' ) ? ' style="display: block;"' : '';
388
+
389
+ $error_messages = $sb_instagram_posts_manager->get_frontend_errors();
390
+ if ( ! empty( $error_messages ) ) {?>
391
+ <div id="sbi_mod_error"<?php echo $style; ?>>
392
+ <span><?php _e('This error message is only visible to WordPress admins', 'instagram-feed' ); ?></span><br />
393
+ <?php foreach ( $error_messages as $error_message ) {
394
+ echo $error_message;
395
+ } ?>
396
+ </div>
397
+ <?php
398
+ }
399
+
400
+ $sb_instagram_posts_manager->reset_frontend_errors();
401
+ }
402
+ add_action( 'sbi_before_feed_end', 'sbi_error_report', 10, 2 );
403
+
404
+ /**
405
+ * Debug report added at the end of the feed when sbi_debug query arg is added to a page
406
+ * that has the feed on it.
407
+ *
408
+ * @param object $instagram_feed
409
+ * @param string $feed_id
410
+ */
411
+ function sbi_debug_report( $instagram_feed, $feed_id ) {
412
+
413
+ if ( ! isset( $_GET['sbi_debug'] ) ) {
414
+ return;
415
+ }
416
+
417
+ ?>
418
+ <p>Status</p>
419
+ <ul>
420
+ <li>Time: <?php echo date( "Y-m-d H:i:s", time() ); ?></li>
421
+ <?php foreach ( $instagram_feed->get_report() as $item ) : ?>
422
+ <li><?php echo esc_html( $item ); ?></li>
423
+ <?php endforeach; ?>
424
+
425
+ </ul>
426
+
427
+ <?php
428
+ $database_settings = sbi_get_database_settings();
429
+
430
+ $public_settings_keys = SB_Instagram_Settings::get_public_db_settings_keys();
431
+ ?>
432
+ <p>Settings</p>
433
+ <ul>
434
+ <?php foreach ( $public_settings_keys as $key ) : if ( isset( $database_settings[ $key ] ) ) : ?>
435
+ <li>
436
+ <small><?php echo esc_html( $key ); ?>:</small>
437
+ <?php if ( ! is_array( $database_settings[ $key ] ) ) :
438
+ echo $database_settings[ $key ];
439
+ else : ?>
440
+ <pre>
441
+ <?php var_export( $database_settings[ $key ] ); ?>
442
+ </pre>
443
+ <?php endif; ?>
444
+ </li>
445
+
446
+ <?php endif; endforeach; ?>
447
+ </ul>
448
+ <?php
449
+ }
450
+ add_action( 'sbi_before_feed_end', 'sbi_debug_report', 11, 2 );
451
+
452
+ /**
453
+ * Uses post IDs to process images that may need resizing
454
+ *
455
+ * @param array $ids
456
+ * @param string $transient_name
457
+ * @param array $settings
458
+ * @param int $offset
459
+ */
460
+ function sbi_resize_posts_by_id( $ids, $transient_name, $settings, $offset = 0 ) {
461
+ $instagram_feed = new SB_Instagram_Feed( $transient_name );
462
+
463
+ if ( $instagram_feed->regular_cache_exists() ) {
464
+ // set_post_data_from_cache
465
+ $instagram_feed->set_post_data_from_cache();
466
+
467
+ $cached_post_data = $instagram_feed->get_post_data();
468
+
469
+ $num_ids = count( $ids );
470
+ $found_posts = array();
471
+ $i = 0;
472
+ while ( count( $found_posts) < $num_ids && isset( $cached_post_data[ $i ] ) ) {
473
+ if ( ! empty( $cached_post_data[ $i ]['id'] ) && in_array( $cached_post_data[ $i ]['id'], $ids, true ) ) {
474
+ $found_posts[] = $cached_post_data[ $i ];
475
+ }
476
+ $i++;
477
+ }
478
+
479
+ $fill_in_timestamp = date( 'Y-m-d H:i:s', time() + 120 );
480
+
481
+ if ( $offset !== 0 ) {
482
+ $fill_in_timestamp = date( 'Y-m-d H:i:s', strtotime( $instagram_feed->get_earliest_time_stamp() ) - 120 );
483
+ }
484
+
485
+ $post_set = new SB_Instagram_Post_Set( $found_posts, $transient_name, $fill_in_timestamp );
486
+
487
+ $post_set->maybe_save_update_and_resize_images_for_posts();
488
+ }
489
+ }
490
+
491
+ /**
492
+ * Get the settings in the database with defaults
493
+ *
494
+ * @return array
495
+ */
496
+ function sbi_get_database_settings() {
497
+ $defaults = array(
498
+ 'sb_instagram_at' => '',
499
+ 'sb_instagram_user_id' => '',
500
+ 'sb_instagram_preserve_settings' => '',
501
+ 'sb_instagram_ajax_theme' => false,
502
+ 'sb_instagram_disable_resize' => false,
503
+ 'sb_instagram_cache_time' => 1,
504
+ 'sb_instagram_cache_time_unit' => 'hours',
505
+ 'sbi_caching_type' => 'page',
506
+ 'sbi_cache_cron_interval' => '12hours',
507
+ 'sbi_cache_cron_time' => '1',
508
+ 'sbi_cache_cron_am_pm' => 'am',
509
+ 'sb_instagram_width' => '100',
510
+ 'sb_instagram_width_unit' => '%',
511
+ 'sb_instagram_feed_width_resp' => false,
512
+ 'sb_instagram_height' => '',
513
+ 'sb_instagram_num' => '20',
514
+ 'sb_instagram_height_unit' => '',
515
+ 'sb_instagram_cols' => '4',
516
+ 'sb_instagram_disable_mobile' => false,
517
+ 'sb_instagram_image_padding' => '5',
518
+ 'sb_instagram_image_padding_unit' => 'px',
519
+ 'sb_instagram_sort' => 'none',
520
+ 'sb_instagram_background' => '',
521
+ 'sb_instagram_show_btn' => true,
522
+ 'sb_instagram_btn_background' => '',
523
+ 'sb_instagram_btn_text_color' => '',
524
+ 'sb_instagram_btn_text' => __( 'Load More...', 'instagram-feed' ),
525
+ 'sb_instagram_image_res' => 'auto',
526
+ //Header
527
+ 'sb_instagram_show_header' => true,
528
+ 'sb_instagram_header_size' => 'small',
529
+ 'sb_instagram_header_color' => '',
530
+ //Follow button
531
+ 'sb_instagram_show_follow_btn' => true,
532
+ 'sb_instagram_folow_btn_background' => '',
533
+ 'sb_instagram_follow_btn_text_color' => '',
534
+ 'sb_instagram_follow_btn_text' => __( 'Follow on Instagram', 'instagram-feed' ),
535
+ //Misc
536
+ 'sb_instagram_custom_css' => '',
537
+ 'sb_instagram_custom_js' => '',
538
+ 'sb_instagram_cron' => 'no',
539
+ 'sb_instagram_backup' => true,
540
+ 'sb_ajax_initial' => false,
541
+ 'enqueue_css_in_shortcode' => false,
542
+ 'sb_instagram_disable_mob_swipe' => false,
543
+ 'sbi_font_method' => 'svg',
544
+ 'sb_instagram_disable_awesome' => false
545
+ );
546
+ $sbi_settings = get_option( 'sb_instagram_settings', array() );
547
+
548
+ return array_merge( $defaults, $sbi_settings );
549
+ }
550
+
551
+ /**
552
+ * May include support for templates in theme folders in the future
553
+ */
554
+ function sbi_get_feed_template_part( $part, $settings = array() ) {
555
+ $file = '';
556
+ if ( $part === 'header' ) {
557
+ $file = trailingslashit( SBI_PLUGIN_DIR ) . 'templates/header.php';
558
+ } elseif ( $part === 'item' ) {
559
+ $file = trailingslashit( SBI_PLUGIN_DIR ) . 'templates/item.php';
560
+ } elseif ( $part === 'footer' ) {
561
+ $file = trailingslashit( SBI_PLUGIN_DIR ) . 'templates/footer.php';
562
+ } elseif ( $part === 'feed' ) {
563
+ $file = trailingslashit( SBI_PLUGIN_DIR ) . 'templates/feed.php';
564
+ }
565
+
566
+ return $file;
567
+ }
568
+
569
+ /**
570
+ * Triggered by a cron event to update feeds
571
+ */
572
+ function sbi_cron_updater() {
573
+ $sbi_settings = sbi_get_database_settings();
574
+
575
+ if ( $sbi_settings['sbi_caching_type'] === 'background' ) {
576
+ $cron_updater = new SB_Instagram_Cron_Updater();
577
+
578
+ $cron_updater->do_feed_updates();
579
+ }
580
+
581
+ }
582
+ add_action( 'sbi_feed_update', 'sbi_cron_updater' );
583
+
584
+ /**
585
+ * @param $maybe_dirty
586
+ *
587
+ * @return string
588
+ */
589
+ function sbi_maybe_clean( $maybe_dirty ) {
590
+ if ( substr_count ( $maybe_dirty , '.' ) < 3 ) {
591
+ return $maybe_dirty;
592
+ }
593
+
594
+ $parts = explode( '.', trim( $maybe_dirty ) );
595
+ $last_part = $parts[2] . $parts[3];
596
+ $cleaned = $parts[0] . '.' . base64_decode( $parts[1] ) . '.' . base64_decode( $last_part );
597
+
598
+ return $cleaned;
599
+ }
600
+
601
+ /**
602
+ * @param $whole
603
+ *
604
+ * @return string
605
+ */
606
+ function sbi_get_parts( $whole ) {
607
+ if ( substr_count ( $whole , '.' ) !== 2 ) {
608
+ return $whole;
609
+ }
610
+
611
+ $parts = explode( '.', trim( $whole ) );
612
+ $return = $parts[0] . '.' . base64_encode( $parts[1] ). '.' . base64_encode( $parts[2] );
613
+
614
+ return substr( $return, 0, 40 ) . '.' . substr( $return, 40, 100 );
615
+ }
616
+
617
+ /**
618
+ * @param $a
619
+ * @param $b
620
+ *
621
+ * @return false|int
622
+ */
623
+ function sbi_date_sort( $a, $b ) {
624
+ $time_stamp_a = SB_Instagram_Parse::get_timestamp( $a );
625
+ $time_stamp_b = SB_Instagram_Parse::get_timestamp( $b );
626
+
627
+ if ( isset( $time_stamp_a ) ) {
628
+ return $time_stamp_b - $time_stamp_a;
629
+ } else {
630
+ return rand ( -1, 1 );
631
+ }
632
+ }
633
+
634
+ /**
635
+ * @param $a
636
+ * @param $b
637
+ *
638
+ * @return false|int
639
+ */
640
+ function sbi_rand_sort( $a, $b ) {
641
+ return rand ( -1, 1 );
642
+ }
643
+
644
+ /**
645
+ * Converts a hex code to RGB so opacity can be
646
+ * applied more easily
647
+ *
648
+ * @param $hex
649
+ *
650
+ * @return string
651
+ */
652
+ function sbi_hextorgb( $hex ) {
653
+ // allows someone to use rgb in shortcode
654
+ if ( strpos( $hex, ',' ) !== false ) {
655
+ return $hex;
656
+ }
657
+
658
+ $hex = str_replace( '#', '', $hex );
659
+
660
+ if ( strlen( $hex ) === 3 ) {
661
+ $r = hexdec( substr( $hex,0,1 ).substr( $hex,0,1 ) );
662
+ $g = hexdec( substr( $hex,1,1 ).substr( $hex,1,1 ) );
663
+ $b = hexdec( substr( $hex,2,1 ).substr( $hex,2,1 ) );
664
+ } else {
665
+ $r = hexdec( substr( $hex,0,2 ) );
666
+ $g = hexdec( substr( $hex,2,2 ) );
667
+ $b = hexdec( substr( $hex,4,2 ) );
668
+ }
669
+ $rgb = array( $r, $g, $b );
670
+
671
+ return implode( ',', $rgb ); // returns the rgb values separated by commas
672
+ }
673
+
674
+ /**
675
+ * @return int
676
+ */
677
+ function sbi_get_utc_offset() {
678
+ return get_option( 'gmt_offset', 0 ) * HOUR_IN_SECONDS;
679
+ }
680
+
681
+ /**
682
+ * Used to clear caches when transients aren't working
683
+ * properly
684
+ */
685
+ function sb_instagram_cron_clear_cache() {
686
+ //Delete all transients
687
+ global $wpdb;
688
+ $table_name = $wpdb->prefix . "options";
689
+ $wpdb->query( "
690
+ DELETE
691
+ FROM $table_name
692
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
693
+ " );
694
+ $wpdb->query( "
695
+ DELETE
696
+ FROM $table_name
697
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
698
+ " );
699
+ $wpdb->query( "
700
+ DELETE
701
+ FROM $table_name
702
+ WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
703
+ " );
704
+ $wpdb->query( "
705
+ DELETE
706
+ FROM $table_name
707
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
708
+ " );
709
+ $wpdb->query( "
710
+ DELETE
711
+ FROM $table_name
712
+ WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
713
+ " );
714
+ $wpdb->query( "
715
+ DELETE
716
+ FROM $table_name
717
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
718
+ " );
719
+
720
+ sb_instagram_clear_page_caches();
721
+ }
722
+
723
+ /**
724
+ * When certain events occur, page caches need to
725
+ * clear or errors occur or changes will not be seen
726
+ */
727
+ function sb_instagram_clear_page_caches() {
728
+ if ( isset( $GLOBALS['wp_fastest_cache'] ) && method_exists( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ){
729
+ /* Clear WP fastest cache*/
730
+ $GLOBALS['wp_fastest_cache']->deleteCache();
731
+ }
732
+
733
+ if ( function_exists( 'wp_cache_clear_cache' ) ) {
734
+ wp_cache_clear_cache();
735
+ }
736
+
737
+ if ( class_exists('W3_Plugin_TotalCacheAdmin') ) {
738
+ $plugin_totalcacheadmin = & w3_instance('W3_Plugin_TotalCacheAdmin');
739
+
740
+ $plugin_totalcacheadmin->flush_all();
741
+ }
742
+
743
+ if ( function_exists( 'rocket_clean_domain' ) ) {
744
+ rocket_clean_domain();
745
+ }
746
+
747
+ if ( class_exists( 'autoptimizeCache' ) ) {
748
+ /* Clear autoptimize */
749
+ autoptimizeCache::clearall();
750
+ }
751
+ }
752
+
753
+ /**
754
+ * Makes the JavaScript file available and enqueues the stylesheet
755
+ * for the plugin
756
+ */
757
+ function sb_instagram_scripts_enqueue() {
758
+ //Register the script to make it available
759
+
760
+ //Options to pass to JS file
761
+ $sb_instagram_settings = get_option( 'sb_instagram_settings' );
762
+
763
+ $js_file = 'js/sb-instagram.min.js';
764
+ if ( isset( $_GET['sbi_debug'] ) ) {
765
+ $js_file = 'js/sb-instagram.js';
766
+ }
767
+
768
+ if ( isset( $sb_instagram_settings['enqueue_js_in_head'] ) && $sb_instagram_settings['enqueue_js_in_head'] ) {
769
+ wp_enqueue_script( 'sb_instagram_scripts', trailingslashit( SBI_PLUGIN_URL ) . $js_file, array('jquery'), SBIVER, false );
770
+ } else {
771
+ wp_register_script( 'sb_instagram_scripts', trailingslashit( SBI_PLUGIN_URL ) . $js_file, array('jquery'), SBIVER, true );
772
+ }
773
+
774
+ if ( isset( $sb_instagram_settings['enqueue_css_in_shortcode'] ) && $sb_instagram_settings['enqueue_css_in_shortcode'] ) {
775
+ wp_register_style( 'sb_instagram_styles', trailingslashit( SBI_PLUGIN_URL ) . 'css/sb-instagram.min.css', array(), SBIVER );
776
+ } else {
777
+ wp_enqueue_style( 'sb_instagram_styles', trailingslashit( SBI_PLUGIN_URL ) . 'css/sb-instagram.min.css', array(), SBIVER );
778
+ }
779
+
780
+ $font_method = isset( $sb_instagram_settings['sbi_font_method'] ) ? $sb_instagram_settings['sbi_font_method'] : 'svg';
781
+
782
+ if ( isset( $sb_instagram_settings['sb_instagram_disable_awesome'] ) ) {
783
+ $disable_font_awesome = isset( $sb_instagram_settings['sb_instagram_disable_awesome'] ) ? $sb_instagram_settings['sb_instagram_disable_awesome'] === 'on' : false;
784
+ } else {
785
+ $disable_font_awesome = isset( $sb_instagram_settings['sb_instagram_disable_font'] ) ? $sb_instagram_settings['sb_instagram_disable_font'] === 'on' : false;
786
+ }
787
+
788
+ if ( $font_method === 'fontfile' && ! $disable_font_awesome ) {
789
+ wp_enqueue_style( 'sb-font-awesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' );
790
+ }
791
+
792
+ $upload = wp_upload_dir();
793
+ $resized_url = trailingslashit( $upload['baseurl'] ) . trailingslashit( SBI_UPLOADS_NAME );
794
+ $data = array(
795
+ 'font_method' => $font_method,
796
+ 'resized_url' => $resized_url,
797
+ 'placeholder' => trailingslashit( SBI_PLUGIN_URL ) . 'img/placeholder.png'
798
+ );
799
+ //Pass option to JS file
800
+ wp_localize_script('sb_instagram_scripts', 'sb_instagram_js_options', $data );
801
+ }
802
+ add_action( 'wp_enqueue_scripts', 'sb_instagram_scripts_enqueue', 2 );
803
+
804
+ /**
805
+ * Adds the ajax url and custom JavaScript to the page
806
+ */
807
+ function sb_instagram_custom_js() {
808
+ $options = get_option('sb_instagram_settings');
809
+ isset($options[ 'sb_instagram_custom_js' ]) ? $sb_instagram_custom_js = trim($options['sb_instagram_custom_js']) : $sb_instagram_custom_js = '';
810
+
811
+ echo '<!-- Instagram Feed JS -->';
812
+ echo "\r\n";
813
+ echo '<script type="text/javascript">';
814
+ echo "\r\n";
815
+ echo 'var sbiajaxurl = "' . admin_url('admin-ajax.php') . '";';
816
+
817
+ if ( !empty( $sb_instagram_custom_js ) ) {
818
+ echo "\r\n";
819
+ echo "jQuery( document ).ready(function($) {";
820
+ echo "\r\n";
821
+ echo "window.sbi_custom_js = function(){";
822
+ echo "\r\n";
823
+ echo stripslashes($sb_instagram_custom_js);
824
+ echo "\r\n";
825
+ echo "}";
826
+ echo "\r\n";
827
+ echo "});";
828
+ }
829
+
830
+ echo "\r\n";
831
+ echo '</script>';
832
+ echo "\r\n";
833
+ }
834
+ add_action( 'wp_footer', 'sb_instagram_custom_js' );
835
+
836
+ //Custom CSS
837
+ add_action( 'wp_head', 'sb_instagram_custom_css' );
838
+ function sb_instagram_custom_css() {
839
+ $options = get_option('sb_instagram_settings');
840
+
841
+ isset($options[ 'sb_instagram_custom_css' ]) ? $sb_instagram_custom_css = trim($options['sb_instagram_custom_css']) : $sb_instagram_custom_css = '';
842
+
843
+ //Show CSS if an admin (so can see Hide Photos link), if including Custom CSS or if hiding some photos
844
+ ( current_user_can( 'edit_posts' ) || !empty($sb_instagram_custom_css) || !empty($sb_instagram_hide_photos) ) ? $sbi_show_css = true : $sbi_show_css = false;
845
+
846
+ if( $sbi_show_css ) echo '<!-- Instagram Feed CSS -->';
847
+ if( $sbi_show_css ) echo "\r\n";
848
+ if( $sbi_show_css ) echo '<style type="text/css">';
849
+
850
+ if( !empty($sb_instagram_custom_css) ){
851
+ echo "\r\n";
852
+ echo stripslashes($sb_instagram_custom_css);
853
+ }
854
+
855
+ if( current_user_can( 'edit_posts' ) ){
856
+ echo "\r\n";
857
+ echo "#sbi_mod_link, #sbi_mod_error{ display: block !important; width: 100%; float: left; box-sizing: border-box; }";
858
+ }
859
+
860
+ if( $sbi_show_css ) echo "\r\n";
861
+ if( $sbi_show_css ) echo '</style>';
862
+ if( $sbi_show_css ) echo "\r\n";
863
+ }
864
+
865
+ /**
866
+ * Used to change the number of posts in the api request. Useful for filtered posts
867
+ * or special caching situations.
868
+ *
869
+ * @param int $num
870
+ * @param array $settings
871
+ *
872
+ * @return int
873
+ */
874
+ function sbi_raise_num_in_request( $num, $settings ) {
875
+ if ( $settings['sortby'] === 'random' ) {
876
+ if ( $num > 5 ) {
877
+ return min( $num * 4, 100 );
878
+ } else {
879
+ return 20;
880
+ }
881
+ }
882
+ return $num;
883
+ }
884
+ add_filter( 'sbi_num_in_request', 'sbi_raise_num_in_request', 5, 2 );
instagram-feed.php CHANGED
@@ -1,9 +1,9 @@
1
- <?php
2
  /*
3
- Plugin Name: Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
- Description: Display beautifully clean, customizable, and responsive Instagram feeds
6
- Version: 1.12.2
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
@@ -22,982 +22,550 @@ You should have received a copy of the GNU General Public License
22
  along with this program; if not, write to the Free Software
23
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
  */
 
 
 
 
 
 
 
25
 
26
- define( 'SBIVER', '1.12.2' );
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
29
-
30
- //Include admin
31
- if ( is_admin() ) include dirname( __FILE__ ) .'/instagram-feed-admin.php';
32
-
33
- // Add shortcodes
34
- add_shortcode('instagram-feed', 'display_instagram');
35
- function display_instagram($atts, $content = null) {
36
-
37
- /******************* SHORTCODE OPTIONS ********************/
38
-
39
- $options = get_option('sb_instagram_settings');
40
-
41
- //Pass in shortcode attrbutes
42
- $atts = shortcode_atts(
43
- array(
44
- 'id' => isset($options[ 'sb_instagram_user_id' ]) ? $options[ 'sb_instagram_user_id' ] : '',
45
- 'width' => isset($options[ 'sb_instagram_width' ]) ? $options[ 'sb_instagram_width' ] : '',
46
- 'widthunit' => isset($options[ 'sb_instagram_width_unit' ]) ? $options[ 'sb_instagram_width_unit' ] : '',
47
- 'widthresp' => isset($options[ 'sb_instagram_feed_width_resp' ]) ? $options[ 'sb_instagram_feed_width_resp' ] : '',
48
- 'height' => isset($options[ 'sb_instagram_height' ]) ? $options[ 'sb_instagram_height' ] : '',
49
- 'heightunit' => isset($options[ 'sb_instagram_height_unit' ]) ? $options[ 'sb_instagram_height_unit' ] : '',
50
- 'sortby' => isset($options[ 'sb_instagram_sort' ]) ? $options[ 'sb_instagram_sort' ] : '',
51
- 'num' => isset($options[ 'sb_instagram_num' ]) ? $options[ 'sb_instagram_num' ] : '',
52
- 'cols' => isset($options[ 'sb_instagram_cols' ]) ? $options[ 'sb_instagram_cols' ] : '',
53
- 'disablemobile' => isset($options[ 'sb_instagram_disable_mobile' ]) ? $options[ 'sb_instagram_disable_mobile' ] : '',
54
- 'imagepadding' => isset($options[ 'sb_instagram_image_padding' ]) ? $options[ 'sb_instagram_image_padding' ] : '',
55
- 'imagepaddingunit' => isset($options[ 'sb_instagram_image_padding_unit' ]) ? $options[ 'sb_instagram_image_padding_unit' ] : '',
56
- 'background' => isset($options[ 'sb_instagram_background' ]) ? $options[ 'sb_instagram_background' ] : '',
57
- 'showbutton' => isset($options[ 'sb_instagram_show_btn' ]) ? $options[ 'sb_instagram_show_btn' ] : '',
58
- 'buttoncolor' => isset($options[ 'sb_instagram_btn_background' ]) ? $options[ 'sb_instagram_btn_background' ] : '',
59
- 'buttontextcolor' => isset($options[ 'sb_instagram_btn_text_color' ]) ? $options[ 'sb_instagram_btn_text_color' ] : '',
60
- 'buttontext' => isset($options[ 'sb_instagram_btn_text' ]) ? $options[ 'sb_instagram_btn_text' ] : '',
61
- 'imageres' => isset($options[ 'sb_instagram_image_res' ]) ? $options[ 'sb_instagram_image_res' ] : '',
62
- 'showfollow' => isset($options[ 'sb_instagram_show_follow_btn' ]) ? $options[ 'sb_instagram_show_follow_btn' ] : '',
63
- 'followcolor' => isset($options[ 'sb_instagram_folow_btn_background' ]) ? $options[ 'sb_instagram_folow_btn_background' ] : '',
64
- 'followtextcolor' => isset($options[ 'sb_instagram_follow_btn_text_color' ]) ? $options[ 'sb_instagram_follow_btn_text_color' ] : '',
65
- 'followtext' => isset($options[ 'sb_instagram_follow_btn_text' ]) ? $options[ 'sb_instagram_follow_btn_text' ] : '',
66
- 'showheader' => isset($options[ 'sb_instagram_show_header' ]) ? $options[ 'sb_instagram_show_header' ] : '',
67
- 'headersize' => isset($options[ 'sb_instagram_header_size' ]) ? $options[ 'sb_instagram_header_size' ] : '',
68
- 'showbio' => isset($options[ 'sb_instagram_show_bio' ]) ? $options[ 'sb_instagram_show_bio' ] : '',
69
- 'headercolor' => isset($options[ 'sb_instagram_header_color' ]) ? $options[ 'sb_instagram_header_color' ] : '',
70
- 'class' => '',
71
- 'ajaxtheme' => isset($options[ 'sb_instagram_ajax_theme' ]) ? $options[ 'sb_instagram_ajax_theme' ] : '',
72
- 'cachetime' => isset($options[ 'sb_instagram_cache_time' ]) ? $options[ 'sb_instagram_cache_time' ] : '',
73
- 'media' => isset($options[ 'sb_instagram_media_type' ]) ? $options[ 'sb_instagram_media_type' ] : '',
74
- 'accesstoken' => '',
75
- 'user' => isset($options[ 'sb_instagram_user' ]) ? $options[ 'sb_instagram_user' ] : false,
76
- ), $atts);
77
-
78
-
79
- /******************* VARS ********************/
80
-
81
- $sb_instagram_user_id = is_array( $atts['id'] ) ? implode( ',', $atts['id'] ) : trim($atts['id'], " ,");
82
- $sb_instagram_users = !empty($atts['user']) ? explode( ',', trim( $atts['user'] ) ) : false;
83
-
84
- // Access Token
85
- $at_front_string = '';
86
- $at_middle_string = '';
87
- $at_back_string = '';
88
-
89
- //$db_access_token = isset( $options['sb_instagram_at'] ) ? trim( $options['sb_instagram_at'] ) : '';
90
- $existing_shortcode_tokens = ! empty( $atts['accesstoken'] ) ? explode(',', str_replace(' ', '', $atts['accesstoken'] ) ) : '';
91
- $existing_shortcode_tokens = apply_filters( 'sbi_access_tokens', $existing_shortcode_tokens );
92
-
93
- $usable_tokens = array();
94
- $all_valid_tokens = array();
95
-
96
-
97
- if ( ! empty ( $existing_shortcode_tokens ) ) {
98
- foreach ( $existing_shortcode_tokens as $existing_shortcode_token ) {
99
- if ( ! empty( $existing_shortcode_token ) ) {
100
- $usable_tokens[] = $existing_shortcode_token;
101
- $all_valid_tokens[] = $existing_shortcode_tokens;
102
- }
103
-
104
  }
105
- }
106
- if ( $sb_instagram_users !== false && ! empty ( $options[ 'connected_accounts' ] ) ) {
107
- foreach ( $options[ 'connected_accounts' ] as $connected_account ) {
108
- if ( in_array( $connected_account['username'], $sb_instagram_users ) ) {
109
- $usable_tokens[] = sbi_get_parts( $connected_account['access_token'] );
110
- }
111
- if ( ! in_array( sbi_get_parts( $connected_account['access_token'] ), $all_valid_tokens ) && ! in_array( sbi_maybe_clean( $connected_account['access_token'] ), $all_valid_tokens ) ) {
112
- $all_valid_tokens[] = sbi_get_parts( $connected_account['access_token'] );
113
- }
114
  }
115
-
116
- }
117
- if ( empty( $usable_tokens ) && ! empty( $options[ 'connected_accounts' ] ) ) {
118
- $feed_id_array = is_array( $sb_instagram_user_id ) ? $sb_instagram_user_id : explode( ',', $sb_instagram_user_id );
119
- if ( ! empty( $feed_id_array ) && ! empty( $feed_id_array[0] ) ) {
120
- foreach ( $options[ 'connected_accounts' ] as $connected_account ) {
121
- if ( isset( $connected_account['access_token'] ) && in_array( $connected_account['user_id'], $feed_id_array, true ) ) {
122
- $usable_tokens[] = $connected_account['access_token'];
123
- } elseif ( isset( $connected_account['access_token'] ) ) {
124
- if ( ! in_array( sbi_get_parts( $connected_account['access_token'] ), $all_valid_tokens ) && ! in_array( sbi_maybe_clean( $connected_account['access_token'] ), $all_valid_tokens ) ) {
125
- $all_valid_tokens[] = sbi_get_parts( $connected_account['access_token'] );
126
- }
127
- }
128
- }
129
- } else {
130
- foreach ( $options[ 'connected_accounts' ] as $connected_account ) {
131
- if ( empty( $usable_tokens ) ) {
132
- $usable_tokens = array( $connected_account['access_token'] );
133
- $user_for_token = explode( '.', $connected_account['access_token'] );
134
- $sb_instagram_user_id = $user_for_token[0];
135
- }
136
-
137
- if ( ! in_array( sbi_get_parts( $connected_account['access_token'] ), $all_valid_tokens ) && ! in_array( sbi_maybe_clean( $connected_account['access_token'] ), $all_valid_tokens ) ) {
138
- $all_valid_tokens[] = sbi_get_parts( $connected_account['access_token'] );
139
- }
140
- }
141
  }
142
-
143
- } elseif ( empty ( $all_valid_tokens ) ) {
144
-
145
- $db_access_tokens = isset( $options['sb_instagram_at'] ) ? explode( ',', trim( $options['sb_instagram_at'] ) ) : array();
146
- foreach ( $db_access_tokens as $db_access_token ) {
147
- if ( ! empty( $db_access_token ) ) {
148
- $usable_tokens[] = sbi_get_parts( $db_access_token );
149
- $all_valid_tokens[] = sbi_get_parts( $db_access_token );
150
- }
151
  }
152
- }
153
-
154
- $the_token_array = ! empty( $usable_tokens ) ? $usable_tokens : $all_valid_tokens;
155
- if ( empty( $the_token_array ) && ! empty( $all_valid_tokens ) ) {
156
- $the_token_array = $all_valid_tokens;
157
- }
158
-
159
- if ( ! empty( $the_token_array ) ) {
160
- $at_front_string = '&quot;feedID&quot;: &quot;';
161
- $at_middle_string = '&quot;mid&quot;: &quot;';
162
- $at_back_string = '&quot;callback&quot;: &quot;';
163
- $sb_instagram_user_id = '';
164
- foreach ( $usable_tokens as $token ) {
165
- $parts = explode('.', $token );
166
- $sb_instagram_user_id .= $parts[0].',';
167
- $at_front_string .= $parts[0].',';
168
- $at_middle_string .= $parts[1].',';
169
- if ( isset( $parts[3] ) ) {
170
- $at_back_string .= $parts[2].'.'.$parts[3].',';
171
- } else {
172
- $at_back_string .= $parts[2].',';
173
- }
174
  }
175
- $sb_instagram_user_id = substr( $sb_instagram_user_id, 0, -1 );
176
- $at_front_string = substr( $at_front_string, 0, -1 ) . '&quot;,';
177
- $at_middle_string = substr( $at_middle_string, 0, -1 ) . '&quot;,';
178
- $at_back_string = substr( $at_back_string, 0, -1 ) . '&quot;,';
179
- $access_token = $the_token_array[0];
180
- }
181
-
182
- //Container styles
183
- $sb_instagram_width = $atts['width'];
184
- $sb_instagram_width_unit = $atts['widthunit'];
185
- $sb_instagram_height = $atts['height'];
186
- $sb_instagram_height_unit = $atts['heightunit'];
187
- $sb_instagram_image_padding = $atts['imagepadding'];
188
- $sb_instagram_image_padding_unit = $atts['imagepaddingunit'];
189
- $sb_instagram_background = $atts['background'];
190
-
191
- //Set to be 100% width on mobile?
192
- $sb_instagram_width_resp = $atts[ 'widthresp' ];
193
- ( $sb_instagram_width_resp == 'on' || $sb_instagram_width_resp == 'true' || $sb_instagram_width_resp == true ) ? $sb_instagram_width_resp = true : $sb_instagram_width_resp = false;
194
- if( $atts[ 'widthresp' ] == 'false' ) $sb_instagram_width_resp = false;
195
-
196
- //Layout options
197
- $sb_instagram_cols = $atts['cols'];
198
-
199
- $sb_instagram_styles = 'style="';
200
- if($sb_instagram_cols == 1) $sb_instagram_styles .= 'max-width: 640px; ';
201
- if ( !empty($sb_instagram_width) ) $sb_instagram_styles .= 'width:' . $sb_instagram_width . $sb_instagram_width_unit .'; ';
202
- if ( !empty($sb_instagram_height) && $sb_instagram_height != '0' ) $sb_instagram_styles .= 'height:' . $sb_instagram_height . $sb_instagram_height_unit .'; ';
203
- if ( !empty($sb_instagram_background) ) $sb_instagram_styles .= 'background-color: ' . $sb_instagram_background . '; ';
204
- if ( !empty($sb_instagram_image_padding) ) $sb_instagram_styles .= 'padding-bottom: ' . (2*intval($sb_instagram_image_padding)).$sb_instagram_image_padding_unit . '; ';
205
- $sb_instagram_styles .= '"';
206
-
207
- //Header
208
- $sb_instagram_show_header = $atts['showheader'];
209
- ( $sb_instagram_show_header == 'on' || $sb_instagram_show_header == 'true' || $sb_instagram_show_header == true ) ? $sb_instagram_show_header = true : $sb_instagram_show_header = false;
210
- if( $atts[ 'showheader' ] === 'false' ) $sb_instagram_show_header = false;
211
- $sb_instagram_header_size_class = in_array( strtolower( $atts['headersize'] ), array( 'medium', 'large' ) ) ? ' sbi_'.strtolower( $atts['headersize'] ) : '';
212
- $sb_instagram_header_color = str_replace('#', '', $atts['headercolor']);
213
-
214
- //As this is a new option in the update then set it to be true if it doesn't exist yet
215
- if ( !array_key_exists( 'sb_instagram_show_bio', $options ) ) $sb_instagram_show_bio = 'true';
216
-
217
- $sb_instagram_show_bio = $atts['showbio'];
218
- ( $sb_instagram_show_bio == 'on' || $sb_instagram_show_bio == 'true' || $sb_instagram_show_bio ) ? $sb_instagram_show_bio = 'true' : $sb_instagram_show_bio = 'false';
219
- if( $atts[ 'showbio' ] === 'false' ) $sb_instagram_show_bio = false;
220
-
221
- // button text
222
- $sb_instagram_follow_btn_text = __( $atts['followtext'], 'instagram-feed' );
223
- $sb_instagram_load_btn_text = __( $atts['buttontext'], 'instagram-feed' );
224
-
225
- //Load more button
226
- $sb_instagram_show_btn = $atts['showbutton'];
227
- ( $sb_instagram_show_btn == 'on' || $sb_instagram_show_btn == 'true' || $sb_instagram_show_btn == true ) ? $sb_instagram_show_btn = true : $sb_instagram_show_btn = false;
228
- if( $atts[ 'showbutton' ] === 'false' ) $sb_instagram_show_btn = false;
229
- $sb_instagram_btn_background = str_replace('#', '', $atts['buttoncolor']);
230
- $sb_instagram_btn_text_color = str_replace('#', '', $atts['buttontextcolor']);
231
- //Load more button styles
232
- $sb_instagram_button_styles = 'style="display: none; ';
233
- if ( !empty($sb_instagram_btn_background) ) $sb_instagram_button_styles .= 'background: #'.$sb_instagram_btn_background.'; ';
234
- if ( !empty($sb_instagram_btn_text_color) ) $sb_instagram_button_styles .= 'color: #'.$sb_instagram_btn_text_color.';';
235
- $sb_instagram_button_styles .= '"';
236
-
237
- //Follow button vars
238
- $sb_instagram_show_follow_btn = $atts['showfollow'];
239
- ( $sb_instagram_show_follow_btn == 'on' || $sb_instagram_show_follow_btn == 'true' || $sb_instagram_show_follow_btn == true ) ? $sb_instagram_show_follow_btn = true : $sb_instagram_show_follow_btn = false;
240
- if( $atts[ 'showfollow' ] === 'false' ) $sb_instagram_show_follow_btn = false;
241
- $sb_instagram_follow_btn_background = str_replace('#', '', $atts['followcolor']);
242
- $sb_instagram_follow_btn_text_color = str_replace('#', '', $atts['followtextcolor']);
243
- //Follow button styles
244
- $sb_instagram_follow_btn_styles = 'style="';
245
- if ( !empty($sb_instagram_follow_btn_background) ) $sb_instagram_follow_btn_styles .= 'background: #'.$sb_instagram_follow_btn_background.'; ';
246
- if ( !empty($sb_instagram_follow_btn_text_color) ) $sb_instagram_follow_btn_styles .= 'color: #'.$sb_instagram_follow_btn_text_color.';';
247
- $sb_instagram_follow_btn_styles .= '"';
248
- //Follow button HTML
249
- $sb_instagram_follow_btn_classes = '';
250
- if( strpos($sb_instagram_follow_btn_styles, 'background') !== false ) $sb_instagram_follow_btn_classes = ' sbi_custom';
251
- $sb_instagram_follow_btn_html = '<span class="sbi_follow_btn'.$sb_instagram_follow_btn_classes.'"><a href="https://www.instagram.com/" '.$sb_instagram_follow_btn_styles.' target="_blank" rel="noopener"><i class="fa fab fa-instagram"></i>'.esc_html( stripslashes( $sb_instagram_follow_btn_text ) ).'</a></span>';
252
-
253
- //Mobile
254
- $sb_instagram_disable_mobile = $atts['disablemobile'];
255
- ( $sb_instagram_disable_mobile == 'on' || $sb_instagram_disable_mobile == 'true' || $sb_instagram_disable_mobile == true ) ? $sb_instagram_disable_mobile = ' sbi_disable_mobile' : $sb_instagram_disable_mobile = ' sbi_mob_col_auto';
256
- if( $atts[ 'disablemobile' ] === 'false' ) $sb_instagram_disable_mobile = ' sbi_mob_col_auto';
257
-
258
- //Caching
259
- $sb_instagram_cache_time = trim($atts['cachetime']);
260
- if ( !array_key_exists( 'sb_instagram_cache_time', $options ) || $sb_instagram_cache_time == '' ) $sb_instagram_cache_time = '1';
261
- ($sb_instagram_cache_time == 0 || $sb_instagram_cache_time == '0') ? $sb_instagram_disable_cache = 'true' : $sb_instagram_disable_cache = 'false';
262
- //Figure out how long the first part of the caching string should be
263
- $sbi_cache_string_include_length = 0;
264
- $sbi_cache_string_exclude_length = 0;
265
- $sbi_cache_string_length = 40 - min($sbi_cache_string_include_length + $sbi_cache_string_exclude_length, 20);
266
-
267
- //Create the first part of the caching string
268
- $sbi_transient_name = 'sbi_';
269
- $sb_instagram_white_list = '';
270
- $sb_instagram_show_users = '';
271
- $sbi_transient_name .= substr( $sb_instagram_white_list, 0, 3 ) . substr( $sb_instagram_show_users, 0, 3 );
272
-
273
- $feed_is_filtered = ($sb_instagram_white_list !== '' || $sb_instagram_show_users !== '');
274
- //Media type
275
- $sb_instagram_media_type = $atts['media'];
276
- if( !isset($sb_instagram_media_type) || empty($sb_instagram_media_type) ) $sb_instagram_media_type = 'all';
277
-
278
- if ( $sb_instagram_media_type !== 'all' ) {
279
- $sbi_transient_name .= substr( $sb_instagram_media_type, 0, 1 );
280
- }
281
- if( true ) $sbi_transient_name .= substr( str_replace(str_split(', '), '', $sb_instagram_user_id), 0, $sbi_cache_string_length); //Remove commas and spaces and limit chars
282
-
283
- //Find the length of the string so far, and then however many chars are left we can use this for filters
284
- $sbi_cache_string_length = strlen($sbi_transient_name);
285
- $sbi_cache_string_length = 44 - intval($sbi_cache_string_length);
286
-
287
- //Add both parts of the caching string together and make sure it doesn't exceed 45
288
- $sbi_transient_name = substr($sbi_transient_name, 0, 45);
289
- // delete_transient($sbi_transient_name);
290
-
291
- //Check whether the cache transient exists in the database and is available for more than one more minute
292
- $feed_expires = get_option( '_transient_timeout_'.$sbi_transient_name );
293
- $sbi_cache_exists = $feed_expires !== false && ($feed_expires - time()) > 60 ? 'true' : 'false';
294
-
295
- if ( $sbi_cache_exists === 'false' && isset( $access_token ) ) {
296
- $sbi_cache_exists = 'true';
297
- sbi_pre_cache_photos( $sbi_transient_name, trim($atts['num']), $the_token_array );
298
- }
299
-
300
- $sbiHeaderCache = 'false';
301
- //If it's a user then add the header cache check to the feed
302
- $sb_instagram_user_id_arr = explode(',', $sb_instagram_user_id);
303
- $sbi_header_transient_name = 'sbi_header_' . trim($sb_instagram_user_id_arr[0]);
304
- $sbi_header_transient_name = substr($sbi_header_transient_name, 0, 45);
305
-
306
- //Check for the header cache
307
- $header_expires = get_option( '_transient_timeout_'.$sbi_header_transient_name );
308
- $sbi_header_cache_exists = $header_expires !== false && ($header_expires - time()) > 60 ? 'true' : 'false';
309
- $sbiHeaderCache = $sbi_header_cache_exists;
310
-
311
- if ( $sbi_header_cache_exists === 'false' && isset( $access_token ) ) {
312
- sbi_pre_cache_photos( $sbi_header_transient_name, 1, array( $access_token ) );
313
- $sbiHeaderCache = 'true';
314
- }
315
-
316
- if ( isset( $options['check_api'] ) && ( $options['check_api'] === 'on' || $options['check_api']) && ( !isset( $options['sb_instagram_cache_time'] ) || ( isset( $options['sb_instagram_cache_time'] ) && (int)$options['sb_instagram_cache_time'] > 0 ) ) ) {
317
- if ( ! get_transient( '&'.$sbi_transient_name, false ) ) {
318
- $sbi_cache_exists = 'true';
319
- $sbiHeaderCache = 'true';
320
  }
321
- }
322
-
323
- $use_backup_json = '';
324
- $use_header_backup = false;
325
- $always_use_backup = isset( $atts['permanent'] ) ? ($atts['permanent'] === 'true') : false;
326
- $backups_enabled = isset( $options['sb_instagram_backup'] ) ? $options['sb_instagram_backup'] !== '' : true;
327
- if ( !$always_use_backup ) {
328
- $always_use_backup = false;
329
- }
330
- $still_using_backup = false;
331
- if ( $sbiHeaderCache == 'false' && true ) {
332
- $still_using_backup = get_transient( '&'.$sbi_header_transient_name, false );
333
- }
334
-
335
- if ( ($sbiHeaderCache == 'false' && $still_using_backup) || ($always_use_backup && isset( $sbi_header_transient_name )) ) {
336
- $use_header_backup = sbi_should_use_backup_cache( $access_token, $sbi_header_transient_name, $feed_is_filtered, $always_use_backup, $sb_instagram_white_list, $backups_enabled);
337
- if ( $use_header_backup ) {
338
- $sbiHeaderCache = 'true';
339
- $use_backup_json = ', &quot;useBackup&quot;: &quot;header&quot;';
340
  }
341
- }
342
-
343
- $still_using_backup = false;
344
- if ( $sbi_cache_exists == 'false' ) {
345
- $still_using_backup = get_transient( '&'.$sbi_transient_name, false );
346
- }
347
- if ( ($sbi_cache_exists == 'false' && $still_using_backup) || $always_use_backup ) {
348
- $use_feed_backup = sbi_should_use_backup_cache( $access_token, $sbi_transient_name, $feed_is_filtered, $always_use_backup, $sb_instagram_white_list, $backups_enabled );
349
-
350
- if ( $use_feed_backup ) {
351
- $sbi_cache_exists = 'true';
352
- if ( $use_header_backup ) {
353
- $use_backup_json = ', &quot;useBackup&quot;: &quot;header,feed&quot;';
354
- } else {
355
- $use_backup_json = ', &quot;useBackup&quot;: &quot;feed&quot;';
356
- }
357
  }
358
- }
359
-
360
- /* END CACHING */
361
- //Class
362
- !empty( $atts['class'] ) ? $sbi_class = ' ' . trim($atts['class']) : $sbi_class = '';
363
-
364
- //Ajax theme
365
- $sb_instagram_ajax_theme = $atts['ajaxtheme'];
366
- ( $sb_instagram_ajax_theme == 'on' || $sb_instagram_ajax_theme == 'true' || $sb_instagram_ajax_theme == true ) ? $sb_instagram_ajax_theme = true : $sb_instagram_ajax_theme = false;
367
- if( $atts[ 'disablemobile' ] === 'false' ) $sb_instagram_ajax_theme = false;
368
-
369
- /******************* CONTENT ********************/
370
-
371
- $sb_instagram_content = '<div id="sb_instagram" class="sbi' . $sbi_class . $sb_instagram_disable_mobile;
372
- if ( !empty($sb_instagram_height) ) $sb_instagram_content .= ' sbi_fixed_height ';
373
- $sb_instagram_content .= ' sbi_col_' . trim($sb_instagram_cols);
374
- if ( $sb_instagram_width_resp ) $sb_instagram_content .= ' sbi_width_resp';
375
- $sb_instagram_content .= '" '.$sb_instagram_styles .' data-id="' . $sb_instagram_user_id . '" data-num="' . trim($atts['num']) . '" data-res="' . trim($atts['imageres']) . '" data-cols="' . trim($sb_instagram_cols) . '" data-options=\'{&quot;sortby&quot;: &quot;'.$atts['sortby'].'&quot;, &quot;showbio&quot;: &quot;'.$sb_instagram_show_bio.'&quot;,'.$at_front_string.' &quot;headercolor&quot;: &quot;'.$sb_instagram_header_color.'&quot;, &quot;imagepadding&quot;: &quot;'.$sb_instagram_image_padding.'&quot;,'.$at_middle_string.' &quot;disablecache&quot;: &quot;'.$sb_instagram_disable_cache.'&quot;, &quot;sbiCacheExists&quot;: &quot;'.$sbi_cache_exists.'&quot;,'.$at_back_string.' &quot;sbiHeaderCache&quot;: &quot;'.$sbiHeaderCache.'&quot;'.$use_backup_json.'}\'>';
376
-
377
- //Header
378
- if( $sb_instagram_show_header ) $sb_instagram_content .= '<div class="sb_instagram_header'.$sb_instagram_header_size_class.'" style="padding: '.(2*intval($sb_instagram_image_padding)) . $sb_instagram_image_padding_unit .'; padding-bottom: 0;"></div>';
379
-
380
- //Images container
381
- $padding_style = (int)$sb_instagram_image_padding > 0 ? ' style="padding: '.$sb_instagram_image_padding . $sb_instagram_image_padding_unit . ';"' : '';
382
- $sb_instagram_content .= '<div id="sbi_images"' . $padding_style .'>';
383
-
384
- //Error messages
385
- $sb_instagram_error = false;
386
-
387
- if ( empty( $access_token ) ){
388
- $sb_instagram_content .= '<div class="sb_instagram_error"><p>' . __( 'Please enter an Access Token on the Instagram Feed plugin Settings page.', 'instagram-feed' ) . '</p></div>';
389
- $sb_instagram_error = true;
390
- }
391
-
392
- //Loader
393
- if( !$sb_instagram_error ) $sb_instagram_content .= '<div class="sbi_loader"></div>';
394
-
395
- //Load section
396
- $sb_instagram_content .= '</div><div id="sbi_load" class="sbi_hidden"';
397
-
398
- if(($sb_instagram_image_padding == 0 || !isset($sb_instagram_image_padding)) && ($sb_instagram_show_btn || $sb_instagram_show_follow_btn)) $sb_instagram_content .= ' style="padding-top: 5px"';
399
- $sb_instagram_content .= '>';
400
-
401
- //Load More button
402
- if( $sb_instagram_show_btn && !$sb_instagram_error ) $sb_instagram_content .= '<a class="sbi_load_btn" href="javascript:void(0);" '.$sb_instagram_button_styles.'><span class="sbi_btn_text">' . esc_html( stripslashes( $sb_instagram_load_btn_text ) ).'</span><span class="sbi_loader sbi_hidden"></span></a>';
403
-
404
- //Follow button
405
- if( $sb_instagram_show_follow_btn && !$sb_instagram_error ) $sb_instagram_content .= $sb_instagram_follow_btn_html;
406
-
407
- $sb_instagram_content .= '</div>'; //End #sbi_load
408
-
409
- $sb_instagram_content .= '</div>'; //End #sb_instagram
410
-
411
- //If using an ajax theme then add the JS to the bottom of the feed
412
- //If using an ajax theme then add the JS to the bottom of the feed
413
- if($sb_instagram_ajax_theme){
414
- $font_method = isset( $options['sbi_font_method'] ) ? $options['sbi_font_method'] : 'svg';
415
- $access_token = isset( $options['sb_instagram_at'] ) ? $options['sb_instagram_at'] : '';
416
-
417
- $sb_instagram_content .= '<script type="text/javascript">var sb_instagram_js_options = {"sb_instagram_at":"'.sbi_get_parts( $access_token ).'", "font_method":"'.$font_method.'"};</script>';
418
- $sb_instagram_content .= "<script type='text/javascript' src='".plugins_url( '/js/sb-instagram.min.js?ver='.SBIVER , __FILE__ )."'></script>";
419
- }
420
-
421
- //Return our feed HTML to display
422
- return $sb_instagram_content;
423
-
424
- }
425
-
426
 
427
- #############################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
 
429
- //Allows shortcodes in theme
430
- add_filter('widget_text', 'do_shortcode');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
 
432
- function sbi_should_use_backup_cache( $token, $cache_name, $is_filtered, $always_use_backup = false, $white_list_id = '', $backups_enabled = true ) {
433
- if ( ! $backups_enabled ) {
434
- return false;
435
  }
436
 
437
- $expired_tokens = get_option( 'sb_expired_tokens', array() );
438
- $still_using_backup = get_transient( '&'.$cache_name, false );
439
- $backup_cache_exists = get_option( '!' . $cache_name );
440
- $white_list_updated = get_transient( 'sb_wlupdated_'.$white_list_id );
441
 
442
- if ( $always_use_backup ) {
443
- if ( !$backup_cache_exists || $white_list_updated ) {
444
- return false;
 
 
 
 
 
 
 
 
 
445
  }
446
- return true;
447
- } elseif ( $white_list_updated == 'true' ) {
448
- return false;
449
- }
450
 
451
- if ( in_array( sbi_maybe_clean( $token ), $expired_tokens, true ) && $backup_cache_exists ) {
452
-
453
- if ( !strpos( $cache_name, '_header' ) ) {
454
- echo '<div id="sbi_mod_error">';
455
- echo '<p><b>' . __( 'Error: Access Token is not valid or has expired.', 'instagram-feed' ) . ' ' . __( 'Feed will not update.', 'instagram-feed' ) . '</b><br /><span>' . __(' This error message is only visible to WordPress admins</span>', 'instagram-feed' );
456
- echo '<p>' . __( 'There\'s an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin\'s Settings page.<br />If you continue to have an issue with your Access Token then please see <a href="https://smashballoon.com/my-instagram-access-token-keep-expiring/" target="_blank" rel="noopener">this FAQ</a> for more information.', 'instagram-feed' );
457
- echo '</div>';
458
  }
459
 
460
- return true;
461
- } elseif ( $still_using_backup && $backup_cache_exists ) {
462
- return true;
463
- }
464
-
465
- return false;
466
- }
467
-
468
- function sbi_pre_cache_photos( $transient, $num_images, $tokens ) {
469
- $sb_instagram_settings = get_option('sb_instagram_settings');
470
-
471
- //If the caching time doesn't exist in the database then set it to be 1 hour
472
- ( !array_key_exists( 'sb_instagram_cache_time', $sb_instagram_settings ) ) ? $sb_instagram_cache_time = 1 : $sb_instagram_cache_time = $sb_instagram_settings['sb_instagram_cache_time'];
473
- ( !array_key_exists( 'sb_instagram_cache_time_unit', $sb_instagram_settings ) ) ? $sb_instagram_cache_time_unit = 'minutes' : $sb_instagram_cache_time_unit = $sb_instagram_settings['sb_instagram_cache_time_unit'];
474
-
475
- //Calculate the cache time in seconds
476
- if($sb_instagram_cache_time_unit == 'minutes') $sb_instagram_cache_time_unit = 60;
477
- if($sb_instagram_cache_time_unit == 'hours') $sb_instagram_cache_time_unit = 60*60;
478
- if($sb_instagram_cache_time_unit == 'days') $sb_instagram_cache_time_unit = 60*60*24;
479
- $cache_seconds = intval($sb_instagram_cache_time) * intval($sb_instagram_cache_time_unit);
480
-
481
- $transient_name = $transient;
482
- if ( is_array( $transient_name ) ) {
483
- $transient_name = isset( $transient_name['feed'] ) ? sanitize_text_field( $transient_name['feed'] ) : 'sbi_other';
484
- }
485
-
486
- $cache_type = strpos( $transient_name, 'sbi_header_' ) !== 0 ? 'feed' : 'header';
487
- $num_images = isset( $num_images ) ? (int)$num_images : 33;
488
-
489
- if ( $num_images > 0 ) {
490
- $feed_tokens = $tokens ? $tokens : array();
491
- $new_cache = ! empty( $feed_tokens ) ? sbi_get_post_data_from_tokens( $feed_tokens, $cache_type, $num_images ) : '{"meta": {"code": 400, "error_type": "OAuthAccessTokenException", "error_message": "The access_token provided is invalid."}}"';
492
-
493
- if ( ! is_wp_error( $new_cache ) ) {
494
- set_transient( $transient_name, $new_cache, $cache_seconds );
495
-
496
- $backups_enabled = isset( $sb_instagram_settings['sb_instagram_backup'] ) ? $sb_instagram_settings['sb_instagram_backup'] !== '' : true;
497
-
498
- if ( $backups_enabled ) {
499
- if ( strlen( $new_cache ) > 1999 && strpos( $transient_name, 'sbi_header_' ) !== 0 ) {
500
- update_option( '!'.$transient_name, $new_cache, false );
501
- } elseif ( strpos( $transient_name, 'sbi_header_' ) === 0 ) {
502
- update_option( '!'.$transient_name, $new_cache, false );
503
- }
504
- }
505
  }
506
 
507
- }
508
- }
509
-
510
- function sbi_cache_photos() {
511
- $sb_instagram_settings = get_option('sb_instagram_settings');
512
- //If the caching time doesn't exist in the database then set it to be 1 hour
513
- ( !array_key_exists( 'sb_instagram_cache_time', $sb_instagram_settings ) ) ? $sb_instagram_cache_time = 1 : $sb_instagram_cache_time = $sb_instagram_settings['sb_instagram_cache_time'];
514
- ( !array_key_exists( 'sb_instagram_cache_time_unit', $sb_instagram_settings ) ) ? $sb_instagram_cache_time_unit = 'minutes' : $sb_instagram_cache_time_unit = $sb_instagram_settings['sb_instagram_cache_time_unit'];
515
- //Calculate the cache time in seconds
516
- if($sb_instagram_cache_time_unit == 'minutes') $sb_instagram_cache_time_unit = 60;
517
- if($sb_instagram_cache_time_unit == 'hours') $sb_instagram_cache_time_unit = 60*60;
518
- if($sb_instagram_cache_time_unit == 'days') $sb_instagram_cache_time_unit = 60*60*24;
519
- $cache_seconds = intval($sb_instagram_cache_time) * intval($sb_instagram_cache_time_unit);
520
-
521
- $transient_name = $_POST['transientName'];
522
- if ( is_array( $transient_name ) ) {
523
- $transient_name = isset( $transient_name['feed'] ) ? sanitize_text_field( $transient_name['feed'] ) : 'sbi_other';
524
- }
525
- $cache_type = strpos( $transient_name, 'sbi_header_' ) !== 0 ? 'feed' : 'header';
526
-
527
- // no longer processing header cache here
528
- if ( $cache_type === 'header' ) {
529
- die();
530
- }
531
- $existing_cache = get_transient( $transient_name );
532
-
533
- $existing_cache_decoded = $existing_cache ? json_decode( $existing_cache, true ) : array();
534
- $existing_cache_as_expected = isset( $existing_cache_decoded['data'] ) && isset( $existing_cache_decoded['data'][0]['id'] ) ? true : false;
535
-
536
- $num_images = isset( $_POST['num_images'] ) ? (int)$_POST['num_images'] : 33;
537
- if ( $existing_cache && $existing_cache_as_expected && $num_images > 0 ) {
538
- $feed_tokens = isset( $_POST['feed_tokens'] ) ? $_POST['feed_tokens'] : array();
539
- $new_cache = ! empty( $feed_tokens ) ? sbi_get_post_data_from_tokens( $feed_tokens, $cache_type, $num_images, $existing_cache_decoded ) : '';
540
-
541
- if ( ! is_wp_error( $new_cache ) ) {
542
- set_transient( $transient_name, $new_cache, $cache_seconds );
543
- $backups_enabled = isset( $sb_instagram_settings['sb_instagram_backup'] ) ? $sb_instagram_settings['sb_instagram_backup'] !== '' : true;
544
- if ( $backups_enabled ) {
545
- if ( strlen( $new_cache ) > 1999 && strpos( $transient_name, 'sbi_header_' ) !== 0 ) {
546
- update_option( '!' . $transient_name, $new_cache, false );
547
- } elseif ( strpos( $transient_name, 'sbi_header_' ) === 0 ) {
548
- update_option( '!' . $transient_name, $new_cache, false );
549
  }
550
- }
551
- }
552
- }
553
-
554
- die();
555
- }
556
- add_action('wp_ajax_cache_photos', 'sbi_cache_photos');
557
- add_action('wp_ajax_nopriv_cache_photos', 'sbi_cache_photos');
558
-
559
- function sbi_get_post_data_from_tokens( $access_tokens = array(), $cache_type = 'feed', $num_needed = 33, $existing_cache = array() ) {
560
-
561
- $images = array();
562
- $num_images_overall = 0;
563
- $pagination = array(
564
- 'next_url' => array()
565
- );
566
-
567
- if ( ! empty( $existing_cache ) ) {
568
- $num_images_overall = count( $existing_cache['data'] );
569
- $pagination = array(
570
- 'next_url' => $existing_cache['pagination']['next_url']
571
- );
572
- $images = isset( $existing_cache['data'] ) ? $existing_cache['data'] : array();
573
- }
574
 
575
- if ( empty( $pagination['next_url'] ) ) {
576
- foreach ( $access_tokens as $token ) {
577
- $clean_token = preg_replace("/[^a-zA-Z0-9\.]+/", "", sbi_maybe_clean( $token ) );
578
- $split_token = explode( '.', $clean_token );
579
- $id = $split_token[0];
580
- if ( $cache_type === 'header' ) {
581
- $api_call = 'https://api.instagram.com/v1/users/' . $id . '?access_token=' . $clean_token;
582
- } else {
583
- $api_call = 'https://api.instagram.com/v1/users/' . $id . '/media/recent?access_token=' . $clean_token . '&count=33';
584
  }
585
- $args = array(
586
- 'timeout' => 60,
587
- 'sslverify' => false
588
- );
589
- $result = wp_remote_get( $api_call, $args );
590
-
591
- if ( ! is_wp_error( $result ) ) {
592
- $decoded_results = json_decode( str_replace( '%22', '&rdquo;', $result['body'] ), true );
593
-
594
- if ( isset( $decoded_results['data'] ) && is_array( $decoded_results['data'] ) ) {
595
- $num_images_returned = count( $decoded_results['data'] );
596
- $num_images_overall += $num_images_returned;
597
- $images = array_merge( $images, $decoded_results['data'] );
598
- if ( !empty( $decoded_results['pagination']['next_url'] ) ) {
599
- $pagination['next_url'][] = $decoded_results['pagination']['next_url'];
600
- }
601
  } else {
602
- return $result['body'];
 
 
 
603
  }
604
-
605
  } else {
606
- // error
607
- return $result;
608
  }
609
- }
610
- }
611
-
612
- if ( $cache_type === 'feed' ) {
613
- $secondary_requests = 0;
614
-
615
- while ( $num_images_overall < $num_needed && ! empty( $pagination['next_url'] ) && $secondary_requests < 10 ) {
616
- $secondary_requests++;
617
- $api_call = array_shift( $pagination['next_url'] );
618
- $args = array(
619
- 'timeout' => 60,
620
- 'sslverify' => false
621
- );
622
- $result = wp_remote_get( $api_call, $args );
623
- if ( ! is_wp_error( $result ) ) {
624
- $decoded_results = json_decode( str_replace( '%20', '&rdquo;', $result['body'] ), true );
625
- $num_images_returned = 0;
626
- if ( isset( $decoded_results['data'] ) && is_array( $decoded_results['data'] ) ) {
627
- $num_images_returned = count( $decoded_results['data'] );
628
- $num_images_overall += $num_images_returned;
629
- $images = array_merge( $images, $decoded_results['data'] );
630
- if ( !empty( $decoded_results['pagination']['next_url'] ) ) {
631
- $pagination['next_url'][] = $decoded_results['pagination']['next_url'];
632
- }
633
- } else {
634
- return $result['body'];
635
- }
636
-
637
- } else {
638
- // error
639
- return $result;
640
- }
641
-
642
- }
643
- }
644
-
645
- if ( isset( $images[0]['created_time'] ) ) {
646
- usort($images, 'sbi_date_sort' );
647
- }
648
-
649
- $return = array(
650
- 'pagination' => $pagination,
651
- 'data' => $images,
652
- 'meta' => array()
653
- );
654
-
655
- return json_encode( $return );
656
- }
657
 
658
- function sbi_date_sort( $a, $b ) {
659
-
660
- if ( isset( $a['created_time'] ) ) {
661
- return (int)$b['created_time'] - (int)$a['created_time'];
662
- } else {
663
- return rand ( -1, 1 );
664
- }
665
-
666
- }
667
-
668
- function sbi_set_expired_token() {
669
- $access_token = isset( $_POST['access_token'] ) ? sanitize_text_field( $_POST['access_token'] ) : false;
670
-
671
- if ( $access_token !== false ) {
672
- $expired_tokens = get_option( 'sb_expired_tokens', array() );
673
-
674
- if (! in_array( sbi_maybe_clean( $access_token ), $expired_tokens, true ) ) {
675
- $expired_tokens[] = sbi_maybe_clean( $access_token );
676
- }
677
-
678
- update_option( 'sb_expired_tokens', $expired_tokens, false );
679
- }
680
-
681
- die();
682
- }
683
- add_action('wp_ajax_sbi_set_expired_token', 'sbi_set_expired_token');
684
- add_action('wp_ajax_nopriv_sbi_set_expired_token', 'sbi_set_expired_token');
685
-
686
- function sbi_set_use_backup() {
687
- $sb_instagram_settings = get_option('sb_instagram_settings');
688
- $backups_enabled = isset( $sb_instagram_settings['sb_instagram_backup'] ) ? $sb_instagram_settings['sb_instagram_backup'] !== '' : true;
689
- $context = isset( $_POST['context'] ) ? sanitize_text_field( $_POST['context'] ) : 'use_backup';
690
-
691
- if ( $backups_enabled ) {
692
- $transient_name = $_POST['transientName'];
693
-
694
- if ( is_array( $transient_name ) ) {
695
- $transient_name = isset( $transient_name['feed'] ) ? sanitize_text_field( $transient_name['feed'] ) : 'sbi_other';
696
- }
697
- $backup_exists = get_option( '!' . $transient_name, false );
698
-
699
- if ( ! get_transient( '&' . $transient_name ) && $backup_exists !== false ) {
700
- set_transient( '&' . $transient_name, $context, 86400 );
701
  }
702
 
 
 
703
  }
704
 
705
- die();
706
- }
707
- add_action('wp_ajax_sbi_set_use_backup', 'sbi_set_use_backup');
708
- add_action('wp_ajax_nopriv_sbi_set_use_backup', 'sbi_set_use_backup');
709
-
710
- function sbi_encode_uri( $uri )
711
- {
712
- $unescaped = array(
713
- '%2D'=>'-','%5F'=>'_','%2E'=>'.','%21'=>'!', '%7E'=>'~',
714
- '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')'
715
- );
716
- $reserved = array(
717
- '%3B'=>';','%2C'=>',','%2F'=>'/','%3F'=>'?','%3A'=>':',
718
- '%40'=>'@','%26'=>'&','%3D'=>'=','%2B'=>'+','%24'=>'$'
719
- );
720
- $score = array(
721
- '%23'=>'#'
722
- );
723
-
724
- return strtr( rawurlencode( $uri ), array_merge( $reserved,$unescaped,$score ) );
725
- }
726
-
727
- function sbi_get_cache() {
728
- $options = get_option( 'sb_instagram_settings' );
729
-
730
- $transient_names = json_decode(str_replace( array( '\"', "\\'" ), array( '"', "'" ), sanitize_text_field( $_POST['transientName'] ) ), true);
731
- $header_cache_data_transient_data = strpos( $transient_names['header'], 'sbi_' ) !== false ? get_transient( $transient_names['header'] ) : false;
732
- $should_use_backup_header = isset( $_POST['useBackupHeader'] ) && sanitize_text_field( $_POST['useBackupHeader'] ) == 'true' ? true : false;
733
- $should_use_backup_feed = isset( $_POST['useBackupFeed'] ) && sanitize_text_field( $_POST['useBackupFeed'] ) == 'true' ? true : false;
734
- $feed_cache_transient_data = strpos( $transient_names['feed'], 'sbi_' ) !== false ? get_transient( $transient_names['feed'] ) : false;
735
 
736
- // verify contents of cache {"pagination":
737
- if ( strpos( $feed_cache_transient_data, '{"pagination":' ) !== 0 ) {
738
- $feed_cache_transient_data = false;
739
- }
740
- if ( strpos( $header_cache_data_transient_data, '{"pagination":' ) !== 0 ) {
741
- $header_cache_data_transient_data = false;
 
 
742
  }
743
 
744
- $warning_message_data = '';
745
- $backups_enabled = isset( $options['sb_instagram_backup'] ) ? $options['sb_instagram_backup'] !== '' : true;
746
-
747
- if ( ! empty( $feed_cache_transient_data ) ) {
748
- $feed_cache_data = $feed_cache_transient_data;
749
- } elseif ( ! isset( $options['check_api'] ) || $options['check_api'] === 'on' || $options['check_api'] === true ) {
750
- $feed_cache_data = '{"error":"tryfetch"}';
751
- } elseif ( !get_transient( 'sbi_doing_tryfetch_once' ) && $backups_enabled ) {
752
- set_transient( 'sbi_doing_tryfetch_once', 'true', 60*60 );
753
- $feed_cache_data = '{"error":"tryfetch"}';
754
- $warning_message_data = ',"tryfetchonce":{"tryfetchonce":"tryfetchonce"}';
755
- } else {
756
- $feed_cache_data = '{"error":"nocache"}';
757
- }
758
 
759
- $comment_cache_data = '{"error":"nocache"}';
760
-
761
- // maybe use backup cache
762
- $still_using_backup = get_transient( '&'.$transient_names['feed'], false );
763
- $doing_tryfetch = (isset( $options['check_api'] ) && $options['check_api'] === 'on' || $options['check_api']);
764
- $header_cache_data = '{"error":"nocache"}';
765
- if ( ! empty( $header_cache_data_transient_data ) ) {
766
- $header_cache_data = $header_cache_data_transient_data;
767
- } elseif ( $doing_tryfetch ) {
768
- $header_cache_data = '{"error":"tryfetch"}';
769
- } elseif ( !get_transient( 'sbi_doing_tryfetch_once' ) && $backups_enabled ) {
770
- set_transient( 'sbi_doing_tryfetch_once', 'true', 60*60 );
771
- $feed_cache_data = '{"error":"tryfetch"}';
772
- $warning_message_data = ',"tryfetchonce":{"tryfetchonce":"tryfetchonce"}';
773
- } elseif ( empty( $header_cache_data_transient_data ) || $still_using_backup ) {
774
- $backup_header_cache = get_option( '!' . $transient_names['header'] );
775
- $header_cache_data = ! empty( $backup_header_cache ) ? $backup_header_cache : '{"error":"nocache"}';
776
- if ( strpos( $header_cache_data, '{"pagination":' ) !== 0 ) {
777
- $header_cache_data = '{"error":"nocache"}';
778
- }
779
- if ( $still_using_backup === 'falsecache' ) {
780
- $warning_message_data = ',"warning":{"warning":"falsecache"}';
781
- }
782
- } else {
783
- $header_cache_data = ! empty( $header_cache_data ) ? $header_cache_data : '{"error":"nocache"}';
784
- }
785
 
786
- // maybe use backup cache
787
- if ( (empty( $feed_cache_transient_data ) && $should_use_backup_feed) || $still_using_backup ) {
788
- $backup_feed_cache = get_option( '!' . $transient_names['feed'] );
789
- $feed_cache_data = ! empty( $backup_feed_cache ) ? $backup_feed_cache : $feed_cache_data;
790
- if ( strpos( $feed_cache_data, '{"pagination":' ) !== 0 ) {
791
- $feed_cache_data = '{"error":"nocache"}';
792
- }
793
- if ( $still_using_backup === 'falsecache' ) {
794
- $warning_message_data = ',"warning":{"warning":"falsecache"}';
795
  }
796
- }
797
 
798
- $data = '{"header":' . $header_cache_data .',"feed":' . $feed_cache_data . ',"comments":' . $comment_cache_data . $warning_message_data . '}';
799
-
800
- echo $data;
801
-
802
- die();
803
- }
804
- add_action('wp_ajax_get_cache', 'sbi_get_cache');
805
- add_action('wp_ajax_nopriv_get_cache', 'sbi_get_cache');
 
 
 
 
 
 
 
 
 
 
 
 
 
806
 
807
- function sbi_maybe_clean( $maybe_dirty ) {
808
- if ( substr_count ( $maybe_dirty , '.' ) < 3 ) {
809
- return $maybe_dirty;
810
- }
 
 
 
 
 
 
 
 
811
 
812
- $parts = explode( '.', trim( $maybe_dirty ) );
813
- $last_part = $parts[2] . $parts[3];
814
- $cleaned = $parts[0] . '.' . base64_decode( $parts[1] ) . '.' . base64_decode( $last_part );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
 
816
- return $cleaned;
817
- }
818
- function sbi_get_parts( $whole ) {
819
- if ( substr_count ( $whole , '.' ) !== 2 ) {
820
- return $whole;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  }
822
 
823
- $parts = explode( '.', trim( $whole ) );
824
- $return = $parts[0] . '.' . base64_encode( $parts[1] ). '.' . base64_encode( $parts[2] );
825
-
826
- return substr( $return, 0, 40 ) . '.' . substr( $return, 40, 100 );
827
- }
828
-
829
- //Enqueue stylesheet
830
- add_action( 'wp_enqueue_scripts', 'sb_instagram_styles_enqueue' );
831
- function sb_instagram_styles_enqueue() {
832
- wp_register_style( 'sb_instagram_styles', plugins_url('css/sb-instagram.min.css', __FILE__), array(), SBIVER );
833
- wp_enqueue_style( 'sb_instagram_styles' );
834
-
835
- $options = get_option('sb_instagram_settings');
836
- if(isset($options['sb_instagram_disable_awesome'])){
837
- if( !$options['sb_instagram_disable_awesome'] || !isset($options['sb_instagram_disable_awesome']) ) wp_enqueue_style( 'sb-font-awesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', array(), '4.7.0' );
838
- }
839
-
840
- }
841
-
842
- //Enqueue scripts
843
- add_action( 'wp_enqueue_scripts', 'sb_instagram_scripts_enqueue' );
844
- function sb_instagram_scripts_enqueue() {
845
- //Register the script to make it available
846
- wp_register_script( 'sb_instagram_scripts', plugins_url( '/js/sb-instagram.min.js' , __FILE__ ), array('jquery'), SBIVER, true ); //http://www.minifier.org/
847
 
848
- //Options to pass to JS file
849
- $sb_instagram_settings = get_option('sb_instagram_settings');
850
 
851
- //Access token
852
- $font_method = isset( $sb_instagram_settings['sbi_font_method'] ) ? $sb_instagram_settings['sbi_font_method'] : 'svg';
853
- $access_token = isset( $sb_instagram_settings['sb_instagram_at'] ) ? $sb_instagram_settings['sb_instagram_at'] : '';
854
- $disable_font_awesome = isset($sb_instagram_settings['sb_instagram_disable_awesome']) ? $sb_instagram_settings['sb_instagram_disable_awesome'] : false;
855
 
856
- if ( $font_method === 'fontfile' && ! $disable_font_awesome ) {
857
- wp_enqueue_style( 'sb-font-awesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' );
858
- }
 
 
 
859
 
860
- isset($sb_instagram_settings[ 'sb_instagram_ajax_theme' ]) ? $sb_instagram_ajax_theme = trim($sb_instagram_settings['sb_instagram_ajax_theme']) : $sb_instagram_ajax_theme = '';
861
- ( $sb_instagram_ajax_theme == 'on' || $sb_instagram_ajax_theme == 'true' || $sb_instagram_ajax_theme == true ) ? $sb_instagram_ajax_theme = true : $sb_instagram_ajax_theme = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
 
863
- //Enqueue it to load it onto the page
864
- if( !$sb_instagram_ajax_theme ) wp_enqueue_script('sb_instagram_scripts');
865
 
866
- //Pass option to JS file
867
- $font_method = isset( $sb_instagram_settings['sbi_font_method'] ) ? $sb_instagram_settings['sbi_font_method'] : 'svg';
868
- $data = array(
869
- 'sb_instagram_at' => sbi_get_parts( $access_token ),
870
- 'font_method' => $font_method,
871
- );
872
- wp_localize_script('sb_instagram_scripts', 'sb_instagram_js_options', $data);
873
- }
874
-
875
- //Custom CSS
876
- add_action( 'wp_head', 'sb_instagram_custom_css' );
877
- function sb_instagram_custom_css() {
878
- $options = get_option('sb_instagram_settings');
879
-
880
- isset($options[ 'sb_instagram_custom_css' ]) ? $sb_instagram_custom_css = trim($options['sb_instagram_custom_css']) : $sb_instagram_custom_css = '';
881
-
882
- //Show CSS if an admin (so can see Hide Photos link), if including Custom CSS or if hiding some photos
883
- ( current_user_can( 'manage_options' ) || !empty($sb_instagram_custom_css) ) ? $sbi_show_css = true : $sbi_show_css = false;
884
-
885
- if( $sbi_show_css ) echo '<!-- Instagram Feed CSS -->';
886
- if( $sbi_show_css ) echo "\r\n";
887
- if( $sbi_show_css ) echo '<style type="text/css">';
888
-
889
- if( !empty($sb_instagram_custom_css) ){
890
- echo "\r\n";
891
- echo stripslashes($sb_instagram_custom_css);
892
- }
893
-
894
- if( current_user_can( 'manage_options' ) ){
895
- echo "\r\n";
896
- echo "#sbi_mod_error{ display: block !important; }";
897
- }
898
-
899
- if( $sbi_show_css ) echo "\r\n";
900
- if( $sbi_show_css ) echo '</style>';
901
- if( $sbi_show_css ) echo "\r\n";
902
- }
903
 
 
904
 
905
- //Custom JS
906
- add_action( 'wp_footer', 'sb_instagram_custom_js' );
907
- function sb_instagram_custom_js() {
908
- $options = get_option('sb_instagram_settings');
909
- isset($options[ 'sb_instagram_custom_js' ]) ? $sb_instagram_custom_js = trim($options['sb_instagram_custom_js']) : $sb_instagram_custom_js = '';
910
-
911
- echo '<!-- Instagram Feed JS -->';
912
- echo "\r\n";
913
- echo '<script type="text/javascript">';
914
- echo "\r\n";
915
- echo 'var sbiajaxurl = "' . admin_url('admin-ajax.php') . '";';
916
-
917
- if( !empty($sb_instagram_custom_js) ) echo "\r\n";
918
- if( !empty($sb_instagram_custom_js) ) echo "jQuery( document ).ready(function($) {";
919
- if( !empty($sb_instagram_custom_js) ) echo "\r\n";
920
- if( !empty($sb_instagram_custom_js) ) echo "window.sbi_custom_js = function(){";
921
- if( !empty($sb_instagram_custom_js) ) echo "\r\n";
922
- if( !empty($sb_instagram_custom_js) ) echo stripslashes($sb_instagram_custom_js);
923
- if( !empty($sb_instagram_custom_js) ) echo "\r\n";
924
- if( !empty($sb_instagram_custom_js) ) echo "}";
925
- if( !empty($sb_instagram_custom_js) ) echo "\r\n";
926
- if( !empty($sb_instagram_custom_js) ) echo "});";
927
-
928
- echo "\r\n";
929
- echo '</script>';
930
- echo "\r\n";
931
 
932
- }
933
 
934
- if ( ! function_exists( 'sb_remove_style_version' ) ) {
935
- function sb_remove_style_version( $src, $handle ){
936
 
937
- if ( $handle === 'sb-font-awesome' ) {
938
- $parts = explode( '?ver', $src );
939
- return $parts[0];
940
- } else {
941
- return $src;
942
  }
943
 
944
  }
945
- add_filter( 'style_loader_src', 'sb_remove_style_version', 15, 2 );
946
- }
947
-
948
- // Load plugin textdomain
949
- add_action( 'init', 'sb_instagram_load_textdomain' );
950
- function sb_instagram_load_textdomain() {
951
- load_plugin_textdomain('instagram-feed', false, basename( dirname(__FILE__) ) . '/languages');
952
- }
953
-
954
- //Run function on plugin activate
955
- function sb_instagram_activate() {
956
- $options = get_option('sb_instagram_settings');
957
- $options[ 'sb_instagram_show_btn' ] = true;
958
- $options[ 'sb_instagram_show_header' ] = true;
959
- $options[ 'sb_instagram_show_follow_btn' ] = true;
960
- update_option( 'sb_instagram_settings', $options );
961
- delete_option( 'sb_expired_tokens' );
962
-
963
- global $wp_roles;
964
- $wp_roles->add_cap( 'administrator', 'manage_instagram_feed_options' );
965
- }
966
- register_activation_hook( __FILE__, 'sb_instagram_activate' );
967
 
968
- //Uninstall
969
- function sb_instagram_uninstall()
970
- {
971
- if ( ! current_user_can( 'activate_plugins' ) )
972
- return;
973
 
974
- //If the user is preserving the settings then don't delete them
975
- $options = get_option('sb_instagram_settings');
976
- $sb_instagram_preserve_settings = $options[ 'sb_instagram_preserve_settings' ];
977
- if($sb_instagram_preserve_settings) return;
 
 
 
 
 
 
 
978
 
979
- //Settings
980
- delete_option( 'sb_instagram_settings' );
 
 
 
 
981
 
982
- global $wpdb;
983
- $table_name = $wpdb->prefix . "options";
984
- $wpdb->query( "
 
 
 
 
 
 
 
 
 
 
 
985
  DELETE
986
  FROM $table_name
987
  WHERE `option_name` LIKE ('%!sbi\_%')
988
  " );
989
- $wpdb->query( "
990
  DELETE
991
  FROM $table_name
992
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
993
  " );
994
- $wpdb->query( "
995
  DELETE
996
  FROM $table_name
997
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
998
  " );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
999
 
1000
- global $wp_roles;
1001
- $wp_roles->remove_cap( 'administrator', 'manage_instagram_feed_options' );
1002
- }
1003
- register_uninstall_hook( __FILE__, 'sb_instagram_uninstall' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
  /*
3
+ Plugin Name: Smash Balloon Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
+ Description: Display beautifully clean, customizable, and responsive Instagram feeds.
6
+ Version: 2.0
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
22
  along with this program; if not, write to the Free Software
23
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
  */
25
+ if ( ! defined( 'SBIVER' ) ) {
26
+ define( 'SBIVER', '2.0' );
27
+ }
28
+ // Db version.
29
+ if ( ! defined( 'SBI_DBVERSION' ) ) {
30
+ define( 'SBI_DBVERSION', '1.2' );
31
+ }
32
 
33
+ // Upload folder name for local image files for posts
34
+ if ( ! defined( 'SBI_UPLOADS_NAME' ) ) {
35
+ define( 'SBI_UPLOADS_NAME', 'sb-instagram-feed-images' );
36
+ }
37
+ // Name of the database table that contains instagram posts
38
+ if ( ! defined( 'SBI_INSTAGRAM_POSTS_TYPE' ) ) {
39
+ define( 'SBI_INSTAGRAM_POSTS_TYPE', 'sbi_instagram_posts' );
40
+ }
41
+ // Name of the database table that contains feed ids and the ids of posts
42
+ if ( ! defined( 'SBI_INSTAGRAM_FEEDS_POSTS' ) ) {
43
+ define( 'SBI_INSTAGRAM_FEEDS_POSTS', 'sbi_instagram_feeds_posts' );
44
+ }
45
 
46
  if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
47
+ if ( function_exists( 'sb_instagram_feed_init' ) ) {
48
+ wp_die( "Please deactivate Custom Feeds for Instagram Pro before activating this version.<br /><br />Back to the WordPress <a href='".get_admin_url(null, 'plugins.php')."'>Plugins page</a>." );
49
+ } else {
50
+ /**
51
+ * Define constants and load plugin files
52
+ *
53
+ * @since 2.0
54
+ */
55
+ function sb_instagram_feed_init() {
56
+ // Plugin Folder Path.
57
+ if ( ! defined( 'SBI_PLUGIN_DIR' ) ) {
58
+ define( 'SBI_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
+ // Plugin Folder URL.
61
+ if ( ! defined( 'SBI_PLUGIN_URL' ) ) {
62
+ define( 'SBI_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
 
 
 
 
 
 
63
  }
64
+ // Plugin Base Name
65
+ if ( ! defined( 'SBI_PLUGIN_BASENAME' ) ) {
66
+ define( 'SBI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
+ // Plugin Base Name
69
+ if ( ! defined( 'SBI_BACKUP_PREFIX' ) ) {
70
+ define( 'SBI_BACKUP_PREFIX', '!' );
 
 
 
 
 
 
71
  }
72
+ // Plugin Base Name
73
+ if ( ! defined( 'SBI_FPL_PREFIX' ) ) {
74
+ define( 'SBI_FPL_PREFIX', '$' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
+ // Plugin Base Name
77
+ if ( ! defined( 'SBI_USE_BACKUP_PREFIX' ) ) {
78
+ define( 'SBI_USE_BACKUP_PREFIX', '&' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
+ // Cron Updating Cache Time 60 days
81
+ if ( ! defined( 'SBI_CRON_UPDATE_CACHE_TIME' ) ) {
82
+ define( 'SBI_CRON_UPDATE_CACHE_TIME', 60 * 60 * 24 * 60 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
+ // Max Records in Database for Image Resizing
85
+ if ( ! defined( 'SBI_MAX_RECORDS' ) ) {
86
+ define( 'SBI_MAX_RECORDS', 100 );
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/if-functions.php';
90
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-api-connect.php';
91
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-cron-updater.php';
92
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-display-elements.php';
93
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-feed.php';
94
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-parse.php';
95
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-post.php';
96
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-post-set.php';
97
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-posts-manager.php';
98
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/class-sb-instagram-settings.php';
99
+
100
+ if ( is_admin() ) {
101
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/actions.php';
102
+ require_once trailingslashit( SBI_PLUGIN_DIR ) . 'inc/admin/main.php';
103
+ }
104
 
105
+ global $sb_instagram_posts_manager;
106
+ $sb_instagram_posts_manager = new SB_Instagram_Posts_Manager();
107
+ }
108
+
109
+ add_action( 'plugins_loaded', 'sb_instagram_feed_init' );
110
+
111
+ /**
112
+ * Add the custom interval of 30 minutes for cron caching
113
+ *
114
+ * @param array $schedules current list of cron intervals
115
+ *
116
+ * @return array
117
+ *
118
+ * @since 2.0
119
+ */
120
+ function sbi_cron_custom_interval( $schedules ) {
121
+ $schedules['sbi30mins'] = array(
122
+ 'interval' => 30 * 60,
123
+ 'display' => __( 'Every 30 minutes' )
124
+ );
125
 
126
+ return $schedules;
 
 
127
  }
128
 
129
+ add_filter( 'cron_schedules', 'sbi_cron_custom_interval' );
 
 
 
130
 
131
+ /**
132
+ * Create database tables, schedule cron events, initiate capabilities
133
+ *
134
+ * @param bool $network_wide is a multisite network activation
135
+ *
136
+ * @since 2.0 database tables and capabilties created
137
+ * @since 1.0
138
+ */
139
+ function sb_instagram_activate( $network_wide ) {
140
+ //Clear page caching plugins and autoptomize
141
+ if ( is_callable( 'sb_instagram_clear_page_caches' ) ) {
142
+ sb_instagram_clear_page_caches();
143
  }
 
 
 
 
144
 
145
+ //Run cron twice daily when plugin is first activated for new users
146
+ if ( ! wp_next_scheduled( 'sb_instagram_cron_job' ) ) {
147
+ wp_schedule_event( time(), 'twicedaily', 'sb_instagram_cron_job' );
 
 
 
 
148
  }
149
 
150
+ $sbi_settings = get_option( 'sb_instagram_settings', array() );
151
+ if ( isset( $sbi_settings['sbi_caching_type'] ) && $sbi_settings['sbi_caching_type'] === 'background' ) {
152
+ require_once trailingslashit( plugin_dir_path( __FILE__ ) ) . 'inc/if-functions.php';
153
+ require_once trailingslashit( plugin_dir_path( __FILE__ ) ) . 'inc/class-sb-instagram-cron-updater.php';
154
+ SB_Instagram_Cron_Updater::start_cron_job( $sbi_settings['sbi_cache_cron_interval'], $sbi_settings['sbi_cache_cron_time'], $sbi_settings['sbi_cache_cron_am_pm'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
157
+ require_once( trailingslashit( dirname( __FILE__ ) ) . 'inc/class-sb-instagram-posts-manager.php' );
158
+ $sb_instagram_posts_manager = new SB_Instagram_Posts_Manager();
159
+
160
+ if ( is_multisite() && $network_wide && function_exists( 'get_sites' ) && class_exists( 'WP_Site_Query' ) ) {
161
+
162
+ // Get all blogs in the network and activate plugin on each one
163
+ $sites = get_sites();
164
+ foreach ( $sites as $site ) {
165
+ switch_to_blog( $site->blog_id );
166
+
167
+ $upload = wp_upload_dir();
168
+ $upload_dir = $upload['basedir'];
169
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
170
+ if ( ! file_exists( $upload_dir ) ) {
171
+ $created = wp_mkdir_p( $upload_dir );
172
+ if ( $created ) {
173
+ $sb_instagram_posts_manager->remove_error( 'upload_dir' );
174
+ } else {
175
+ $sb_instagram_posts_manager->add_error( 'upload_dir', array(
176
+ __( 'There was an error creating the folder for storing resized images.', 'instagram-feed' ),
177
+ $upload_dir
178
+ ) );
179
+ }
180
+ } else {
181
+ $sb_instagram_posts_manager->remove_error( 'upload_dir' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
+ sbi_create_database_table();
185
+ restore_current_blog();
 
 
 
 
 
 
 
186
  }
187
+
188
+ } else {
189
+ $upload = wp_upload_dir();
190
+ $upload_dir = $upload['basedir'];
191
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
192
+ if ( ! file_exists( $upload_dir ) ) {
193
+ $created = wp_mkdir_p( $upload_dir );
194
+ if ( $created ) {
195
+ $sb_instagram_posts_manager->remove_error( 'upload_dir' );
 
 
 
 
 
 
 
196
  } else {
197
+ $sb_instagram_posts_manager->add_error( 'upload_dir', array(
198
+ __( 'There was an error creating the folder for storing resized images.', 'instagram-feed' ),
199
+ $upload_dir
200
+ ) );
201
  }
 
202
  } else {
203
+ $sb_instagram_posts_manager->remove_error( 'upload_dir' );
 
204
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
+ sbi_create_database_table();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
+ global $wp_roles;
210
+ $wp_roles->add_cap( 'administrator', 'manage_instagram_feed_options' );
211
  }
212
 
213
+ register_activation_hook( __FILE__, 'sb_instagram_activate' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ /**
216
+ * Stop cron events when deactivated
217
+ *
218
+ * @since 1.0
219
+ */
220
+ function sb_instagram_deactivate() {
221
+ wp_clear_scheduled_hook( 'sb_instagram_cron_job' );
222
+ wp_clear_scheduled_hook( 'sbi_feed_update' );
223
  }
224
 
225
+ register_deactivation_hook( __FILE__, 'sb_instagram_deactivate' );
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
+ /**
228
+ * Creates custom database tables and directory for storing custom
229
+ * images
230
+ *
231
+ * @since 2.0
232
+ */
233
+ function sbi_create_database_table() {
234
+ global $wpdb;
235
+ global $sb_instagram_posts_manager;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
+ if ( ! isset( $sb_instagram_posts_manager ) ) {
238
+ require_once( trailingslashit( dirname( __FILE__ ) ) . 'inc/class-sb-instagram-posts-manager.php' );
239
+ $sb_instagram_posts_manager = new SB_Instagram_Posts_Manager();
 
 
 
 
 
 
240
  }
 
241
 
242
+ global $wp_version;
243
+
244
+ if ( version_compare( $wp_version, '3.5', '<' ) ) {
245
+ $table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE );
246
+
247
+ if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
248
+ $sql = "CREATE TABLE " . $table_name . " (
249
+ id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
250
+ created_on DATETIME,
251
+ instagram_id VARCHAR(1000) DEFAULT '' NOT NULL,
252
+ time_stamp DATETIME,
253
+ top_time_stamp DATETIME,
254
+ json_data LONGTEXT DEFAULT '' NOT NULL,
255
+ media_id VARCHAR(1000) DEFAULT '' NOT NULL,
256
+ sizes VARCHAR(1000) DEFAULT '' NOT NULL,
257
+ aspect_ratio DECIMAL (4,2) DEFAULT 0 NOT NULL,
258
+ images_done TINYINT(1) DEFAULT 0 NOT NULL,
259
+ last_requested DATE
260
+ );";
261
+ $wpdb->query( $sql );
262
+ }
263
 
264
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
265
+
266
+ if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
267
+ $sql = "CREATE TABLE " . $feeds_posts_table_name . " (
268
+ record_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
269
+ id INT(11) UNSIGNED NOT NULL,
270
+ instagram_id VARCHAR(1000) DEFAULT '' NOT NULL,
271
+ feed_id VARCHAR(1000) DEFAULT '' NOT NULL,
272
+ INDEX feed_id (feed_id(100))
273
+ );";
274
+ $wpdb->query( $sql );
275
+ }
276
 
277
+ return;
278
+ } else {
279
+ $charset_collate = $wpdb->get_charset_collate();
280
+ $table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE );
281
+
282
+ if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
283
+ $sql = "CREATE TABLE " . $table_name . " (
284
+ id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
285
+ created_on DATETIME,
286
+ instagram_id VARCHAR(1000) DEFAULT '' NOT NULL,
287
+ time_stamp DATETIME,
288
+ top_time_stamp DATETIME,
289
+ json_data LONGTEXT DEFAULT '' NOT NULL,
290
+ media_id VARCHAR(1000) DEFAULT '' NOT NULL,
291
+ sizes VARCHAR(1000) DEFAULT '' NOT NULL,
292
+ aspect_ratio DECIMAL (4,2) DEFAULT 0 NOT NULL,
293
+ images_done TINYINT(1) DEFAULT 0 NOT NULL,
294
+ last_requested DATE
295
+ ) $charset_collate;";
296
+ $wpdb->query( $sql );
297
+ }
298
+ $error = $wpdb->last_error;
299
+ $query = $wpdb->last_query;
300
+
301
+ if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
302
+ $sb_instagram_posts_manager->add_error( 'database_create_posts', array(
303
+ __( 'There was an error when trying to create the database tables used for resizing images.', 'instagram-feed' ),
304
+ $error . '<br><code>' . $query . '</code>'
305
+ ) );
306
+ } else {
307
+ $sb_instagram_posts_manager->remove_error( 'database_create_posts' );
308
+ }
309
 
310
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
311
+
312
+ if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
313
+ $sql = "CREATE TABLE " . $feeds_posts_table_name . " (
314
+ record_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
315
+ id INT(11) UNSIGNED NOT NULL,
316
+ instagram_id VARCHAR(1000) DEFAULT '' NOT NULL,
317
+ feed_id VARCHAR(1000) DEFAULT '' NOT NULL,
318
+ INDEX feed_id (feed_id(100))
319
+ ) $charset_collate;";
320
+ $wpdb->query( $sql );
321
+ }
322
+ $error = $wpdb->last_error;
323
+ $query = $wpdb->last_query;
324
+
325
+ if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
326
+ $sb_instagram_posts_manager->add_error( 'database_create_posts_feeds', array(
327
+ __( 'There was an error when trying to create the database tables used for resizing images.', 'instagram-feed' ),
328
+ $error . '<br><code>' . $query . '</code>'
329
+ ) );
330
+ } else {
331
+ $sb_instagram_posts_manager->remove_error( 'database_create_posts_feeds' );
332
+ }
333
+ }
334
  }
335
 
336
+ /**
337
+ * Compares previous plugin version and updates database related
338
+ * items as needed
339
+ *
340
+ * @since 2.0
341
+ */
342
+ function sbi_check_for_db_updates() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
 
344
+ $db_ver = get_option( 'sbi_db_version', 0 );
 
345
 
346
+ if ( (float) $db_ver < 1.2 ) {
 
 
 
347
 
348
+ $upload = wp_upload_dir();
349
+ $upload_dir = $upload['basedir'];
350
+ $upload_dir = trailingslashit( $upload_dir ) . SBI_UPLOADS_NAME;
351
+ if ( ! file_exists( $upload_dir ) ) {
352
+ $created = wp_mkdir_p( $upload_dir );
353
+ }
354
 
355
+ sbi_create_database_table();
356
+
357
+ global $wp_roles;
358
+ $wp_roles->add_cap( 'administrator', 'manage_instagram_feed_options' );
359
+
360
+ //Delete all transients
361
+ global $wpdb;
362
+ $table_name = $wpdb->prefix . "options";
363
+ $wpdb->query( "
364
+ DELETE
365
+ FROM $table_name
366
+ WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
367
+ " );
368
+ $wpdb->query( "
369
+ DELETE
370
+ FROM $table_name
371
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
372
+ " );
373
+ $wpdb->query( "
374
+ DELETE
375
+ FROM $table_name
376
+ WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
377
+ " );
378
+ $wpdb->query( "
379
+ DELETE
380
+ FROM $table_name
381
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
382
+ " );
383
+ $wpdb->query( "
384
+ DELETE
385
+ FROM $table_name
386
+ WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
387
+ " );
388
+ $wpdb->query( "
389
+ DELETE
390
+ FROM $table_name
391
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
392
+ " );
393
+
394
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
395
+
396
+ if ( ! isset( $sbi_statuses_option['first_install'] ) ) {
397
+
398
+ $options_set = get_option( 'sb_instagram_settings', false );
399
+
400
+ if ( $options_set ) {
401
+ $sbi_statuses_option['first_install'] = 'from_update';
402
+ } else {
403
+ $sbi_statuses_option['first_install'] = time();
404
+ }
405
 
406
+ $sbi_rating_notice_option = get_option( 'sbi_rating_notice', false );
 
407
 
408
+ if ( $sbi_rating_notice_option === 'dismissed' ) {
409
+ $sbi_statuses_option['rating_notice_dismissed'] = time();
410
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
 
412
+ $sbi_rating_notice_waiting = get_transient( 'instagram_feed_rating_notice_waiting' );
413
 
414
+ if ( $sbi_rating_notice_waiting === false
415
+ && $sbi_rating_notice_option === false ) {
416
+ $time = 2 * WEEK_IN_SECONDS;
417
+ set_transient( 'instagram_feed_rating_notice_waiting', 'waiting', $time );
418
+ update_option( 'sbi_rating_notice', 'pending', false );
419
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
+ update_option( 'sbi_statuses', $sbi_statuses_option, false );
422
 
423
+ }
 
424
 
425
+ update_option( 'sbi_db_version', SBI_DBVERSION );
 
 
 
 
426
  }
427
 
428
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
 
430
+ add_action( 'wp_loaded', 'sbi_check_for_db_updates' );
 
 
 
 
431
 
432
+ /**
433
+ * Deletes saved data for the plugin unless setting to preserve
434
+ * settings is enabled
435
+ *
436
+ * @since 2.0 custom tables, custom images, and image directory deleted
437
+ * @since 1.0
438
+ */
439
+ function sb_instagram_uninstall() {
440
+ if ( ! current_user_can( 'activate_plugins' ) ) {
441
+ return;
442
+ }
443
 
444
+ //If the user is preserving the settings then don't delete them
445
+ $options = get_option( 'sb_instagram_settings' );
446
+ $sb_instagram_preserve_settings = $options['sb_instagram_preserve_settings'];
447
+ if ( $sb_instagram_preserve_settings ) {
448
+ return;
449
+ }
450
 
451
+ //Settings
452
+ delete_option( 'sb_instagram_settings' );
453
+ delete_option( 'sbi_ver' );
454
+ delete_option( 'sbi_db_version' );
455
+ delete_option( 'sb_expired_tokens' );
456
+ delete_option( 'sbi_cron_report' );
457
+ delete_option( 'sb_instagram_errors' );
458
+ delete_option( 'sb_instagram_ajax_status' );
459
+ delete_option( 'sbi_statuses' );
460
+
461
+ // Clear backup caches
462
+ global $wpdb;
463
+ $table_name = $wpdb->prefix . "options";
464
+ $wpdb->query( "
465
  DELETE
466
  FROM $table_name
467
  WHERE `option_name` LIKE ('%!sbi\_%')
468
  " );
469
+ $wpdb->query( "
470
  DELETE
471
  FROM $table_name
472
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
473
  " );
474
+ $wpdb->query( "
475
  DELETE
476
  FROM $table_name
477
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
478
  " );
479
+ $wpdb->query( "
480
+ DELETE
481
+ FROM $table_name
482
+ WHERE `option_name` LIKE ('%sb_wlupdated_%')
483
+ " );
484
+
485
+ //image resizing
486
+ $upload = wp_upload_dir();
487
+ $posts_table_name = $wpdb->prefix . 'sbi_instagram_posts';
488
+ $feeds_posts_table_name = esc_sql( $wpdb->prefix . 'sbi_instagram_feeds_posts' );
489
+
490
+ $image_files = glob( trailingslashit( $upload['basedir'] ) . trailingslashit( 'sb-instagram-feed-images' ) . '*' ); // get all file names
491
+ foreach ( $image_files as $file ) { // iterate files
492
+ if ( is_file( $file ) ) {
493
+ unlink( $file );
494
+ } // delete file
495
+ }
496
 
497
+ global $wp_filesystem;
498
+
499
+ $wp_filesystem->delete( trailingslashit( $upload['basedir'] ) . trailingslashit( 'sb-instagram-feed-images' ) , true );
500
+ //Delete tables
501
+ $wpdb->query( "DROP TABLE IF EXISTS $posts_table_name" );
502
+ $wpdb->query( "DROP TABLE IF EXISTS $feeds_posts_table_name" );
503
+
504
+ $table_name = $wpdb->prefix . "options";
505
+ $wpdb->query( "
506
+ DELETE
507
+ FROM $table_name
508
+ WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
509
+ " );
510
+ $wpdb->query( "
511
+ DELETE
512
+ FROM $table_name
513
+ WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
514
+ " );
515
+ delete_option( 'sbi_hashtag_ids' );
516
+ delete_option( 'sb_instagram_errors' );
517
+
518
+ global $wp_roles;
519
+ $wp_roles->remove_cap( 'administrator', 'manage_instagram_feed_options' );
520
+
521
+ }
522
+
523
+ register_uninstall_hook( __FILE__, 'sb_instagram_uninstall' );
524
+
525
+ /**
526
+ * Create database tables for sub-site if multisite
527
+ *
528
+ * @param int $blog_id
529
+ * @param int $user_id
530
+ * @param string $domain
531
+ * @param string $path
532
+ * @param string $site_id
533
+ * @param array $meta
534
+ *
535
+ * @since 2.0
536
+ */
537
+ function sbi_on_create_blog( $blog_id, $user_id, $domain, $path, $site_id, $meta ) {
538
+ if ( is_plugin_active_for_network( 'instagram-feed/instagram-feed.php' ) ) {
539
+ switch_to_blog( $blog_id );
540
+ sbi_create_database_table();
541
+ restore_current_blog();
542
+ }
543
+ }
544
+
545
+ add_action( 'wpmu_new_blog', 'sbi_on_create_blog', 10, 6 );
546
+
547
+ /**
548
+ * Delete custom tables if not preserving settings
549
+ *
550
+ * @param array $tables tables to drop
551
+ *
552
+ * @return array
553
+ *
554
+ * @since 2.0
555
+ */
556
+ function sbi_on_delete_blog( $tables ) {
557
+ $options = get_option( 'sb_instagram_settings' );
558
+ $sb_instagram_preserve_settings = $options['sb_instagram_preserve_settings'];
559
+ if ( $sb_instagram_preserve_settings ) {
560
+ return;
561
+ }
562
+
563
+ global $wpdb;
564
+ $tables[] = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
565
+ $tables[] = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
566
+
567
+ return $tables;
568
+ }
569
+
570
+ add_filter( 'wpmu_drop_tables', 'sbi_on_delete_blog' );
571
+ }
js/sb-instagram-admin.js CHANGED
@@ -1,14 +1,118 @@
1
  jQuery(document).ready(function($) {
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  var hash = window.location.hash,
4
  token = hash.substring(14),
5
  id = token.split('.')[0];
6
 
7
  if (token.length > 40) {
8
-
9
- //https://api.instagram.com/v1/users/self/?access_token=' . sbi_maybe_clean( $access_token )
10
  $('.sbi_admin_btn').css('opacity','.5').after('<div class="spinner" style="visibility: visible; position: relative;float: left;margin-top: 15px;"></div>');
11
- var url = 'https://api.instagram.com/v1/users/self/?access_token=' + token;
12
  jQuery.ajax({
13
  url: sbiA.ajax_url,
14
  type: 'post',
@@ -86,7 +190,6 @@ jQuery(document).ready(function($) {
86
  }
87
  });
88
 
89
-
90
  function sbiSwitchAccounts(){
91
  $('#sbi_switch_accounts').on('click', function(){
92
  //Log user out of Instagram by hitting the logout URL in an iframe
@@ -127,26 +230,35 @@ jQuery(document).ready(function($) {
127
  $('#sbi_connected_account_'+savedToken.user_id).attr('data-accesstoken',savedToken.access_token);
128
  $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_ca_accesstoken .sbi_ca_token').text(savedToken.access_token);
129
  $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_tooltip code').text('[instagram-feed accesstoken="'+savedToken.access_token+'"]');
130
- $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_ca_at_is_valid span').text('Last Tested: Now');
131
  } else {
 
 
 
 
 
 
 
 
 
132
  var removeOrSaveHTML = saveID ? '<a href="JavaScript:void(0);" class="sbi_remove_from_user_feed button-primary"><i class="fa fa-minus-circle" aria-hidden="true"></i>Remove from Primary Feed</a>' : '<a href="JavaScript:void(0);" class="sbi_use_in_user_feed button-primary"><i class="fa fa-plus-circle" aria-hidden="true"></i>Add to Primary Feed</a>',
133
  statusClass = saveID ? 'sbi_account_active' : 'sbi_account_updated',
134
- html = '<div class="sbi_connected_account '+statusClass+'" id="sbi_connected_account_'+savedToken.user_id+'" data-accesstoken="'+savedToken.access_token+'" data-userid="'+savedToken.user_id+'" data-username="'+savedToken.username+'">'+
135
  '<div class="sbi_ca_info">'+
136
 
137
  '<div class="sbi_ca_delete">'+
138
- '<a href="JavaScript:void(0);" class="sbi_delete_account"><i class="fa fa-times"></i><span class="sbi_remove_text">Remove</span></a>'+
139
  '</div>'+
140
 
141
  '<div class="sbi_ca_username">'+
142
- '<img class="sbi_ca_avatar" src="'+savedToken.profile_picture+'" />'+
143
- '<strong>'+savedToken.username+'</strong>'+
144
  '</div>'+
145
 
146
  '<div class="sbi_ca_actions">'+
147
- removeOrSaveHTML +
148
- '<a class="sbi_ca_token_shortcode button-secondary" href="JavaScript:void(0);"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>Add to another Feed</a>'+
149
- '<p class="sbi_ca_show_token"><input type="checkbox" id="sbi_ca_show_token_'+savedToken.user_id+'" /><label for="sbi_ca_show_token_'+savedToken.user_id+'">Show Access Token</label></p>'+
150
  '</div>'+
151
 
152
  '<div class="sbi_ca_shortcode">'+
@@ -165,6 +277,16 @@ jQuery(document).ready(function($) {
165
  '</div>'+
166
  '</div>';
167
  $('.sbi_connected_accounts_wrap').prepend(html);
 
 
 
 
 
 
 
 
 
 
168
  }
169
  }
170
 
@@ -176,7 +298,8 @@ jQuery(document).ready(function($) {
176
  data: {
177
  action: 'sbi_auto_save_tokens',
178
  access_token: token,
179
- just_tokens: true
 
180
  },
181
  success: function (data) {
182
  var savedToken = JSON.parse(data);
@@ -193,7 +316,8 @@ jQuery(document).ready(function($) {
193
  data: {
194
  action: 'sbi_auto_save_id',
195
  id: ID,
196
- just_tokens: true
 
197
  },
198
  success: function (data) {
199
  }
@@ -201,6 +325,13 @@ jQuery(document).ready(function($) {
201
  }
202
 
203
  // connect accounts
 
 
 
 
 
 
 
204
  $('.sbi_manually_connect_wrap').hide();
205
  $('.sbi_manually_connect').click(function(event) {
206
  event.preventDefault();
@@ -211,95 +342,172 @@ jQuery(document).ready(function($) {
211
  $('#sb_manual_at').focus();
212
  }
213
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  var $body = $('body');
215
- $body.on('click', '.sbi_remove_from_user_feed, .sbi_use_in_user_feed, .sbi_test_token, .sbi_delete_account *, .sbi_ca_token_shortcode', function (event) {
216
  event.preventDefault();
217
  var $clicked = $(event.target),
218
  accessToken = $clicked.closest('.sbi_connected_account').attr('data-accesstoken'),
219
  action = false,
220
  atParts = accessToken.split('.'),
221
- username = $clicked.closest('.sbi_connected_account').attr('data-username');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
- if ($clicked.hasClass('sbi_remove_from_user_feed')) {
224
  $clicked.removeClass('sbi_remove_from_user_feed');
225
  $clicked.addClass('sbi_use_in_user_feed');
226
  $clicked.closest('.sbi_connected_account').removeClass('sbi_account_active');
227
  $clicked.html('<i class="fa fa-plus-circle" aria-hidden="true"></i>Add to Primary Feed');
228
- $('#sbi_user_feed_id_'+atParts[0]).remove();
229
- } else if ($clicked.hasClass('sbi_use_in_user_feed')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  $clicked.removeClass('sbi_use_in_user_feed');
231
  $clicked.addClass('sbi_remove_from_user_feed');
232
  $clicked.closest('.sbi_connected_account').removeClass('sbi_account_updated');
233
  $clicked.closest('.sbi_connected_account').addClass('sbi_account_active');
234
  $clicked.html('<i class="fa fa-minus-circle" aria-hidden="true" style="margin-right: 5px;"></i>Remove from Primary Feed');
235
- var name = '<strong>'+atParts[0]+'</strong>';
236
  if (username !== '') {
237
- name = '<strong>'+username+'</strong> <span>('+atParts[0]+')</span>';
238
  }
239
  $('.sbi_user_feed_ids_wrap').prepend(
240
- '<div id="sbi_user_feed_id_'+atParts[0]+'" class="sbi_user_feed_account_wrap">'+
241
  name +
242
- '<input type="hidden" name="sb_instagram_user_id[]" value="'+atParts[0]+'">' +
243
  '</div>'
244
  );
245
- } else if ($clicked.parent().hasClass('sbi_delete_account')) {
246
- if (window.confirm("Delete this connected account?")) {
247
- action = 'sbi_delete_account';
248
- $('#sbi_user_feed_id_' + atParts[0] + ',#sbi_connected_account_' + atParts[0]).remove();
249
- jQuery.ajax({
250
- url: sbiA.ajax_url,
251
- type: 'post',
252
- data: {
253
- action: action,
254
- access_token: accessToken
255
- },
256
- success: function (data) {
257
- console.log(data);
258
- }
259
- });
260
  }
261
- } else if ($clicked.hasClass('sbi_ca_token_shortcode')) {
262
- jQuery(this).closest('.sbi_ca_info').find('.sbi_ca_shortcode').slideToggle(200);
263
- } //
264
 
265
- });
266
 
267
  $body.on('change', '.sbi_ca_show_token input[type=checkbox]', function(event) {
268
  jQuery(this).closest('.sbi_ca_info').find('.sbi_ca_accesstoken').slideToggle(200);
269
  });
270
 
271
-
272
- //If there's a hash then autofill the token and id
273
- /*
274
- if(hash && !jQuery('#sbi_just_saved').length){
275
- //$('#sbi_config').append('<div id="sbi_config_info"><p><b>Access Token: </b><input type="text" size=58 readonly value="'+token+'" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)."></p><p><b>User ID: </b><input type="text" size=12 readonly value="'+id+'" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)."></p><p><i class="fa fa-clipboard" aria-hidden="true"></i>&nbsp; <b><span style="color: red;">Important:</span> Copy and paste</b> these into the fields below and click <b>"Save Changes"</b>.</p></div>');
276
- $('#sbi_config').append('<div id="sbi_config_info"><p class="sb_get_token"><b>Access Token: </b><input type="text" size=58 readonly value="'+token+'" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)."></p><p><b>User ID: </b><input type="text" size=12 readonly value="'+id+'" onclick="this.focus();this.select()" title="To copy, click the field then press Ctrl + C (PC) or Cmd + C (Mac)."></p></div>');
277
- if(jQuery('#sb_instagram_at').val() == '' && token.length > 40) {
278
- jQuery('#sb_instagram_at').val(token);
279
- sbSaveToken(token);
280
- } else {
281
- jQuery('.sb_get_token').append('<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Connect This Account"></p>');
282
- }
283
-
284
- }
285
-
286
- $('.sb_get_token #submit').click(function(event) {
287
- event.preventDefault();
288
- $(this).closest('.submit').fadeOut();
289
- jQuery('#sb_instagram_at').val(token);
290
- sbSaveToken(token);
291
- });
292
- */
293
-
294
  $('#sbi_manual_submit').click(function(event) {
295
  event.preventDefault();
296
  var $self = $(this);
297
- var accessToken = $('#sb_manual_at').val();
 
 
 
 
 
 
 
 
 
298
  if (accessToken.length < 15) {
299
  if (!$('.sbi_manually_connect_wrap').find('.sbi_user_id_error').length) {
300
  $('.sbi_manually_connect_wrap').show().prepend('<div class="sbi_user_id_error" style="display:block;">Please enter a valid access token</div>');
301
  }
302
- } else {
303
  $(this).attr('disabled',true);
304
  $(this).closest('.sbi_manually_connect_wrap').fadeOut();
305
  $('.sbi_connected_accounts_wrap').fadeTo("slow" , 0.5).find('.sbi_user_id_error').remove();
@@ -309,16 +517,23 @@ jQuery(document).ready(function($) {
309
  type: 'post',
310
  data: {
311
  action: 'sbi_test_token',
312
- access_token: accessToken
 
 
313
  },
314
  success: function (data) {
315
  $('.sbi_connected_accounts_wrap').fadeTo("slow" , 1);
316
  $self.removeAttr('disabled');
317
  if ( data.indexOf('{') > -1) {
318
  var savedToken = JSON.parse(data);
319
- $(this).closest('.sbi_manually_connect_wrap').fadeOut();
320
- $('#sb_manual_at').val('');
321
- sbiAfterUpdateToken(savedToken,false);
 
 
 
 
 
322
  } else {
323
  $('.sbi_manually_connect_wrap').show().prepend('<div class="sbi_user_id_error" style="display:block;">'+data+'</div>');
324
  }
@@ -329,6 +544,79 @@ jQuery(document).ready(function($) {
329
 
330
  });
331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  //clear backup caches
333
  jQuery('#sbi_clear_backups').click(function(event) {
334
  jQuery('.sbi-success').remove();
@@ -347,11 +635,41 @@ jQuery(document).ready(function($) {
347
  }
348
  });
349
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
  //Tooltips
352
- jQuery('#sbi_admin .sbi_tooltip_link').click(function(){
353
- jQuery(this).siblings('.sbi_tooltip').slideToggle();
354
- });
 
 
 
 
355
 
356
  //Shortcode labels
357
  jQuery('#sbi_admin label').click(function(){
@@ -509,4 +827,39 @@ jQuery(document).ready(function($) {
509
  $self.siblings().removeClass('sbi_layout_selected');
510
  });
511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  });
1
  jQuery(document).ready(function($) {
2
 
3
+ /* NEW API CODE */
4
+ $('.sbi_admin_btn').click(function(event) {
5
+ event.preventDefault();
6
+ var oldApiURL = $(this).attr('data-old-api'),
7
+ newApiURL = $(this).attr('data-new-api');
8
+ $('#sbi_config').append('<div id="sbi_config_info" class="sb_get_token">' +
9
+ '<div class="sbi_config_modal">' +
10
+ '<p>Are you connecting a Personal or Business Instagram Profile?</p>' +
11
+
12
+ '<div class="sbi_login_button_row">' +
13
+ '<input type="radio" id="sbi_personal_login" name="sbi_login_type" value="personal" checked>' +
14
+ '<label for="sbi_personal_login"><b>Personal</b></label>&nbsp;<a href="JavaScript:void(0);" class="sbi_tooltip_link"><i class="fa fa-question-circle"></i></a><div class="sbi_tooltip">Select this to connect a Personal Instagram profile. This option can also be used to connect a Business profile too if needed.</div>' +
15
+ '</div>' +
16
+ '<div class="sbi_login_button_row">' +
17
+ '<input type="radio" id="sbi_business_login" name="sbi_login_type" value="business">' +
18
+ '<label for="sbi_business_login"><b>Business</b> </label><a href="JavaScript:void(0);" class="sbi_tooltip_link"><i class="fa fa-question-circle"></i></a><div class="sbi_tooltip">Select this to connect a Business Instagram profile. If you have trouble using this method then try using the "Personal" option above. If you wish to convert your Personal profile into a Business profile then follow the directions <a href="https://smashballoon.com/instagram-business-profiles" target="_blank">here</a>.</div>' +
19
+ '</div>' +
20
+ '<div class="sbi_login_button_row">' +
21
+ '<a href="JavaScript:void(0);" class="sbi_tooltip_link" style="margin-left: 0; font-size: 12px;">I\'m not sure</a><div class="sbi_tooltip">If you are unsure then select the "Personal" option, as this can be used to connect both Personal and Business profiles.</div>' +
22
+ '</div>' +
23
+
24
+ '<a href="'+oldApiURL+'" class="sbi_admin_btn">Connect</a>' +
25
+ '<a href="JavaScript:void(0);"><i class="sbi_modal_close fa fa-times"></i></a>' +
26
+ '</div>' +
27
+ '</div>');
28
+
29
+ $('.sbi_modal_close').on('click', function(){
30
+ $('#sbi_config_info').remove();
31
+ });
32
+
33
+ $('input[name=sbi_login_type]').change(function() {
34
+ if ($('input[name=sbi_login_type]:checked').val() === 'business') {
35
+ $('a.sbi_admin_btn').attr('href',newApiURL);
36
+ } else {
37
+ $('a.sbi_admin_btn').attr('href',oldApiURL);
38
+ }
39
+ });
40
+ });
41
+
42
+ if ($('.sbi_config_modal .sbi-managed-pages').length) {
43
+ $('#sbi_config').append($('#sbi_config_info'));
44
+ }
45
+
46
+ $('#sbi-select-all').change(function() {
47
+ var status = $(this).is(':checked');
48
+ $('.sbi-add-checkbox input').each(function() {
49
+ $(this).attr('checked',status);
50
+ });
51
+ if($('.sbi-add-checkbox input:checked').length) {
52
+ $('#sbi-connect-business-accounts').removeAttr('disabled');
53
+ } else {
54
+ $('#sbi-connect-business-accounts').attr('disabled',true);
55
+ }
56
+ });
57
+
58
+ $('.sbi-add-checkbox input').change(function() {
59
+ if($('.sbi-add-checkbox input:checked').length) {
60
+ $('#sbi-connect-business-accounts').removeAttr('disabled');
61
+ } else {
62
+ $('#sbi-connect-business-accounts').attr('disabled',true);
63
+ }
64
+ });
65
+
66
+ $('#sbi-connect-business-accounts').click(function(event) {
67
+ if(typeof $(this).attr('disabled') === 'undefined') {
68
+ event.preventDefault();
69
+ var accounts = {};
70
+ $('.sbi-add-checkbox input').each(function(index) {
71
+ if ($(this).is(':checked')) {
72
+ var jsonSubmit = JSON.parse($(this).val());
73
+ jsonSubmit.access_token = $(this).closest('.sbi-managed-page').attr('data-token');
74
+ jsonSubmit.page_access_token = $(this).closest('.sbi-managed-page').attr('data-page-token');
75
+ accounts[index] = jsonSubmit;
76
+ }
77
+ });
78
+
79
+ $('.sbi_connected_accounts_wrap,#sbi_config_info').fadeTo("slow" , 0.5);
80
+ jQuery.ajax({
81
+ url: sbiA.ajax_url,
82
+ type: 'post',
83
+ data: {
84
+ action: 'sbi_connect_business_accounts',
85
+ accounts: JSON.stringify(accounts),
86
+ sbi_nonce: sbiA.sbi_nonce
87
+ },
88
+ success: function (data) {
89
+ if (data.trim().indexOf('{') === 0) {
90
+ var connectedAccounts = JSON.parse(data);
91
+ $('.sbi_connected_accounts_wrap').fadeTo("slow" , 1);
92
+ $('#sbi_config_info').remove();
93
+ $.each(connectedAccounts,function(index,savedToken) {
94
+ sbiAfterUpdateToken(savedToken,false);
95
+
96
+ });
97
+ }
98
+
99
+ }
100
+ });
101
+ }
102
+
103
+ });
104
+
105
+ $('.sbi_modal_close').on('click', function(){
106
+ $('#sbi_config_info').remove();
107
+ });
108
+ /* NEW API CODE */
109
+ //Autofill the token and id
110
  var hash = window.location.hash,
111
  token = hash.substring(14),
112
  id = token.split('.')[0];
113
 
114
  if (token.length > 40) {
 
 
115
  $('.sbi_admin_btn').css('opacity','.5').after('<div class="spinner" style="visibility: visible; position: relative;float: left;margin-top: 15px;"></div>');
 
116
  jQuery.ajax({
117
  url: sbiA.ajax_url,
118
  type: 'post',
190
  }
191
  });
192
 
 
193
  function sbiSwitchAccounts(){
194
  $('#sbi_switch_accounts').on('click', function(){
195
  //Log user out of Instagram by hitting the logout URL in an iframe
230
  $('#sbi_connected_account_'+savedToken.user_id).attr('data-accesstoken',savedToken.access_token);
231
  $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_ca_accesstoken .sbi_ca_token').text(savedToken.access_token);
232
  $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_tooltip code').text('[instagram-feed accesstoken="'+savedToken.access_token+'"]');
233
+ $('#sbi_connected_account_'+savedToken.user_id).find('.sbi_ca_alert').remove();
234
  } else {
235
+ //Check which kind of account it is
236
+ if(typeof savedToken.type !== 'undefined'){
237
+ var accountType = savedToken.type;
238
+ $('.sbi_hashtag_feed_issue').removeClass('sbi_hashtag_feed_issue').find('.sbi_hashtag_feed_issue_note').hide();
239
+ } else {
240
+ var accountType = 'personal';
241
+ }
242
+
243
+ //Add the account HTML to the page
244
  var removeOrSaveHTML = saveID ? '<a href="JavaScript:void(0);" class="sbi_remove_from_user_feed button-primary"><i class="fa fa-minus-circle" aria-hidden="true"></i>Remove from Primary Feed</a>' : '<a href="JavaScript:void(0);" class="sbi_use_in_user_feed button-primary"><i class="fa fa-plus-circle" aria-hidden="true"></i>Add to Primary Feed</a>',
245
  statusClass = saveID ? 'sbi_account_active' : 'sbi_account_updated',
246
+ html = '<div class="sbi_connected_account '+statusClass+' sbi-init-click-remove" id="sbi_connected_account_'+savedToken.user_id+'" data-accesstoken="'+savedToken.access_token+'" data-userid="'+savedToken.user_id+'" data-username="'+savedToken.username+'">'+
247
  '<div class="sbi_ca_info">'+
248
 
249
  '<div class="sbi_ca_delete">'+
250
+ '<a href="JavaScript:void(0);" class="sbi_delete_account"><i class="fa fa-times"></i><span class="sbi_remove_text">Remove</span></a>'+
251
  '</div>'+
252
 
253
  '<div class="sbi_ca_username">'+
254
+ '<img class="sbi_ca_avatar" src="'+savedToken.profile_picture+'" />'+
255
+ '<strong>'+savedToken.username+'<span>'+accountType+'</span></strong>'+
256
  '</div>'+
257
 
258
  '<div class="sbi_ca_actions">'+
259
+ removeOrSaveHTML +
260
+ '<a class="sbi_ca_token_shortcode button-secondary" href="JavaScript:void(0);"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>Add to another Feed</a>'+
261
+ '<p class="sbi_ca_show_token"><input type="checkbox" id="sbi_ca_show_token_'+savedToken.user_id+'" /><label for="sbi_ca_show_token_'+savedToken.user_id+'">Show Access Token</label></p>'+
262
  '</div>'+
263
 
264
  '<div class="sbi_ca_shortcode">'+
277
  '</div>'+
278
  '</div>';
279
  $('.sbi_connected_accounts_wrap').prepend(html);
280
+ var $clickRemove = $('.sbi-init-click-remove');
281
+ sbiInitClickRemove($clickRemove.find('.sbi_delete_account'));
282
+ if ($clickRemove.find('.sbi_remove_from_user_feed').length ) {
283
+ $clickRemove.find('.sbi_remove_from_user_feed').off();
284
+ sbiInitUserRemove($clickRemove.find('.sbi_remove_from_user_feed'));
285
+ } else {
286
+ $clickRemove.find('.sbi_use_in_user_feed').off();
287
+ sbiInitUserAdd($clickRemove.find('.sbi_use_in_user_feed'));
288
+ }
289
+ $clickRemove.removeClass('sbi-init-click-remove');
290
  }
291
  }
292
 
298
  data: {
299
  action: 'sbi_auto_save_tokens',
300
  access_token: token,
301
+ just_tokens: true,
302
+ sbi_nonce: sbiA.sbi_nonce
303
  },
304
  success: function (data) {
305
  var savedToken = JSON.parse(data);
316
  data: {
317
  action: 'sbi_auto_save_id',
318
  id: ID,
319
+ just_tokens: true,
320
+ sbi_nonce: sbiA.sbi_nonce
321
  },
322
  success: function (data) {
323
  }
325
  }
326
 
327
  // connect accounts
328
+ //sbi-bus-account-error
329
+ if (window.location.hash && window.location.hash === '#test') {
330
+ window.location.hash = '';
331
+ $('#sbi-bus-account-error').html('<p style="margin-top: 5px;"><b style="font-size: 16px">Couldn\'t connect an account with this access token</b><br />' +
332
+ 'Please check to make sure that the token you entered is correct.</p>')
333
+ }
334
+
335
  $('.sbi_manually_connect_wrap').hide();
336
  $('.sbi_manually_connect').click(function(event) {
337
  event.preventDefault();
342
  $('#sb_manual_at').focus();
343
  }
344
  });
345
+
346
+ $('#sb_manual_at').on('input',function() {
347
+ sbiToggleManualAccountIDInput();
348
+ });
349
+ if ($('#sb_manual_at').length){
350
+ sbiToggleManualAccountIDInput();
351
+ }
352
+
353
+ function sbiIsBusinessToken() {
354
+ return ($('#sb_manual_at').val().trim().length > 150);
355
+ }
356
+
357
+ function sbiToggleManualAccountIDInput() {
358
+ if (sbiIsBusinessToken()) {
359
+ $('.sbi_manual_account_id_toggle').slideDown();
360
+ $('.sbi_business_profile_tag').css('display', 'inline-block');
361
+ } else {
362
+ $('.sbi_manual_account_id_toggle').slideUp();
363
+ }
364
+ }
365
+
366
  var $body = $('body');
367
+ $body.on('click', '.sbi_test_token, .sbi_ca_token_shortcode', function (event) {
368
  event.preventDefault();
369
  var $clicked = $(event.target),
370
  accessToken = $clicked.closest('.sbi_connected_account').attr('data-accesstoken'),
371
  action = false,
372
  atParts = accessToken.split('.'),
373
+ username = $clicked.closest('.sbi_connected_account').attr('data-username'),
374
+ accountID = $clicked.closest('.sbi_connected_account').attr('data-userid');
375
+ if ($clicked.hasClass('sbi_ca_token_shortcode')) {
376
+ jQuery(this).closest('.sbi_ca_info').find('.sbi_ca_shortcode').slideToggle(200);
377
+ } //
378
+
379
+ });
380
+
381
+ $('.sbi_delete_account').each(function() {
382
+ sbiInitClickRemove($(this));
383
+ });
384
+
385
+ function sbiInitClickRemove(el) {
386
+ el.click(function() {
387
+ if (!$(this).closest('.sbi_connected_accounts_wrap').hasClass('sbi-waiting')) {
388
+ $(this).closest('.sbi_connected_accounts_wrap').addClass('sbi-waiting');
389
+ var accessToken = $(this).closest('.sbi_connected_account').attr('data-accesstoken'),
390
+ action = false,
391
+ atParts = accessToken.split('.'),
392
+ username = $(this).closest('.sbi_connected_account').attr('data-username'),
393
+ accountID = $(this).closest('.sbi_connected_account').attr('data-userid');
394
+
395
+ if (window.confirm("Delete this connected account?")) {
396
+ action = 'sbi_delete_account';
397
+ $('#sbi_user_feed_id_' + accountID).remove();
398
+ $('#sbi_connected_account_' + accountID).append('<div class="spinner" style="margin-top: -10px;visibility: visible;top: 50%;position: absolute;right: 50%;"></div>').find('.sbi_ca_info').css('opacity','.5');
399
+
400
+ jQuery.ajax({
401
+ url: sbiA.ajax_url,
402
+ type: 'post',
403
+ data: {
404
+ action: action,
405
+ account_id: accountID,
406
+ sbi_nonce: sbiA.sbi_nonce
407
+ },
408
+ success: function (data) {
409
+ $('.sbi-waiting').removeClass('sbi-waiting');
410
+ $('#sbi_connected_account_' + accountID).fadeOut(300, function() { $(this).remove(); });
411
+ }
412
+ });
413
+ } else {
414
+ $('.sbi-waiting').removeClass('sbi-waiting');
415
+ }
416
+ }
417
+
418
+ });
419
+ }
420
+
421
+ $('.sbi_remove_from_user_feed').each(function() {
422
+ sbiInitUserRemove($(this));
423
+ });
424
+
425
+ function sbiInitUserRemove(el) {
426
+ el.click(function(event) {
427
+ event.preventDefault();
428
+ var $clicked = $(this),
429
+ $closest = $clicked.closest('.sbi_connected_account'),
430
+ username = $clicked.closest('.sbi_connected_account').attr('data-username'),
431
+ accountID = $clicked.closest('.sbi_connected_account').attr('data-userid');
432
 
 
433
  $clicked.removeClass('sbi_remove_from_user_feed');
434
  $clicked.addClass('sbi_use_in_user_feed');
435
  $clicked.closest('.sbi_connected_account').removeClass('sbi_account_active');
436
  $clicked.html('<i class="fa fa-plus-circle" aria-hidden="true"></i>Add to Primary Feed');
437
+ $('#sbi_user_feed_id_'+accountID).remove();
438
+ if ($closest.find('.sbi_remove_from_user_feed').length ) {
439
+ $closest.find('.sbi_remove_from_user_feed').off();
440
+ sbiInitUserRemove($closest.find('.sbi_remove_from_user_feed'));
441
+ } else {
442
+ $closest.find('.sbi_use_in_user_feed').off();
443
+ sbiInitUserAdd($closest.find('.sbi_use_in_user_feed'));
444
+ }
445
+ });
446
+ }
447
+
448
+
449
+
450
+ $('.sbi_use_in_user_feed').each(function() {
451
+ sbiInitUserAdd($(this));
452
+ });
453
+
454
+ function sbiInitUserAdd(el) {
455
+ el.click(function(event) {
456
+ event.preventDefault();
457
+ var $clicked = $(this),
458
+ $closest = $clicked.closest('.sbi_connected_account'),
459
+ username = $clicked.closest('.sbi_connected_account').attr('data-username'),
460
+ accountID = $clicked.closest('.sbi_connected_account').attr('data-userid');
461
+
462
  $clicked.removeClass('sbi_use_in_user_feed');
463
  $clicked.addClass('sbi_remove_from_user_feed');
464
  $clicked.closest('.sbi_connected_account').removeClass('sbi_account_updated');
465
  $clicked.closest('.sbi_connected_account').addClass('sbi_account_active');
466
  $clicked.html('<i class="fa fa-minus-circle" aria-hidden="true" style="margin-right: 5px;"></i>Remove from Primary Feed');
467
+ var name = '<strong>'+accountID+'</strong>';
468
  if (username !== '') {
469
+ name = '<strong>'+username+'</strong> <span>('+accountID+')</span>';
470
  }
471
  $('.sbi_user_feed_ids_wrap').prepend(
472
+ '<div id="sbi_user_feed_id_'+accountID+'" class="sbi_user_feed_account_wrap">'+
473
  name +
474
+ '<input type="hidden" name="sb_instagram_user_id[]" value="'+accountID+'">' +
475
  '</div>'
476
  );
477
+ $('.sbi_no_accounts').hide();
478
+ if ($closest.find('.sbi_remove_from_user_feed').length ) {
479
+ $closest.find('.sbi_remove_from_user_feed').off();
480
+ sbiInitUserRemove($closest.find('.sbi_remove_from_user_feed'));
481
+ } else {
482
+ $closest.find('.sbi_use_in_user_feed').off();
483
+ sbiInitUserAdd($closest.find('.sbi_use_in_user_feed'));
 
 
 
 
 
 
 
 
484
  }
485
+ });
486
+ }
 
487
 
 
488
 
489
  $body.on('change', '.sbi_ca_show_token input[type=checkbox]', function(event) {
490
  jQuery(this).closest('.sbi_ca_info').find('.sbi_ca_accesstoken').slideToggle(200);
491
  });
492
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  $('#sbi_manual_submit').click(function(event) {
494
  event.preventDefault();
495
  var $self = $(this);
496
+ var accessToken = $('#sb_manual_at').val(),
497
+ error = false;
498
+ if (sbiIsBusinessToken() && $('.sbi_manual_account_id_toggle').find('input').val().length < 3) {
499
+ error = true;
500
+ if (!$('.sbi_manually_connect_wrap').find('.sbi_user_id_error').length) {
501
+ $('.sbi_manually_connect_wrap').show().prepend('<div class="sbi_user_id_error" style="display:block;">Please enter a valid User ID for this Business account.</div>');
502
+ }
503
+ } else {
504
+ error = false;
505
+ }
506
  if (accessToken.length < 15) {
507
  if (!$('.sbi_manually_connect_wrap').find('.sbi_user_id_error').length) {
508
  $('.sbi_manually_connect_wrap').show().prepend('<div class="sbi_user_id_error" style="display:block;">Please enter a valid access token</div>');
509
  }
510
+ } else if (! error) {
511
  $(this).attr('disabled',true);
512
  $(this).closest('.sbi_manually_connect_wrap').fadeOut();
513
  $('.sbi_connected_accounts_wrap').fadeTo("slow" , 0.5).find('.sbi_user_id_error').remove();
517
  type: 'post',
518
  data: {
519
  action: 'sbi_test_token',
520
+ access_token: accessToken,
521
+ account_id : $('.sbi_manual_account_id_toggle').find('input').val().trim(),
522
+ sbi_nonce: sbiA.sbi_nonce
523
  },
524
  success: function (data) {
525
  $('.sbi_connected_accounts_wrap').fadeTo("slow" , 1);
526
  $self.removeAttr('disabled');
527
  if ( data.indexOf('{') > -1) {
528
  var savedToken = JSON.parse(data);
529
+ if (typeof savedToken.url !== 'undefined') {
530
+ window.location.href = savedToken.url;
531
+ } else {
532
+ $(this).closest('.sbi_manually_connect_wrap').fadeOut();
533
+ $('#sb_manual_at, .sbi_manual_account_id_toggle input').val('');
534
+ sbiAfterUpdateToken(savedToken,false);
535
+ }
536
+
537
  } else {
538
  $('.sbi_manually_connect_wrap').show().prepend('<div class="sbi_user_id_error" style="display:block;">'+data+'</div>');
539
  }
544
 
545
  });
546
 
547
+ //sbi_reset_resized
548
+ // clear resized
549
+ var $sbiClearResizedButton = $('#sbi_reset_resized');
550
+
551
+ $sbiClearResizedButton.click(function(event) {
552
+ event.preventDefault();
553
+
554
+ jQuery('#sbi-clear-cache-success').remove();
555
+ jQuery(this).prop("disabled",true);
556
+
557
+ $.ajax({
558
+ url : sbiA.ajax_url,
559
+ type : 'post',
560
+ data : {
561
+ action : 'sbi_reset_resized'
562
+ },
563
+ success : function(data) {
564
+ $sbiClearResizedButton.prop('disabled',false);
565
+ if(data=='1') {
566
+ $sbiClearResizedButton.after('<i id="sbi-clear-cache-success" class="fa fa-check-circle sbi-success"></i>');
567
+ } else {
568
+ $sbiClearResizedButton.after('<span>error</span>');
569
+ }
570
+ }
571
+ }); // ajax call
572
+ }); // clear_comment_cache click
573
+
574
+ //Caching options
575
+ if( jQuery('#sbi_caching_type_page').is(':checked') ) {
576
+ jQuery('.sbi-caching-cron-options').hide();
577
+ jQuery('.sbi-caching-page-options').show();
578
+ } else {
579
+ jQuery('.sbi-caching-page-options').hide();
580
+ jQuery('.sbi-caching-cron-options').show();
581
+ }
582
+
583
+ $('input[type=radio][name=sbi_caching_type]').change(function() {
584
+ if (this.value == 'page') {
585
+ jQuery('.sbi-caching-cron-options').slideUp();
586
+ jQuery('.sbi-caching-page-options').slideDown();
587
+ }
588
+ else if (this.value == 'background') {
589
+ jQuery('.sbi-caching-page-options').slideUp();
590
+ jQuery('.sbi-caching-cron-options').slideDown();
591
+ }
592
+ });
593
+
594
+
595
+ //Should we show the caching time settings?
596
+ var sbi_cache_cron_interval = jQuery('#sbi_cache_cron_interval').val(),
597
+ $sbi_caching_time_settings = jQuery('#sbi-caching-time-settings');
598
+
599
+ //Should we show anything initially?
600
+ if(sbi_cache_cron_interval == '30mins' || sbi_cache_cron_interval == '1hour') $sbi_caching_time_settings.hide();
601
+
602
+ jQuery('#sbi_cache_cron_interval').change(function(){
603
+ sbi_cache_cron_interval = jQuery('#sbi_cache_cron_interval').val();
604
+
605
+ if(sbi_cache_cron_interval == '30mins' || sbi_cache_cron_interval == '1hour'){
606
+ $sbi_caching_time_settings.hide();
607
+ } else {
608
+ $sbi_caching_time_settings.show();
609
+ }
610
+ });
611
+ sbi_cache_cron_interval = jQuery('#sbi_cache_cron_interval').val();
612
+
613
+ if(sbi_cache_cron_interval == '30mins' || sbi_cache_cron_interval == '1hour'){
614
+ $sbi_caching_time_settings.hide();
615
+ } else {
616
+ $sbi_caching_time_settings.show();
617
+ }
618
+
619
+
620
  //clear backup caches
621
  jQuery('#sbi_clear_backups').click(function(event) {
622
  jQuery('.sbi-success').remove();
635
  }
636
  });
637
  });
638
+
639
+ //sbi_reset_log
640
+ var $sbiClearLog = $('#sbi_reset_log');
641
+
642
+ $sbiClearLog.click(function(event) {
643
+ event.preventDefault();
644
+
645
+ jQuery('#sbi-clear-cache-success').remove();
646
+ jQuery(this).prop("disabled",true);
647
+
648
+ $.ajax({
649
+ url : sbiA.ajax_url,
650
+ type : 'post',
651
+ data : {
652
+ action : 'sbi_reset_log'
653
+ },
654
+ success : function(data) {
655
+ $sbiClearLog.prop('disabled',false);
656
+ if(data=='1') {
657
+ $sbiClearLog.after('<i id="sbi-clear-cache-success" class="fa fa-check-circle sbi-success"></i>');
658
+ } else {
659
+ $sbiClearLog.after('<span>error</span>');
660
+ }
661
+ }
662
+ }); // ajax call
663
+ }); // clear_comment_cache click
664
 
665
  //Tooltips
666
+ jQuery('#sbi_admin').on('click', '.sbi_tooltip_link, .sbi_type_tooltip_link', function(){
667
+ if( jQuery(this).hasClass('sbi_type_tooltip_link') ){
668
+ jQuery(this).closest('.sbi_row').children('.sbi_tooltip').slideToggle();
669
+ } else {
670
+ jQuery(this).siblings('.sbi_tooltip').slideToggle();
671
+ }
672
+ });
673
 
674
  //Shortcode labels
675
  jQuery('#sbi_admin label').click(function(){
827
  $self.siblings().removeClass('sbi_layout_selected');
828
  });
829
 
830
+ setTimeout( function() {
831
+ jQuery('.notice-dismiss').click(function() {
832
+ if (jQuery(this).closest('.sbi-admin-notice').length) {
833
+
834
+ if (jQuery(this).closest('.sbi-admin-notice').find('.sbi-admin-error').length) {
835
+
836
+ var exemptErrorType = jQuery(this).closest('.sbi-admin-notice').find('.sbi-admin-error').attr('data-sbi-type');
837
+
838
+ if (exemptErrorType === 'ajax') {
839
+ jQuery.ajax({
840
+ url: sbiA.ajax_url,
841
+ type: 'post',
842
+ data: {
843
+ action : 'sbi_on_ajax_test_trigger',
844
+ sbi_nonce: sbiA.sbi_nonce
845
+ },
846
+ success: function (data) {
847
+ }
848
+ });
849
+ }
850
+ }
851
+ }
852
+ });
853
+ },1500);
854
+
855
+ //Load the admin share widgets
856
+ jQuery('#sbi_admin_show_share_links').on('click', function(){
857
+ jQuery(this).fadeOut();
858
+ if( jQuery('#sbi_admin_share_links iframe').length == 0 ) jQuery('#sbi_admin_share_links').html('<a href="https://twitter.com/share" class="twitter-share-button" data-url="https://wordpress.org/plugins/instagram-feed/" data-text="Display beautifully clean, customizable, and responsive Instagram feeds from multiple accounts" data-via="smashballoon" data-dnt="true">Tweet</a> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?"http":"https";if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document, "script", "twitter-wjs");</script> <style type="text/css"> #twitter-widget-0{float: left; width: 82px !important;}.IN-widget{margin-right: 20px;}</style> <div id="fb-root" style="display: none;"></div><script>(function(d, s, id){var js, fjs=d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js=d.createElement(s); js.id=id; js.src="//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.0"; fjs.parentNode.insertBefore(js, fjs);}(document, "script", "facebook-jssdk"));</script> <div class="fb-like" data-href="https://wordpress.org/plugins/instagram-feed/" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true" style="display: block; float: left; margin-right: 5px;"></div><script src="//platform.linkedin.com/in.js" type="text/javascript"> lang: en_US </script> <script type="IN/Share" data-url="https://wordpress.org/plugins/instagram-feed/"></script></div>');
859
+
860
+ setTimeout(function(){
861
+ jQuery('#sbi_admin_share_links').addClass('sbi_show');
862
+ }, 500);
863
+ });
864
+
865
  });
js/sb-instagram.js CHANGED
@@ -1,1406 +1,840 @@
1
  var sbi_js_exists = (typeof sbi_js_exists !== 'undefined') ? true : false;
2
- if(!sbi_js_exists){
3
-
4
- //Shim for "fixing" IE's lack of support (IE < 9) for applying slice on host objects like NamedNodeMap, NodeList, and HTMLCollection) https://github.com/stevenschobert/instafeed.js/issues/84
5
- (function(){"use strict";var e=Array.prototype.slice;try{e.call(document.documentElement)}catch(t){Array.prototype.slice=function(t,n){n=typeof n!=="undefined"?n:this.length;if(Object.prototype.toString.call(this)==="[object Array]"){return e.call(this,t,n)}var r,i=[],s,o=this.length;var u=t||0;u=u>=0?u:o+u;var a=n?n:o;if(n<0){a=o+n}s=a-u;if(s>0){i=new Array(s);if(this.charAt){for(r=0;r<s;r++){i[r]=this.charAt(u+r)}}else{for(r=0;r<s;r++){i[r]=this[u+r]}}}return i}}})()
6
-
7
- //IE8 also doesn't offer the .bind() method triggered by the 'sortBy' property. Copy and paste the polyfill offered here:
8
- if(!Function.prototype.bind){Function.prototype.bind=function(e){if(typeof this!=="function"){throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable")}var t=Array.prototype.slice.call(arguments,1),n=this,r=function(){},i=function(){return n.apply(this instanceof r&&e?this:e,t.concat(Array.prototype.slice.call(arguments)))};r.prototype=this.prototype;i.prototype=new r;return i}}
9
-
10
- /* Font Awesome SVG implementation */
11
- var sbIconSVG = {
12
- 'fa-clock' : 'class="svg-inline--fa fa-clock fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="clock" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z"></path></svg>',
13
- 'fa-play' : 'class="svg-inline--fa fa-play fa-w-14 sbi_playbtn" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="play" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"></path></svg>',
14
- 'fa-image' : 'class="svg-inline--fa fa-image fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="image" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>',
15
- 'fa-user' : 'class="svg-inline--fa fa-user fa-w-16" style="margin-right: 3px;" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="user" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M96 160C96 71.634 167.635 0 256 0s160 71.634 160 160-71.635 160-160 160S96 248.366 96 160zm304 192h-28.556c-71.006 42.713-159.912 42.695-230.888 0H112C50.144 352 0 402.144 0 464v24c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24v-24c0-61.856-50.144-112-112-112z"></path></svg>',
16
- 'fa-comment' : 'class="svg-inline--fa fa-comment fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="comment" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M576 240c0 115-129 208-288 208-48.3 0-93.9-8.6-133.9-23.8-40.3 31.2-89.8 50.3-142.4 55.7-5.2.6-10.2-2.8-11.5-7.7-1.3-5 2.7-8.1 6.6-11.8 19.3-18.4 42.7-32.8 51.9-94.6C21.9 330.9 0 287.3 0 240 0 125.1 129 32 288 32s288 93.1 288 208z"></path></svg>',
17
- 'fa-heart' : 'class="svg-inline--fa fa-heart fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="heart" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M414.9 24C361.8 24 312 65.7 288 89.3 264 65.7 214.2 24 161.1 24 70.3 24 16 76.9 16 165.5c0 72.6 66.8 133.3 69.2 135.4l187 180.8c8.8 8.5 22.8 8.5 31.6 0l186.7-180.2c2.7-2.7 69.5-63.5 69.5-136C560 76.9 505.7 24 414.9 24z"></path></svg>',
18
- 'fa-check' : 'class="svg-inline--fa fa-check fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="check" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"></path></svg>',
19
- 'fa-exclamation-circle' : 'class="svg-inline--fa fa-exclamation-circle fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="exclamation-circle" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>',
20
- 'fa-map-marker' : 'class="svg-inline--fa fa-map-marker fa-w-12" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="map-marker" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path></svg>',
21
- 'fa-clone' : 'class="svg-inline--fa fa-clone fa-w-16 sbi_lightbox_carousel_icon" aria-hidden="true" data-fa-proƒcessed="" data-prefix="far" data-icon="clone" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path></svg>',
22
- 'fa-chevron-right' : 'class="svg-inline--fa fa-chevron-right fa-w-10" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="chevron-right" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>',
23
- 'fa-chevron-left' : 'class="svg-inline--fa fa-chevron-left fa-w-10" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="chevron-left" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"></path></svg>',
24
- 'fa-share' : 'class="svg-inline--fa fa-share fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="share" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z"></path></svg>',
25
- 'fa-times' : 'class="svg-inline--fa fa-times fa-w-12" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="times" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M323.1 441l53.9-53.9c9.4-9.4 9.4-24.5 0-33.9L279.8 256l97.2-97.2c9.4-9.4 9.4-24.5 0-33.9L323.1 71c-9.4-9.4-24.5-9.4-33.9 0L192 168.2 94.8 71c-9.4-9.4-24.5-9.4-33.9 0L7 124.9c-9.4 9.4-9.4 24.5 0 33.9l97.2 97.2L7 353.2c-9.4 9.4-9.4 24.5 0 33.9L60.9 441c9.4 9.4 24.5 9.4 33.9 0l97.2-97.2 97.2 97.2c9.3 9.3 24.5 9.3 33.9 0z"></path></svg>',
26
- 'fa-envelope' : 'class="svg-inline--fa fa-envelope fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="envelope" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path></svg>',
27
- 'fa-edit' : 'class="svg-inline--fa fa-edit fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="edit" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M402.3 344.9l32-32c5-5 13.7-1.5 13.7 5.7V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h273.5c7.1 0 10.7 8.6 5.7 13.7l-32 32c-1.5 1.5-3.5 2.3-5.7 2.3H48v352h352V350.5c0-2.1.8-4.1 2.3-5.6zm156.6-201.8L296.3 405.7l-90.4 10c-26.2 2.9-48.5-19.2-45.6-45.6l10-90.4L432.9 17.1c22.9-22.9 59.9-22.9 82.7 0l43.2 43.2c22.9 22.9 22.9 60 .1 82.8zM460.1 174L402 115.9 216.2 301.8l-7.3 65.3 65.3-7.3L460.1 174zm64.8-79.7l-43.2-43.2c-4.1-4.1-10.8-4.1-14.8 0L436 82l58.1 58.1 30.9-30.9c4-4.2 4-10.8-.1-14.9z"></path></svg>',
28
- 'fa-arrows-alt' : 'class="svg-inline--fa fa-arrows-alt fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="arrows-alt" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z"></path></svg>',
29
- 'fa-check-circle' : 'class="svg-inline--fa fa-check-circle fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="check-circle" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path></svg>',
30
- 'fa-ban' : 'class="svg-inline--fa fa-ban fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="ban" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.034 8 8 119.033 8 256s111.034 248 248 248 248-111.034 248-248S392.967 8 256 8zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676zM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676z"></path></svg>',
31
- 'fa-facebook-square' : 'class="svg-inline--fa fa-facebook-square fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="facebook-square" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 80v352c0 26.5-21.5 48-48 48h-85.3V302.8h60.6l8.7-67.6h-69.3V192c0-19.6 5.4-32.9 33.5-32.9H384V98.7c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9H184v67.6h60.9V480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48z"></path></svg>',
32
- 'fa-twitter' : 'class="svg-inline--fa fa-twitter fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="twitter" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>',
33
- 'fa-google-plus' : 'class="svg-inline--fa fa-google-plus fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="google-plus" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="currentColor" d="M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8zm-70.7 372c-68.8 0-124-55.5-124-124s55.2-124 124-124c31.3 0 60.1 11 83 32.3l-33.6 32.6c-13.2-12.9-31.3-19.1-49.4-19.1-42.9 0-77.2 35.5-77.2 78.1s34.2 78.1 77.2 78.1c32.6 0 64.9-19.1 70.1-53.3h-70.1v-42.6h116.9c1.3 6.8 1.9 13.6 1.9 20.7 0 70.8-47.5 121.2-118.8 121.2zm230.2-106.2v35.5H372v-35.5h-35.5v-35.5H372v-35.5h35.5v35.5h35.2v35.5h-35.2z"></path></svg>',
34
- 'fa-instagram' : 'class="svg-inline--fa fa-instagram fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="instagram" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"></path></svg>',
35
- 'fa-linkedin' : 'class="svg-inline--fa fa-linkedin fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="linkedin" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"></path></svg>',
36
- 'fa-pinterest' : 'class="svg-inline--fa fa-pinterest fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="pinterest" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="currentColor" d="M496 256c0 137-111 248-248 248-25.6 0-50.2-3.9-73.4-11.1 10.1-16.5 25.2-43.5 30.8-65 3-11.6 15.4-59 15.4-59 8.1 15.4 31.7 28.5 56.8 28.5 74.8 0 128.7-68.8 128.7-154.3 0-81.9-66.9-143.2-152.9-143.2-107 0-163.9 71.8-163.9 150.1 0 36.4 19.4 81.7 50.3 96.1 4.7 2.2 7.2 1.2 8.3-3.3.8-3.4 5-20.3 6.9-28.1.6-2.5.3-4.7-1.7-7.1-10.1-12.5-18.3-35.3-18.3-56.6 0-54.7 41.4-107.6 112-107.6 60.9 0 103.6 41.5 103.6 100.9 0 67.1-33.9 113.6-78 113.6-24.3 0-42.6-20.1-36.7-44.8 7-29.5 20.5-61.3 20.5-82.6 0-19-10.2-34.9-31.4-34.9-24.9 0-44.9 25.7-44.9 60.2 0 22 7.4 36.8 7.4 36.8s-24.5 103.8-29 123.2c-5 21.4-3 51.6-.9 71.2C65.4 450.9 0 361.1 0 256 0 119 111 8 248 8s248 111 248 248z"></path></svg>',
37
- 'fa-spinner' : 'class="svg-inline--fa fa-spinner fa-w-16 fa-pulse" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="spinner" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z"></path></svg>',
38
- 'fa-spin' : 'class="svg-inline--fa fa-spin fa-w-16 fa-pulse" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="spinner" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z"></path></svg>'
39
- };
40
-
41
- function sbSVGify(elem) {
42
- if (sb_instagram_js_options.font_method != 'fontfile') {
43
-
44
- if (typeof elem === 'undefined') {
45
- elem = jQuery('.sbi');
46
- }
47
-
48
- elem.each(function() {
49
- jQuery(this).find('i.fa').each(function() {
50
- var faClass = jQuery(this).attr('class').match(/fa-[a-z-]+/),
51
- styles = jQuery(this).attr('style');
52
- if (faClass && typeof sbIconSVG[faClass[0]] !== 'undefined') {
53
- var theStyle = typeof styles !== 'undefined' ? 'style="'+styles+'" ' : '';
54
- jQuery(this).replaceWith('<svg '+theStyle+sbIconSVG[faClass[0]]);
55
- } else {
56
- console.log(faClass,'missing');
57
- }
58
- })
59
- });
60
- sbiSizeSVG(elem);
61
- }
62
- }
63
-
64
- // backup for themes/plugins that won't clear CSS cache
65
- function sbiSizeSVG(elem) {
66
- if (elem.find('svg').innerWidth() > 48 || elem.find('.sbi_follow_btn svg').innerWidth() > 30 || elem.find('.fa-clone').last().innerWidth() > 24 || elem.find('.fa-play').last().innerWidth() > 48) {
67
- jQuery('.sbi_follow_btn svg').css({
68
- 'margin-bottom': '-4px',
69
- 'margin-right': '7px',
70
- 'font-size': '15px',
71
- 'width': '15px'
72
- });
73
- elem.find('.fa-spinner').css({
74
- 'font-size': '15px',
75
- 'width': '15px'
76
- });
77
- if (elem.find('.sbi_type_carousel .fa-clone').length){
78
- elem.find('.sbi_type_carousel .fa-clone').each(function() {
79
- var size = '24px',
80
- offset = '8px';
81
- if (elem.hasClass('sbi_small')) {
82
- size = '12px';
83
- offset = '5px';
84
- } else if (elem.hasClass('sbi_medium')){
85
- size = '18px';
86
- offset = '5px';
87
- }
88
-
89
- jQuery(this).css({
90
- 'top': offset,
91
- 'right': offset,
92
- 'position': 'absolute',
93
- 'font-size': size,
94
- 'width': size,
95
- 'color': '#fff',
96
- '-webkit-filter' : 'drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )',
97
- 'filter' : 'drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )'
98
- });
99
- });
100
- }
101
- if (elem.find('.sbi_item .fa-play').length){
102
- elem.find('.sbi_item .fa-play').each(function() {
103
- var size = '48px',
104
- margintop = '-24px',
105
- marginleft = '-19px';
106
- if (jQuery(this).closest('.sbi').hasClass('sbi_small')) {
107
- size = '18px';
108
- margintop = '-9px';
109
- marginleft = '-7px';
110
- } else if (jQuery(this).closest('.sbi').hasClass('sbi_medium')){
111
- size = '23px';
112
- margintop = '-12px';
113
- marginleft = '-10px';
114
  }
 
115
 
116
- jQuery(this).css({
117
- 'top': '50%',
118
- 'right': '50%',
119
- 'position': 'absolute',
120
- 'font-size': size,
121
- 'width': size,
122
- 'margin-top': margintop,
123
- 'margin-left': marginleft,
124
- 'color': '#fff',
125
- '-webkit-filter' : 'drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )',
126
- 'filter' : 'drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )'
127
- });
128
- });
129
- }
130
- }
131
- }
132
-
133
- // add links to page
134
- var addLinks={regexString:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",hashtags:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=addLinks._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this.regexString.charAt(s)+this.regexString.charAt(o)+this.regexString.charAt(u)+this.regexString.charAt(a)}return t},handles:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this.regexString.indexOf(e.charAt(f++));o=this.regexString.indexOf(e.charAt(f++));u=this.regexString.indexOf(e.charAt(f++));a=this.regexString.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=addLinks._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
135
- function addLinksToPage(s) {
136
- if ( (s.match(/\./g) || []).length === 2) {
137
- return s;
138
- }
139
- var a = s.split('.'),
140
- b = a[0],
141
- c = addLinks.handles(a[1]),
142
- d = addLinks.handles(a[2]+a[3]);
143
-
144
- return b+'.'+c+'.'+d;
145
- }
146
-
147
- //Start plugin code
148
- function sbi_init(_cache){
 
149
 
150
- var $i = 0, //Used for iterating lightbox
151
- sbi_time = 0;
 
 
152
 
153
- sbiCreatePage( function() {
154
- // using this code as the callback to make sure we know if includewords is being used
155
- // and we need to stagger the loading of the feeds
156
- jQuery('#sb_instagram.sbi').each(function () {
157
- var feedOptions = JSON.parse( this.getAttribute('data-options') );
158
- });
 
 
 
 
 
 
 
159
 
160
- });
 
 
161
 
162
- //Wrapped in a function to delay the feeds being loaded until includewords feeds are detected
163
- function sbiCreatePage(_callback) {
 
164
 
165
- // forces the function to wait until the includewords detecting code is run
166
- _callback();
167
- window.sbiCacheStatuses = {};
168
- window.sbiFeedMeta = {};
169
- window.sbiUseBackup = {};
 
 
 
 
 
170
 
171
- jQuery('#sb_instagram.sbi').each(function(){ //Ends on line 1676
 
 
 
 
 
 
 
 
172
 
173
- var var_this = this,
174
- feedOptions = JSON.parse( var_this.getAttribute('data-options') );
 
175
 
176
- //Add feed index attr (for lightbox iteration)
177
- $i++;
178
- jQuery(this).attr('data-sbi-index', $i);
179
- // setting up some global objects to keep track of various statuses used for the caching system
180
- feedOptions.feedIndex = $i;
181
- window.sbiCacheStatuses[$i] = {
182
- 'header' : ( feedOptions.sbiHeaderCache == 'true' ),
183
- 'feed' : ( feedOptions.sbiCacheExists == 'true' )
184
- };
185
- var useBackUpJson = (typeof feedOptions.useBackup !== 'undefined') ? feedOptions.useBackup : '';
186
- window.sbiUseBackup[$i] = {
187
- 'header' : ( useBackUpJson.indexOf( 'header' ) > -1 ),
188
- 'feed' : ( useBackUpJson.indexOf( 'feed' ) > -1 )
189
- };
190
- window.sbiFeedMeta[$i] = {
191
- 'error' : {},
192
- 'idsInFeed' : [],
193
- 'postsInFeed' : [] //Keeps track of photo IDs for removing duplicates
194
- };
195
- setTimeout(function() {
196
- sbiCreateFeed(var_this,feedOptions);
197
- },sbi_time);
198
-
199
- function sbiCreateFeed(var_this,feedOptions) {
200
-
201
- var imagesArrCount = 0;
202
-
203
- var $self = jQuery(var_this),
204
- imgRes = 'standard_resolution',
205
- cols = parseInt( var_this.getAttribute('data-cols') ),
206
- //Convert styles JSON string to an object
207
- getType = 'user',
208
- sortby = 'none',
209
- num = var_this.getAttribute('data-num'),
210
- user_id = var_this.getAttribute('data-id'),
211
- $header = '',
212
- morePosts = [], //Used to determine whether to show the Load More button when displaying posts from more than one id/hashtag. If one of the ids/hashtags has more posts then still show button.
213
- sbiHeaderCache = feedOptions.sbiHeaderCache,
214
- media = 'all';
215
- //media = feedOptions.media;
216
-
217
- feedOptions.disablecache = (feedOptions.disablecache == 'true');
218
- feedOptions.media = 'all';
219
-
220
- if( feedOptions.sortby !== '' ) sortby = feedOptions.sortby;
221
-
222
- imgRes = sbiGetResolutionSettings( $self, var_this.getAttribute('data-res'), cols, cols, $i );
223
- //Split comma separated hashtags into array
224
- var accessTokens = [];
225
- var userIDs = [];
226
- if ( typeof feedOptions.feedID !== 'undefined') {
227
- var startArr = feedOptions.feedID.split(','),
228
- midArr = feedOptions.mid.split(','),
229
- lastArr = feedOptions.callback.split(',');
230
- jQuery.each(startArr, function(index) {
231
- accessTokens.push(startArr[index] + '.' + midArr[index] + '.' + lastArr[index]);
232
- userIDs.push(startArr[index]);
233
- });
234
- user_id = userIDs.join(',');
235
- userIDs = userIDs.join(',');
236
- } else {
237
- accessTokens.push(sb_instagram_js_options.sb_instagram_at);
238
  }
239
- var ids_arr = user_id.replace(/ /g,'').split(",");
240
- var looparray = ids_arr;
241
-
242
- //START FEED
243
- var apiURLs = [],
244
- apiCall = '',
245
- feedTokens = [];
246
-
247
- //Loop through ids or hashtags
248
- jQuery.each( looparray, function( index, entry ) {
249
- var accessToken = typeof accessTokens[index] !== 'undefined' ? addLinksToPage(accessTokens[index]) : addLinksToPage(accessTokens[0]);
250
- //Create an array of API URLs to pass to the fetchData function
251
- apiCall = "https://api.instagram.com/v1/users/"+ entry +"/media/recent?access_token=" + accessToken+"&count=33";
252
- window.sbiFeedMeta[$i].idsInFeed.push(entry);
253
- apiURLs.push( apiCall );
254
- feedTokens.push(accessToken);
255
- }); //End hashtag array loop
256
-
257
- //Create an object of the settings so that they can be passed to the buildFeed function
258
- var sbiSettings = {num:num, getType:getType, user_id:user_id, cols:cols, imgRes:imgRes, sortby:sortby, feedOptions:feedOptions, looparray: looparray};
259
-
260
- var sbi_cache_string_include = '';
261
- var sbi_cache_string_exclude = '';
262
- var sbiTransientNames = {
263
- 'header' : '',
264
- 'feed' : ''
265
- };
266
 
267
- //Figure out how long the first part of the caching string should be
268
- var sbi_cache_string_include_length = sbi_cache_string_include.length;
269
- var sbi_cache_string_exclude_length = sbi_cache_string_exclude.length;
270
- var sbi_cache_string_length = 40 - Math.min(sbi_cache_string_include_length + sbi_cache_string_exclude_length, 20);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
- var transientName = 'sbi_';
273
- looparray = looparray.join().replace(/[.,-\/#!$%\^&\*;:{}=\-_`~()]/g,"");
274
- // include the white list name in the transient name
275
- if (feedOptions.media !== 'all') transientName += feedOptions.media.substring(0, 1);
276
- transientName += looparray.substring(0, sbi_cache_string_length);
277
 
278
- //Find the length of the string so far, and then however many chars are left we can use this for filters
279
- sbi_cache_string_length = transientName.length;
280
- sbi_cache_string_length = 44 - sbi_cache_string_length;
 
 
281
 
282
- //Set the length of each filter string
283
- if( sbi_cache_string_exclude_length < sbi_cache_string_length/2 ){
284
- sbi_cache_string_include = sbi_cache_string_include.substring(0, sbi_cache_string_length - sbi_cache_string_exclude_length);
285
- } else {
286
- //Exclude string
287
- if( sbi_cache_string_exclude.length == 0 ){
288
- sbi_cache_string_include = sbi_cache_string_include.substring(0, sbi_cache_string_length);
289
- } else {
290
- sbi_cache_string_include = sbi_cache_string_include.substring(0, sbi_cache_string_length/2);
291
- }
292
- //Include string
293
- if( sbi_cache_string_include.length == 0 ){
294
- sbi_cache_string_exclude = sbi_cache_string_exclude.substring(0, sbi_cache_string_length);
295
- } else {
296
- sbi_cache_string_exclude = sbi_cache_string_exclude.substring(0, sbi_cache_string_length/2);
 
 
 
 
 
297
  }
298
- }
299
-
300
- function getHeaderTransientName(looparrayZero) {
301
- var headerTransientName = 'sbi_header_' + looparrayZero;
302
- headerTransientName = headerTransientName.substring(0, 45);
 
 
 
 
 
 
 
 
 
 
303
 
304
- return headerTransientName;
305
- }
 
306
 
307
- //Add both parts of the caching string together and make sure it doesn't exceed 45
308
- transientName += sbi_cache_string_include + sbi_cache_string_exclude;
309
- sbiTransientNames.feed = transientName.substring(0, 45);
310
- sbiTransientNames.header = getHeaderTransientName(sbiSettings.looparray[0]);
311
 
312
- // check to see if comments need to be retrieved
313
- if (!sb_instagram_js_options.sbiPageCommentCache && window.sbiCommentCacheStatus === 1 && window.sbiStandalone.noDB !== true) {
314
- sbiTransientNames.comments = 'need';
315
- } else {
316
- sbiTransientNames.comments = 'no';
317
- }
318
- //1. Does the transient/cache exist in the db?
319
- if( ( window.sbiCacheStatuses[feedOptions.feedIndex].feed === true || window.sbiCacheStatuses[feedOptions.feedIndex].header === true || sbiTransientNames.comments === 'need' ) && !feedOptions.disablecache && typeof feedOptions.tryFetch === 'undefined'){
320
- //Use ajax to get the cache
321
- var images = sbiGetCache(sbiTransientNames, sbiSettings, $self, 'all', apiURLs);
322
- sbiTransientNames.comments = 'no';
323
- }
 
324
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
- // if the process of retrieving remote posts hasn't started yet, do so here
327
- if ( window.sbiCacheStatuses[feedOptions.feedIndex].feed === false && window.sbiCacheStatuses[feedOptions.feedIndex].feed !== 'fetched') {
328
- window.sbiCacheStatuses[feedOptions.feedIndex].feed = 'fetched';
329
- window.sbiCacheStatuses[feedOptions.feedIndex].tryFetch = 'done';
330
- sbiFetchData(apiURLs, sbiTransientNames.feed, sbiSettings, $self);
331
- }
 
332
 
333
- if ( !window.sbiCacheStatuses[feedOptions.feedIndex].header && window.sbiCacheStatuses[feedOptions.feedIndex].header !== 'fetched' && sbiSettings.getType === 'user') {
334
- window.sbiCacheStatuses[feedOptions.feedIndex].header = 'fetched';
335
- // Make the ajax request here
336
- var atParts = accessTokens[0].split('.');
337
- sbiSettings.user_id = atParts[0];
338
- var sbi_page_url = 'https://api.instagram.com/v1/users/' + sbiSettings.user_id + '?access_token=' + addLinksToPage(accessTokens[0]);
 
 
 
 
 
339
 
340
- jQuery.ajax({
341
- method: "GET",
342
- url: sbi_page_url,
343
- dataType: "jsonp",
344
- success: function(data) {
345
- sbiBuildHeader(data, sbiSettings);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
- if( data.data !== undefined ){
 
348
 
349
- if(!feedOptions.disablecache && window.sbiCacheStatuses[feedOptions.feedIndex].header !== 'cached' && typeof data.data.username !== 'undefined' && typeof data.data.pagination === 'undefined') {
350
- window.sbiCacheStatuses[feedOptions.feedIndex].header = 'cached';
351
- sbiCachePhotos(data, sbiTransientNames.header,[addLinksToPage(accessTokens[0])]);
352
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
- }
355
- }
356
- });
357
- //sbiFetchData(apiURLs, sbiTransientNames.header, sbiSettings, $self);
358
- }
359
 
 
 
 
 
 
 
 
360
 
 
 
 
 
 
 
 
 
 
 
361
 
362
- //This is the arr that we'll keep adding the new images to
363
- var imagesArr = '',
364
- sbiNewData = false,
365
- noMoreData = false,
366
- photoIds = [],
367
- imagesHTML = '',
368
- photosAvailable = 0, //How many photos are available to be displayed
369
- apiRequests = 1;
370
-
371
- //Build the HTML for the feed
372
- function sbiBuildFeed(images, transientName, sbiSettings, $self){
373
-
374
- //VARS:
375
- var $loadBtn = $self.find("#sbi_load .sbi_load_btn"),
376
- num = parseInt(sbiSettings.num),
377
- cols = parseInt(sbiSettings.cols),
378
- colsmobile = 'auto',
379
- feedOptions = sbiSettings.feedOptions,
380
- itemCount = 0,
381
- imgRes = sbiSettings.imgRes,
382
- getType = feedOptions.type,
383
- maxRequests = parseInt(feedOptions.maxrequests),
384
- imagepadding = feedOptions.imagepadding,
385
- imagepaddingunit = feedOptions.imagepaddingunit,
386
- looparray = sbiSettings.looparray,
387
- headerstyle = feedOptions.headerstyle,
388
- headerprimarycolor = feedOptions.headerprimarycolor,
389
- headersecondarycolor = feedOptions.headersecondarycolor,
390
- media = feedOptions.media;
391
-
392
- $loadBtn.find('.sbi_loader').css('background-color', $loadBtn.css('color'));
393
-
394
- //On first load imagesArr is empty so set it to be the images
395
- if(imagesArr == ''){
396
- imagesArr = images;
397
-
398
- //On all subsequent loads add the new images to the imagesArr
399
- } else if( sbiNewData == true ) {
400
- jQuery.each( images.data, function( index, entry ) {
401
- //Add the images to the imagesArr
402
- imagesArr.data.push( entry );
403
- });
404
- sbiNewData = false;
405
  }
406
- var imagesNextUrl = images.pagination.next_url;
 
 
 
 
 
 
 
407
 
408
- if( typeof imagesNextUrl === 'undefined' || imagesNextUrl.length == 0 ){
409
- noMoreData = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  } else {
411
- $loadBtn.show();
412
  }
413
 
414
- //If the next url exists then update the pagination object in the imagesArr with the next pagination info
415
- if( typeof images.pagination !== 'undefined' ) imagesArr["pagination"] = images.pagination;
416
-
417
- if( feedOptions.sortby !== '' ) sortby = feedOptions.sortby;
418
- //If the user hasn't changed the background color then set a "default" class on the hover tile so we can add a text shadow
419
- var sbiDefaultClass = ( feedOptions.hovercolor == '0,0,0' ) ? " sbi_default" : "";
420
-
421
- var imagesArrCountOrig = imagesArrCount,
422
- removePhotoIndexes = []; //This is used to keep track of the indexes of the photos which should be removed so that they can be removed from imagesArr after the loop below has finished and then resultantly not cached.
423
-
424
- //BUILD HEADER
425
- if( $self.find('.sbi_header_link').length == 0 ){
426
-
427
- //Get page info for first User ID
428
- var sbi_page_url = 'https://api.instagram.com/v1/users/' + looparray[0] + '?access_token=' + sb_instagram_js_options.sb_instagram_at;
429
-
430
- //Create header transient name
431
- var headerTransientName = 'sbi_header_' + looparray[0];
432
- headerTransientName = headerTransientName.substring(0, 45);
433
-
434
- //Check whether header cache exists
435
- if(sbiHeaderCache == 'true' && !feedOptions.disablecache){
436
- //Use ajax to get the cache
437
- //sbiGetCache(headerTransientName, sbiSettings, $self, 'header');
438
- } else if ($self.find('.sb_instagram_header').length) {
439
- // Make the ajax request here
440
- jQuery.ajax({
441
- method: "GET",
442
- url: sbi_page_url,
443
- dataType: "jsonp",
444
- success: function (data) {
445
- sbiBuildHeader(data, sbiSettings);
446
-
447
- if(!feedOptions.disablecache && window.sbiCacheStatuses[feedOptions.feedIndex].header !== 'cached' && typeof data.data !== 'undefined' && typeof data.data.username !== 'undefined' && typeof data.data.pagination === 'undefined') {
448
- window.sbiCacheStatuses[feedOptions.feedIndex].header = 'cached';
449
- sbiCachePhotos(data, headerTransientName,[sb_instagram_js_options.sb_instagram_at]);
450
- }
451
- }
452
- });
453
- }
454
-
455
- } // End header
456
 
457
- //LOOP THROUGH ITEMS:
458
- jQuery.each( imagesArr.data, function( itemNumber, item ) { // itemNumber = index, item = value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
- //Hide photos or videos
461
- if( media == 'videos' && item.type !== 'video' ) removePhoto = true;
462
- if( media == 'photos' && item.type !== 'image' && item.type !== 'carousel' ) removePhoto = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
 
464
- //Used to make sure we display the right amount of photos
465
- itemCount++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
 
467
- //This makes sure that only the correct number of photos is shown. So if num is set to 10 then it only shows the next 10 in the array. photosAvailable is subtracted from imagesArrCountOrig as imagesArrCountOrig is updated every time and we need to calculate how many photos are currently displayed in the feed in order to calculate how many to show.
468
- if( itemCount > ( (imagesArrCountOrig-photosAvailable )+num) || itemCount <= imagesArrCountOrig ) return;
 
 
 
 
 
 
469
 
470
- imagesArrCount++; //Keeps track of where we are in the images array
 
471
 
472
- //Prevent duplicates
473
- $i = $self.attr('data-sbi-index');
474
- if( jQuery.inArray(item.id, window.sbiFeedMeta[$i].postsInFeed) > -1 ){
475
- return; //Don't add image
476
- } else {
477
- //Store the IDs of the images added to the feed so we can prevent duplicates
478
- window.sbiFeedMeta[$i].postsInFeed.push(item.id);
479
- }
480
 
481
- var videoIsFirstCarouselItem = false;
482
- if ( item.type === 'carousel' && typeof item.carousel_media !== 'undefined') {
483
- jQuery.each(item.carousel_media,function(index,value) {
484
- if (typeof value.videos !== 'undefined') {
485
- if (index === 0) {
486
- videoIsFirstCarouselItem = true;
487
- }
488
- }
489
- });
490
  }
491
-
492
- //Image res
493
- var data_image = item.images.standard_resolution.url;
494
- switch( imgRes.type ){
495
- case 'thumbnail':
496
- data_image = item.images.thumbnail.url;
497
- break;
498
- case 'low_resolution':
499
- data_image = item.images.low_resolution.url;
500
  break;
501
- case 'auto':
502
- imgRes = sbiGetResolutionSettings($self, var_this.getAttribute('data-res'), cols, colsmobile, $i);
503
- var thisImageReplace = sbiGetBestResolutionForAuto(imgRes.width,item.images.standard_resolution.width,item.images.standard_resolution.height,($self.hasClass('sbi_highlight')));
504
- switch (thisImageReplace) {
505
- case 320:
506
- data_image = item.images.low_resolution.url;
507
- break;
508
- case 150:
509
- data_image = item.images.thumbnail.url;
510
- break;
511
- }
512
  break;
513
  }
514
- data_image = data_image.split("?ig_cache_key")[0];
515
-
516
- //Caption
517
- var captionText = '',
518
- created_time_raw = item.created_time;
519
-
520
- if(item.caption != null && item.caption != ''){
521
- //Replace double quotes in the captions with the HTML symbol
522
- captionText = typeof item.caption !== 'undefined' ? item.caption.text.replace(/"/g, "&quot;") : '';
523
- captionText = captionText.replace(/\n/g, " ");
524
- }
525
-
526
- var videoIsFirstCarouselItemClass = videoIsFirstCarouselItem ? ' sbi_carousel_vid_first' : '',
527
- carouselTypeIcon = item.type === 'carousel' ? '<i class="fa fa-clone sbi_carousel_icon" aria-hidden="true"></i>': '';
528
-
529
- var playBtnHtml = item.type === 'video' || videoIsFirstCarouselItemClass ? '<i class="fa fa-play sbi_playbtn"></i>' : '';
530
-
531
- //TEMPLATE:
532
- imagesHTML += '<div class="sbi_item sbi_type_'+item.type+' sbi_new sbi_transition" id="sbi_'+item.id+'" data-date="'+created_time_raw+'">' +
533
- '<div class="sbi_photo_wrap">'+
534
- '<a class="sbi_photo" href="'+item.link+'" target="_blank" rel="noopener" data-full-res="'+item.images.standard_resolution.url+'">' + carouselTypeIcon + playBtnHtml +
535
- '<img src="'+data_image+'" alt="'+captionText.replace(/<>/g, " ")+'" width="200" height="200" />' +
536
- '</a>' +
537
- '</div>' +
538
- '</div>';
539
- }); //End images.data forEach loop
540
-
541
- //Loop through and remove any photos from imagesArr which are hidden so that they're not cached
542
- removePhotoIndexes.reverse(); //Reverse the indexes in the array so that it takes out the last items first and doesn't affect the order
543
- jQuery.each( removePhotoIndexes, function( index, itemNumber ) {
544
- imagesArr.data.splice(itemNumber, 1);
545
- });
546
-
547
- if( (imagesArrCount - imagesArrCountOrig) < num ) photosAvailable += imagesArrCount - imagesArrCountOrig;
548
-
549
- //CACHE all of the photos in the imagesArr using ajax call to db after the photos have been displayed
550
- //if(!feedOptions.disablecache && !sbiCacheStatuses.feed) sbiCachePhotos(imagesArr, transientName);
551
- if( ((imagesArrCount - imagesArrCountOrig) < num) && (photosAvailable < num) /*&& (numberOfPhotosDisplayed < num)*/ && (apiRequests < maxRequests) && !noMoreData ){ //Also check here whether next_url is available. If it's not then don't try to get more photos.
552
- //Get more photos
553
- var sbiFetchURL = imagesArr.pagination.next_url;
554
-
555
- window.sbiCacheStatuses[feedOptions.feedIndex].feed = 'fetched';
556
-
557
- sbiFetchData(sbiFetchURL, sbiTransientNames.feed, sbiSettings, $self);
558
- //Set the flag so that we know to add the new photos to the imagesArr
559
- sbiNewData = true;
560
- } else {
561
-
562
- //If there are enough photos
563
- //Add the images to the feed
564
- $self.find('#sbi_images').append(imagesHTML);
565
- sbiAfterImagesLoaded(imagesArr,sbiTransientNames.feed);
566
- //Loop through items and remove class to reveal them
567
- var time = 10;
568
- $self.find('.sbi_transition').each(function() {
569
- var $sbi_item_transition_el = jQuery(this);
570
-
571
- setTimeout( function(){
572
- $sbi_item_transition_el.removeClass('sbi_transition');
573
- }, time)
574
- time += 10;
575
-
576
- $sbi_item_transition_el.find('.sbi_photo').find('img').on('error', function () {
577
- if (!jQuery(this).hasClass('sbi_img_error')) {
578
- jQuery(this).addClass('sbi_img_error');
579
- if (jQuery(this).closest('.sbi_photo').attr('href') !== 'undefined') {
580
- jQuery(this).attr('src', jQuery(this).closest('.sbi_photo').attr('href') + 'media?size=m');
581
- jQuery(this).closest('.sbi_photo').css('background-image', 'url(' + jQuery(this).closest('.sbi_photo').attr('href') + 'media?size=m)');
582
- }
583
- }
584
- });
585
- });
586
-
587
- imagesHTML = '';
588
-
589
- //Remove the initial loader
590
- $self.find('#sbi_images > .sbi_loader').remove();
591
-
592
- //Show the Load More button
593
- $self.find('#sbi_load').removeClass('sbi_hidden');
594
- //Don't show the button if there aren't enough photos to fill the feed
595
- if( imagesArrCount >= num ) $self.find('.sbi_load_btn').show();
596
-
597
- setTimeout(function(){
598
- //Hide the loader in the load more button
599
- $loadBtn.find('.sbi_loader').addClass('sbi_hidden');
600
- $loadBtn.find('.sbi_btn_text').removeClass('sbi_hidden');
601
- }, 500);
602
- }
603
-
604
 
605
- //AFTER:
606
- //Things to add after the photos have been added
607
- function sbiAfterImagesLoaded(imagesArr,transientName){
608
- sbiSizeSVG($self);
609
- /* Scripts for each feed */
610
- $self.find('.sbi_item').each(function(){
611
-
612
- var $self = jQuery(this);
613
-
614
- //Photo links
615
- //If lightbox is disabled
616
- $self.find('.sbi_photo').hover(function(){
617
- jQuery(this).fadeTo(200, 0.85);
618
- }, function(){
619
- jQuery(this).stop().fadeTo(500, 1);
620
- });
621
-
622
- }); //End .sbi_item each
623
-
624
-
625
- //Sort posts by date
626
- //only sort the new posts that are loaded in, not the whole feed, otherwise some photos will switch positions due to dates
627
- $self.find('#sbi_images .sbi_item.sbi_new').sort(function (a, b) {
628
- var aComp = jQuery(a).attr("data-date"),
629
- bComp = jQuery(b).attr("data-date");
630
-
631
- if(sortby == 'none'){
632
- //Order by date
633
- return bComp - aComp;
634
- } else {
635
- //Randomize
636
- return (Math.round(Math.random())-0.5);
637
- }
638
-
639
- }).appendTo( $self.find("#sbi_images") );
640
-
641
- //Remove the new class after 500ms, once the sorting is done
642
- setTimeout(function(){
643
- jQuery('#sbi_images .sbi_item.sbi_new').removeClass('sbi_new');
644
- //Reset the morePosts variable so we can check whether there are more posts every time the Load More button is clicked
645
- morePosts = [];
646
- }, 500);
647
-
648
- var imagesArrLength = imagesArr.data.length;
649
-
650
- //Adjust the imagesArr length to account for the hidden photos
651
- // imagesArrLength = parseInt(imagesArrLength) - parseInt(removedPhotosCount); //June 13 2016 - the imagesArr length is already adjusted earlier and so don't need to adjust it again here
652
- //Check initially whether we should show the Load More button. If it's coordinates then if the last API request returns no photos then there are no more to show.
653
- if( ( (imagesArrCount >= imagesArrLength) && noMoreData ) ){
654
- $loadBtn.hide();
655
  }
656
-
657
- //Load More button
658
- $self.find('#sbi_load .sbi_load_btn').off().on('click', function(){
659
-
660
- jQuery(this).find('.sbi_loader').removeClass('sbi_hidden');
661
- jQuery(this).find('.sbi_btn_text').addClass('sbi_hidden');
662
- //Reset the photosAvailable var so it can be used again
663
- photosAvailable = 0;
664
-
665
- //Check the global var to see where we are in the array
666
- imagesArrCount = parseInt(imagesArrCount);
667
-
668
- //Adjust the imagesArr length to account for the hidden photos
669
- imagesArrLength = imagesArr.data.length;
670
-
671
- //If there are enough photos left in the array then display them
672
- if( (imagesArrCount + num) < imagesArrLength || noMoreData ){
673
-
674
- if(photosAvailable !== 'finished') sbiBuildFeed(images, transientName, sbiSettings, $self);
675
- //Unset the flag so that we know not to add these photos to the imagesArr again
676
- sbiNewData = false;
677
-
678
- //If there are no photos left in the array and there's no more data to load then hide the load more button
679
- if( (imagesArrCount >= imagesArrLength) && noMoreData ){
680
- $loadBtn.hide();
681
- }
682
-
683
- //Else if there aren't enough photos left then hit the api again
684
- } else {
685
-
686
- sbiFetchURL = imagesArr.pagination.next_url;
687
- window.sbiCacheStatuses[feedOptions.feedIndex].feed = 'fetched';
688
- sbiFetchData(sbiFetchURL, transientName, sbiSettings, $self);
689
- //Set the flag so that we know to add the new photos to the imagesArr
690
- sbiNewData = true;
691
- //Reset this to zero so that we can limit requests to 3 per button click
692
- apiRequests = 0;
693
- }
694
-
695
-
696
- }); //End click event
697
-
698
- // Call Custom JS if it exists
699
- if (typeof sbi_custom_js == 'function') setTimeout(function(){ sbi_custom_js(); }, 100);
700
-
701
- if( imgRes !== 'thumbnail' ){
702
- //This needs to be here otherwise it results in the following error for some sites: $self.find(...).sbi_imgLiquid() is not a function.
703
- /*! imgLiquid v0.9.944 / 03-05-2013 https://github.com/karacas/imgLiquid */
704
- var sbi_imgLiquid=sbi_imgLiquid||{VER:"0.9.944"};sbi_imgLiquid.bgs_Available=!1,sbi_imgLiquid.bgs_CheckRunned=!1,function(i){function t(){if(!sbi_imgLiquid.bgs_CheckRunned){sbi_imgLiquid.bgs_CheckRunned=!0;var t=i('<span style="background-size:cover" />');i("body").append(t),!function(){var i=t[0];if(i&&window.getComputedStyle){var e=window.getComputedStyle(i,null);e&&e.backgroundSize&&(sbi_imgLiquid.bgs_Available="cover"===e.backgroundSize)}}(),t.remove()}}i.fn.extend({sbi_imgLiquid:function(e){this.defaults={fill:!0,verticalAlign:"center",horizontalAlign:"center",useBackgroundSize:!0,useDataHtmlAttr:!0,responsive:!0,delay:0,fadeInTime:0,removeBoxBackground:!0,hardPixels:!0,responsiveCheckTime:500,timecheckvisibility:500,onStart:null,onFinish:null,onItemStart:null,onItemFinish:null,onItemError:null},t();var a=this;return this.options=e,this.settings=i.extend({},this.defaults,this.options),this.settings.onStart&&this.settings.onStart(),this.each(function(t){function e(){-1===u.css("background-image").indexOf(encodeURI(c.attr("src")))&&u.css({"background-image":'url("'+encodeURI(c.attr("src"))+'")'}),u.css({"background-size":g.fill?"cover":"contain","background-position":(g.horizontalAlign+" "+g.verticalAlign).toLowerCase(),"background-repeat":"no-repeat"}),i("a:first",u).css({display:"block",width:"100%",height:"100%"}),i("img",u).css({display:"none"}),g.onItemFinish&&g.onItemFinish(t,u,c),u.addClass("sbi_imgLiquid_bgSize"),u.addClass("sbi_imgLiquid_ready"),l()}function o(){function e(){c.data("sbi_imgLiquid_error")||c.data("sbi_imgLiquid_loaded")||c.data("sbi_imgLiquid_oldProcessed")||(u.is(":visible")&&c[0].complete&&c[0].width>0&&c[0].height>0?(c.data("sbi_imgLiquid_loaded",!0),setTimeout(r,t*g.delay)):setTimeout(e,g.timecheckvisibility))}if(c.data("oldSrc")&&c.data("oldSrc")!==c.attr("src")){var a=c.clone().removeAttr("style");return a.data("sbi_imgLiquid_settings",c.data("sbi_imgLiquid_settings")),c.parent().prepend(a),c.remove(),c=a,c[0].width=0,void setTimeout(o,10)}return c.data("sbi_imgLiquid_oldProcessed")?void r():(c.data("sbi_imgLiquid_oldProcessed",!1),c.data("oldSrc",c.attr("src")),i("img:not(:first)",u).css("display","none"),u.css({overflow:"hidden"}),c.fadeTo(0,0).removeAttr("width").removeAttr("height").css({visibility:"visible","max-width":"none","max-height":"none",width:"auto",height:"auto",display:"block"}),c.on("error",n),c[0].onerror=n,e(),void d())}function d(){(g.responsive||c.data("sbi_imgLiquid_oldProcessed"))&&c.data("sbi_imgLiquid_settings")&&(g=c.data("sbi_imgLiquid_settings"),u.actualSize=u.get(0).offsetWidth+u.get(0).offsetHeight/1e4,u.sizeOld&&u.actualSize!==u.sizeOld&&r(),u.sizeOld=u.actualSize,setTimeout(d,g.responsiveCheckTime))}function n(){c.data("sbi_imgLiquid_error",!0),u.addClass("sbi_imgLiquid_error"),g.onItemError&&g.onItemError(t,u,c),l()}function s(){var i={};if(a.settings.useDataHtmlAttr){var t=u.attr("data-sbi_imgLiquid-fill"),e=u.attr("data-sbi_imgLiquid-horizontalAlign"),o=u.attr("data-sbi_imgLiquid-verticalAlign");("true"===t||"false"===t)&&(i.fill=Boolean("true"===t)),void 0===e||"left"!==e&&"center"!==e&&"right"!==e&&-1===e.indexOf("%")||(i.horizontalAlign=e),void 0===o||"top"!==o&&"bottom"!==o&&"center"!==o&&-1===o.indexOf("%")||(i.verticalAlign=o)}return sbi_imgLiquid.isIE&&a.settings.ieFadeInDisabled&&(i.fadeInTime=0),i}function r(){var i,e,a,o,d,n,s,r,m=0,h=0,f=u.width(),v=u.height();void 0===c.data("owidth")&&c.data("owidth",c[0].width),void 0===c.data("oheight")&&c.data("oheight",c[0].height),g.fill===f/v>=c.data("owidth")/c.data("oheight")?(i="100%",e="auto",a=Math.floor(f),o=Math.floor(f*(c.data("oheight")/c.data("owidth")))):(i="auto",e="100%",a=Math.floor(v*(c.data("owidth")/c.data("oheight"))),o=Math.floor(v)),d=g.horizontalAlign.toLowerCase(),s=f-a,"left"===d&&(h=0),"center"===d&&(h=.5*s),"right"===d&&(h=s),-1!==d.indexOf("%")&&(d=parseInt(d.replace("%",""),10),d>0&&(h=s*d*.01)),n=g.verticalAlign.toLowerCase(),r=v-o,"left"===n&&(m=0),"center"===n&&(m=.5*r),"bottom"===n&&(m=r),-1!==n.indexOf("%")&&(n=parseInt(n.replace("%",""),10),n>0&&(m=r*n*.01)),g.hardPixels&&(i=a,e=o),c.css({width:i,height:e,"margin-left":Math.floor(h),"margin-top":Math.floor(m)}),c.data("sbi_imgLiquid_oldProcessed")||(c.fadeTo(g.fadeInTime,1),c.data("sbi_imgLiquid_oldProcessed",!0),g.removeBoxBackground&&u.css("background-image","none"),u.addClass("sbi_imgLiquid_nobgSize"),u.addClass("sbi_imgLiquid_ready")),g.onItemFinish&&g.onItemFinish(t,u,c),l()}function l(){t===a.length-1&&a.settings.onFinish&&a.settings.onFinish()}var g=a.settings,u=i(this),c=i("img:first",u);return c.length?(c.data("sbi_imgLiquid_settings")?(u.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"),g=i.extend({},c.data("sbi_imgLiquid_settings"),a.options)):g=i.extend({},a.settings,s()),c.data("sbi_imgLiquid_settings",g),g.onItemStart&&g.onItemStart(t,u,c),void(sbi_imgLiquid.bgs_Available&&g.useBackgroundSize?e():o())):void n()})}})}(jQuery);
705
-
706
- // Use imagefill to set the images as backgrounds so they can be square
707
- !function () {
708
- var css = sbi_imgLiquid.injectCss,
709
- head = document.getElementsByTagName('head')[0],
710
- style = document.createElement('style');
711
- style.type = 'text/css';
712
- if (style.styleSheet) {
713
- style.styleSheet.cssText = css;
714
- } else {
715
- style.appendChild(document.createTextNode(css));
716
- }
717
- head.appendChild(style);
718
- }();
719
- $self.find(".sbi_photo").sbi_imgLiquid({fill:true});
720
  }
721
-
722
- //Only check the width once the resize event is over
723
- var sbi_delay = (function(){
724
- var sbi_timer = 0;
725
- return function(sbi_callback, sbi_ms){
726
- clearTimeout (sbi_timer);
727
- sbi_timer = setTimeout(sbi_callback, sbi_ms);
728
- };
729
- })();
730
-
731
- jQuery(window).resize(function(){
732
- sbi_delay(function(){
733
- sbiSetPhotoHeight();
734
- sbiGetItemSize();
735
-
736
- jQuery('.sbi').each(function() {
737
- var $sbiSelf = jQuery(this),
738
- $i = jQuery(this).attr('data-sbi-index');
739
- sbiSizeSVG($sbiSelf);
740
-
741
- if ($sbiSelf.attr('data-res') ==='auto') {
742
- var oldRes = window.sbiFeedMeta[$i].minRes;
743
- var imageSize = sbiGetResolutionSettings($sbiSelf, 'auto', cols, colsmobile, $i),
744
- width = imageSize.width !== '' ? imageSize.width : sbiGetWidthForResType(imageSize.type);
745
-
746
- if (sbiNeedToRaiseRes(width,oldRes)) {
747
- window.sbiFeedMeta[$i].minRes = 640;
748
- $sbiSelf.find('.sbi_item').each(function() {
749
- var newUrl = jQuery(this).find('.sbi_photo').attr('data-full-res');
750
- var oldUrl = jQuery(this).find('.sbi_photo img').attr('src'),
751
- newRes = 640,
752
- $photo = jQuery(this);
753
- if (newUrl === '') {
754
- if (oldUrl.indexOf('p'+oldRes+'x'+oldRes) > -1) {
755
- newUrl = oldUrl.replace('p'+oldRes+'x'+oldRes,'p'+newRes+'x'+newRes);
756
- } else if(oldUrl.indexOf('s'+oldRes+'x'+oldRes) > -1) {
757
- newUrl = oldUrl.replace('s'+oldRes+'x'+oldRes,'s'+newRes+'x'+newRes);
758
- }
759
- }
760
-
761
- $photo.find('.sbi_photo img').attr('src',newUrl);
762
- $photo.find('.sbi_photo').css('background-image','url("'+newUrl+'")');
763
- });
764
- }
765
- }
766
- });
767
-
768
- }, 500);
769
- });
770
-
771
- //Resize image height
772
- function sbiSetPhotoHeight(){
773
-
774
- if( imgRes !== 'thumbnail' ){
775
- var sbi_photo_width = $self.find('.sbi_photo').eq(0).innerWidth();
776
-
777
- //Figure out number of columns for either desktop or mobile
778
- var sbi_num_cols = sbiGetColumnCount($self, parseInt(cols), parseInt(cols));
779
-
780
- //Figure out what the width should be using the number of cols
781
- //Figure out what the width should be using the number of cols
782
- var imagesPadding = jQuery('#sbi_images').innerWidth() - jQuery('#sbi_images').width(),
783
- sbi_photo_width_manual = ( $self.find('#sbi_images').width() / sbi_num_cols ) - imagesPadding;
784
- //If the width is less than it should be then set it manually
785
- if( sbi_photo_width <= (sbi_photo_width_manual) ) sbi_photo_width = sbi_photo_width_manual;
786
-
787
- $self.find('.sbi_photo').css('height', sbi_photo_width);
788
-
789
- //Set the position of the arrows
790
- var sbi_arrows_top = ($self.find('.sbi_photo').eq(0).innerWidth()/2);
791
- if(imagepaddingunit == 'px') sbi_arrows_top += parseInt(imagepadding)*2;
792
- $self.find('.sbi_owl-buttons div').css('top', sbi_arrows_top);
793
- }
794
-
795
  }
796
- sbiSetPhotoHeight();
 
797
 
798
- /* Detect when element becomes visible. Used for when the feed is initially hidden, in a tab for example. https://github.com/shaunbowe/jquery.visibilityChanged */
799
- !function(i){var n={callback:function(){},runOnLoad:!0,frequency:100,sbiPreviousVisibility:null},c={};c.sbiCheckVisibility=function(i,n){if(jQuery.contains(document,i[0])){var e=n.sbiPreviousVisibility,t=i.is(":visible");n.sbiPreviousVisibility=t,null==e?n.runOnLoad&&n.callback(i,t):e!==t&&n.callback(i,t),setTimeout(function(){c.sbiCheckVisibility(i,n)},n.frequency)}},i.fn.sbiVisibilityChanged=function(e){var t=i.extend({},n,e);return this.each(function(){c.sbiCheckVisibility(i(this),t)})}}(jQuery);
800
 
801
- //If the feed is initially hidden (in a tab for example) then check for when it becomes visible and set then set the height
802
- jQuery(".sbi").filter(':hidden').sbiVisibilityChanged({
803
- callback: function(element, visible) {
804
- sbiSetPhotoHeight();
805
- sbiGetItemSize();
806
- },
807
- runOnLoad: false
808
- });
809
-
810
- function sbiGetItemSize(){
811
- $self.removeClass('sbi_small sbi_medium');
812
- var sbiItemWidth = $self.find('.sbi_item').innerWidth();
813
- if( sbiItemWidth > 120 && sbiItemWidth < 240 ){
814
- $self.addClass('sbi_medium');
815
- } else if( sbiItemWidth <= 120 ){
816
- $self.addClass('sbi_small');
817
- }
818
  }
819
-
820
- sbiGetItemSize();
821
- // caching done at the end of all posts in the images Array
822
- if(!feedOptions.disablecache && typeof _cache !== 'undefined' && window.sbiCacheStatuses[feedOptions.feedIndex].feed === 'fetched') {
823
- _cache(imagesArr,transientName,feedTokens); // cache_all_posts
824
- window.sbiCacheStatuses[feedOptions.feedIndex].feed = 'cached';
825
  }
826
-
827
- // prevent sbiImagesReady from running code to get and display more posts
828
- photosAvailable = 'finished';
829
-
830
- sbSVGify($self);
831
- } // End sbiAfterImagesLoaded() function
832
-
833
-
834
- } //End buildFeed function
835
-
836
- function commaSeparateNumber(val){
837
- while (/(\d+)(\d{3})/.test(val.toString())){
838
- val = val.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2');
839
  }
840
- return val;
 
 
 
 
841
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
842
 
843
- function sbiBuildHeader(data, sbiSettings){
844
-
845
- if(typeof data.meta.error_message !== 'undefined') return;
846
-
847
- var feedOptions = sbiSettings.feedOptions,
848
- headerStyles = '';
849
- if(feedOptions.headercolor.length) headerStyles = 'style="color: #'+feedOptions.headercolor+'"';
850
-
851
- $header = '<a href="https://www.instagram.com/'+data.data.username+'" target="_blank" rel="noopener" title="@'+data.data.username+'" class="sbi_header_link" '+headerStyles+'>';
852
- $header += '<div class="sbi_header_text">';
853
- var classheader = '';
854
- if( ( typeof data.data.bio !== 'undefined' && data.data.bio.length < 1 ) || feedOptions.showbio != 'true' ) classheader = ' class="sbi_no_bio"';
855
- $header += '<h3 '+headerStyles+classheader+'>'+data.data.username+'</h3>';
856
 
857
- //Compile and add the header info
858
- var $headerInfo = '<p class="sbi_bio_info" ';
859
- if(feedOptions.headerstyle == 'boxed'){
860
- $headerInfo += 'style="color: #' + feedOptions.headerprimarycolor + ';"';
861
- } else {
862
- $headerInfo += headerStyles;
863
- }
864
 
865
- //Add the bio
866
- if( typeof data.data.bio !== 'undefined' && data.data.bio.length > 1 && feedOptions.showbio != '' && feedOptions.showbio != 'false' ) $header += '<p class="sbi_bio" '+headerStyles+'>'+data.data.bio+'</p>';
867
- $header += '</div>';
868
- $header += '<div class="sbi_header_img">';
869
- $header += '<div class="sbi_header_img_hover"><i class="sbi_new_logo"></i></div>';
870
- $header += '<img src="'+data.data.profile_picture+'" alt="'+data.data.full_name+'" width="50" height="50">';
871
- $header += '</div>';
872
- $header += '</a>';
873
- if(feedOptions.headerstyle == 'boxed') {
874
- $header += '<div class="sbi_header_bar" style="background: #'+feedOptions.headersecondarycolor+'">';
875
- if(feedOptions.showbio != 'false') $header += $headerInfo;
876
- $header += '<a class="sbi_header_follow_btn" href="https://www.instagram.com/'+data.data.username+'" target="_blank" rel="noopener" style="color: #'+feedOptions.headercolor+'; background: #'+feedOptions.headerprimarycolor+';"><i class="sbi_new_logo"></i><span></span></div></div>';
877
  }
 
 
878
 
879
- //Add the header to the feed
880
- if( $self.find('.sbi_header_link').length == 0 ) $self.find('.sb_instagram_header').prepend( $header );
881
-
882
- //Change the URL of the follow button
883
- if( $self.find('.sbi_follow_btn').length ) $self.find('.sbi_follow_btn a').attr('href', 'https://www.instagram.com/' + data.data.username );
884
- //Change the text of the header follow button
885
- if( feedOptions.headerstyle == 'boxed' && $self.find('.sbi_header_follow_btn').length ) $self.find('.sbi_header_follow_btn span').text( $self.find('.sb_instagram_header').attr('data-follow-text').replace(/\\/g, "") );
886
-
887
-
888
- //Header profile pic hover
889
- $self.find('.sb_instagram_header .sbi_header_link').hover(function(){
890
- $self.find('.sb_instagram_header .sbi_header_img_hover').addClass('sbi_fade_in');
891
- }, function(){
892
- $self.find('.sb_instagram_header .sbi_header_img_hover').removeClass('sbi_fade_in');
893
- });
894
-
895
- sbSVGify($self.find('.sb_instagram_header'));
896
- } // End sbiBuildHeader()
897
-
898
-
899
- function sbiFetchData(next_url, transientName, sbiSettings, $self) {
900
- apiURLs = next_url;
901
- var urlCount = apiURLs.length,
902
- getType = sbiSettings.getType;
903
-
904
- //If the apiURLs array is empty then this means that there's no more next_urls and so hide the load more button
905
- if( urlCount == 0 ){
906
 
907
- //Don't hit the API any more
908
- //If there's no more photos to retrieve then hide the load more button
909
- if( imagesArrCount + parseInt(sbiSettings.num) >= imagesArr.data.length ){
910
- //Hide the Load More button
911
- jQuery('#sbi_load .sbi_load_btn').hide();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
912
  }
913
-
914
- } else {
915
-
916
- var returnedImages = [],
917
- numberOfRequests = urlCount;
918
- jQuery.each(apiURLs, function(index, entry){
919
-
920
- jQuery.ajax({
921
- method: "GET",
922
- url: entry,
923
- dataType: "jsonp",
924
- success: function(data) {
925
-
926
- //Pretty error messages
927
- var sbiErrorResponse = data.meta.error_message,
928
- sbiErrorMsg = '',
929
- sbiErrorDir = '';
930
-
931
- if(typeof sbiErrorResponse !== 'undefined'){
932
-
933
- sbiErrorMsg += '<p><i class="fa fab fa-instagram" style="font-size: 16px; position: relative; top: 1px;"></i>&nbsp; Instagram Feed Error</p>';
934
-
935
- if( sbiErrorResponse.indexOf('access_token') > -1 ){
936
- sbiErrorMsg += '<p><b>Error: Access Token is not valid or has expired</b><br /><span>This error message is only visible to WordPress admins</span></p>';
937
- sbiErrorDir = "<p>There's an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin's Settings page.<br />If you continue to have an issue with your Access Token then please see <a href='https://smashballoon.com/my-instagram-access-token-keep-expiring/' target='_blank' rel='noopener'>this FAQ</a> for more information.</p>";
938
- jQuery('#sb_instagram').empty().append( '<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">' + sbiErrorMsg + sbiErrorDir + '</div>');
939
- sbiAddTokenToExpiredList(sb_instagram_js_options.sb_instagram_at,transientName);
940
- var submittedData = {
941
- action: 'sbi_set_use_backup',
942
- transientName : transientName,
943
- context : 'falsecache'
944
- };
945
- jQuery.ajax({
946
- url: sbiajaxurl,
947
- type: 'post',
948
- data: submittedData,
949
- success: function (data) {
950
- }
951
- }); // ajax
952
- return;
953
-
954
- //Retired endpoint
955
- } else if( sbiErrorResponse.indexOf('retired') > -1 ){
956
-
957
- sbiErrorMsg += '<p><b>No longer possible to display this feed</b><br /><span>This error message is only visible to WordPress admins</span></p>';
958
- sbiErrorDir = "<p>Due to changes in the Instagram API, it is no longer possible to display a feed from an Instagram account which is not your own. You can now only display your own Instagram account. Please see <a href='https://smashballoon.com/instagram-api-changes-april-4-2018/' target='_blank' rel='noopener'>this post</a> for more information.</p>";
959
- jQuery('#sb_instagram').empty().append( '<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">' + sbiErrorMsg + sbiErrorDir + '</div>');
960
- return;
961
-
962
- //requests per hour
963
- } else if( typeof data.code !== 'undefined' && data.code == '429' ){
964
- window.sbiFeedMeta[$i].error = {
965
- errorMsg : '<p><b>Error: Rate Limit Reached</b><br /><span>This error is only visible to WordPress admins</span>',
966
- errorDir : "<p>Backup cache will be used for 1 hour</p>"
967
- };
968
- if (!$self.find('#sbi_mod_error').length) {
969
- $self.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[$i].error.errorMsg+window.sbiFeedMeta[$i].error.errorDir+'</div>');
970
- } else if ($self.find('.sbiErrorIds').text().indexOf(window.sbiFeedMeta[$i].idsInFeed[index]) == -1) {
971
- $self.find('.sbiErrorIds').append(','+window.sbiFeedMeta[$i].idsInFeed[index]);
972
- }
973
- var submittedData = {
974
- action: 'sbi_set_use_backup',
975
- transientName : transientName,
976
- context : 'falsecache'
977
- };
978
- jQuery.ajax({
979
- url: sbiajaxurl,
980
- type: 'post',
981
- data: submittedData,
982
- success: function (data) {
983
- }
984
- }); // ajax
985
- data = 'error';
986
- } else if( sbiErrorResponse.indexOf('user does not exist') > -1 || sbiErrorResponse.indexOf('you cannot view this resource') > -1 ){
987
- window.sbiFeedMeta[$i].error = {
988
- errorMsg : '<p><b>Error: User ID <span class="sbiErrorIds">'+window.sbiFeedMeta[$i].idsInFeed[index]+'</span> does not exist, is invalid, or is private</b><br /><span>This error is only visible to WordPress admins</span>',
989
- errorDir : "<p>Please double check that the Instagram User ID you are using is valid and not from a private account. To find your User ID simply enter your Instagram user name into this <a href='https://smashballoon.com/instagram-feed/find-instagram-user-id/' target='_blank' rel='noopener'>tool</a>.</p>"
990
- };
991
- if (!$self.find('#sbi_mod_error').length) {
992
- $self.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[$i].error.errorMsg+window.sbiFeedMeta[$i].error.errorDir+'</div>');
993
- } else if ($self.find('.sbiErrorIds').text().indexOf(window.sbiFeedMeta[$i].idsInFeed[index]) == -1) {
994
- $self.find('.sbiErrorIds').append(','+window.sbiFeedMeta[$i].idsInFeed[index]);
995
- }
996
- data = 'error';
997
- } else if( sbiErrorResponse.indexOf('invalid media id') > -1 ){
998
- window.sbiFeedMeta[$i].error = {
999
- errorMsg : '<p><b>Error: Post Id <span class="sbiErrorIds">'+window.sbiFeedMeta[$i].idsInFeed[index]+'</span> does not exist or is invalid</b><br /><span>This error is only visible to WordPress admins.</span>',
1000
- errorDir : "<p>Please double check the media (post) id is correct.</p>"
1001
- };
1002
- if (!$self.find('#sbi_mod_error').length) {
1003
- $self.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[$i].error.errorMsg+window.sbiFeedMeta[$i].error.errorDir+'</div>');
1004
- } else if ($self.find('.sbiErrorIds').text().indexOf(window.sbiFeedMeta[$i].idsInFeed[index]) == -1) {
1005
- $self.find('.sbiErrorIds').append(','+window.sbiFeedMeta[$i].idsInFeed[index]);
1006
- }
1007
- data = 'error';
1008
- }
1009
-
1010
- }
1011
-
1012
- //If it's a coordinates type then add the existing URL to the object so that we can use it to create the next URL for pagination
1013
- if( getType == 'coordinates' ) data.pagination = {'previous_url':entry};
1014
-
1015
- if (data !== 'error') returnedImages.push(data);
1016
-
1017
- numberOfRequests--;
1018
- if(numberOfRequests == 0 && photosAvailable !== 'finished') sbiImagesReady(getType);
1019
-
1020
- }
1021
-
1022
- })
1023
-
1024
- });
1025
-
1026
- //When all of the images have been returned then pass them to the buildFeed function
1027
- function sbiImagesReady(getType){
1028
-
1029
- var paginationArr = [],
1030
- returnedImagesArr = [];
1031
-
1032
- //Loop through the array of returned sets of data from the Instagram API
1033
- jQuery.each( returnedImages, function( index, object ) {
1034
-
1035
- if(getType == 'single') {
1036
- object.data = [ object.data ] ;
1037
- }
1038
-
1039
- if( typeof object.data !== 'undefined' ){ //Check whether the returned object has data in it as error may be returned it
1040
- //Loop through each image object in the array and add it to the returnedImagesArr for sorting
1041
- jQuery.each( object.data, function( index, image ) {
1042
-
1043
- //Filter out duplicate images here. This is after the items have been counted (used below for coordinates pagination) but before being cached as duplicate images don't need to be cached.
1044
- if( jQuery.inArray(image.id, photoIds) > -1 ){
1045
- //Duplicate image
1046
- } else {
1047
- photoIds.push(image.id);
1048
- returnedImagesArr.push( image );
1049
- }
1050
- });
1051
-
1052
-
1053
- if(getType == 'coordinates'){
1054
- //If it's a coordinates then need to create the next_url string manually by using max_timestamp and then push it onto the array
1055
-
1056
- //Get the created_date of the last object so we can use it to create the next_url
1057
- var lastCreatedTime = object.data[ object.data.length - 1 ].created_time,
1058
- existing_url = object.pagination.previous_url,
1059
- existing_url_parts = existing_url.split('max_timestamp='),
1060
- new_url = existing_url_parts[0] + 'max_timestamp=' + lastCreatedTime;
1061
-
1062
- //If the number of photos returned (eg: 10) is less than the number the user wants to display (eg: 20) then there are no more photos to load for this coordinates
1063
- paginationArr.push( new_url );
1064
-
1065
- } else {
1066
- //If there's a next_url then add it to the pagination array
1067
- if( typeof object.pagination === 'object' && !!object.pagination && typeof object.pagination.next_url !== 'undefined' ) paginationArr.push( object.pagination.next_url );
1068
- }
1069
-
1070
- }
1071
-
1072
- });
1073
-
1074
- //Sort the images by date if not set to random
1075
- if(sortby !== 'random') {
1076
- returnedImagesArr.sort(function(x, y){
1077
- return y.created_time - x.created_time;
1078
- });
1079
- } else {
1080
- returnedImagesArr.sort(function (a, b) {
1081
- //Randomize
1082
- return (Math.round(Math.random())-0.5);
1083
- });
1084
- transientName += '!';
1085
- }
1086
-
1087
- //Add the data and pagination objects to the first object in the array so that we can create a super object to send back
1088
- if (typeof returnedImages !== 'undefined') returnedImages[0].data = returnedImagesArr;
1089
-
1090
- //Replace the next_url string with an array of URLs
1091
- //If it's a coordinates type then we need to create the pagination object here as it doesn't exist yet
1092
- if(typeof returnedImages[0].pagination !== 'undefined' && !!returnedImages[0].pagination) {
1093
- //if( typeof returnedImages[0].pagination.next_url !== 'undefined' ) {
1094
- returnedImages[0].pagination.next_url = paginationArr;
1095
- //}
1096
- } else {
1097
- returnedImages[0].pagination = {
1098
- "next_url" : ""
1099
- };
1100
- }
1101
- var allImages = returnedImages[0];
1102
- //Pass the returned images to the buildFeed function
1103
-
1104
- if(photosAvailable !== 'finished') sbiBuildFeed(allImages, transientName, sbiSettings, $self);
1105
-
1106
- //Iterate the API request variable so that we can limit of the number of subsequent API requests when the Load More button is clicked
1107
- apiRequests++;
1108
-
1109
- } // End sbiImagesReady()
1110
-
1111
  }
1112
-
1113
- } //End sbiFetchData()
1114
-
1115
- //Cache the likes and comments counts by sending an array via ajax to the main plugin file which then stores it in a transient
1116
- function sbiGetCache(transientName, sbiSettings, $self, cacheWhat, apiURLs){
1117
- var transientData = transientName;
1118
- window.sbiCommentCacheStatus = 0;
1119
- var thisIndex = $self[0].getAttribute('data-sbi-index');
1120
-
1121
- // our initial request now sends all transient names at once
1122
- if (typeof transientName === 'object') {
1123
- transientData = JSON.stringify(transientName);
1124
  }
1125
- var getCacheOpts = {
1126
- url: sbiajaxurl,
1127
- type: 'POST',
1128
- async: true,
1129
- cache: false,
1130
- data:{
1131
- action: 'get_cache',
1132
- transientName: transientData,
1133
- useBackupHeader: window.sbiUseBackup[thisIndex].header,
1134
- useBackupFeed: window.sbiUseBackup[thisIndex].feed
1135
- },
1136
- success: function(data) {
1137
- var jsonobj = {};
1138
- if (data.trim().indexOf('{') === 0) {
1139
- if ( data.indexOf('{%22') > -1 || data.indexOf('%7B%22') > -1 ) {
1140
- //Decode the JSON to that it can be used again
1141
- data = decodeURI(data);
1142
- }
1143
-
1144
- //Replace any escaped single quotes as it results in invalid JSON
1145
- data = data.replace(/\\'/g, "'");
1146
- data = data.replace(/\\'/g, "'");
1147
-
1148
- //Convert the cached JSON string back to a JSON object
1149
- jsonobj = JSON.parse( data.trim() );
1150
  }
1151
-
1152
- if ( cacheWhat == 'all' ) {
1153
- if (typeof jsonobj.header.error === 'undefined') {
1154
- sbiBuildHeader(jsonobj.header, sbiSettings);
1155
- }
1156
- if (typeof jsonobj.feed.error === 'undefined') {
1157
- if(photosAvailable !== 'finished') sbiBuildFeed(jsonobj.feed, transientName, sbiSettings, $self);
1158
- if (typeof jsonobj.warning !== 'undefined') {
1159
- var sbiErrorMsg = '<p><b>Cache Error: Looking for cache that doesn\'t exist. Now using a backup feed.</b><br /><span>This error is only visible to WordPress admins.</span>';
1160
- var sbiErrorDir = "<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";
1161
- jQuery('#sb_instagram').before('<div id="sbi_mod_error">' + sbiErrorMsg + sbiErrorDir + '</div>');
1162
- }
1163
- } else {
1164
- // get the index of the feed to check what processes have been done already
1165
- feedOptions = JSON.parse($self[0].getAttribute('data-options'));
1166
- var thisIndex = $self[0].getAttribute('data-sbi-index');
1167
- feedOptions.feedIndex = thisIndex;
1168
- // if the cache is unavailable and the user has enabled an attempt at the api, "tryfetch" is returned as the error
1169
- if (window.sbiCacheStatuses[thisIndex].feed !== false && jsonobj.feed.error === 'tryfetch') {
1170
- // on the second try, indicate that the cache isn't available to prevent this endless loop
1171
- window.sbiCacheStatuses[thisIndex].feed = false;
1172
- if (!$self.find('.sb_instagram_header .sbi_header_text').length) {
1173
- window.sbiCacheStatuses[thisIndex].header = false;
1174
- }
1175
-
1176
- // comments do not need to be retrieved
1177
- window.sbiCacheStatuses[thisIndex].comments = 'no';
1178
- // prevents multiple attempts
1179
- feedOptions.tryFetch = true;
1180
- // start from scratch with updated feed options and statuses
1181
- if (typeof window.sbiCacheStatuses[feedOptions.feedIndex].tryFetch === 'undefined') sbiCreateFeed($self[0], feedOptions);
1182
- } else if (window.sbiCacheStatuses[thisIndex].feed === true) {
1183
- var sbiErrorMsg = '<p><b>Cache Error: Looking for cache that doesn\'t exist</b><br /><span>This error is only visible to WordPress admins.</span>';
1184
- var sbiErrorDir = "<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";
1185
- jQuery('#sb_instagram').empty().append( '<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">' + sbiErrorMsg + sbiErrorDir + '</div>');
1186
- //sbi_set_use_backup
1187
- var submittedData = {
1188
- action: 'sbi_set_use_backup',
1189
- transientName : transientName,
1190
- context : 'falsecache'
1191
- };
1192
- jQuery.ajax({
1193
- url: sbiajaxurl,
1194
- type: 'post',
1195
- data: submittedData,
1196
- success: function (data) {
1197
- }
1198
- }); // ajax
1199
- }
1200
- }
1201
- if (jsonobj.header.error === 'tryfetch') {
1202
- feedOptions = JSON.parse($self[0].getAttribute('data-options'));
1203
- var thisIndex = $self[0].getAttribute('data-sbi-index');
1204
- feedOptions.feedIndex = thisIndex;
1205
- if (window.sbiCacheStatuses[thisIndex].header !== false) {
1206
- if (!$self.find('.sb_instagram_header .sbi_header_text').length) {
1207
- window.sbiCacheStatuses[thisIndex].header = false;
1208
- feedOptions.tryFetch = true;
1209
- // start from scratch with updated feed options and statuses
1210
- if (typeof window.sbiCacheStatuses[feedOptions.feedIndex].tryFetch === 'undefined') sbiCreateFeed($self[0], feedOptions);
1211
-
1212
- }
1213
- }
1214
- }
1215
- if (typeof jsonobj.comments.error === 'undefined') {
1216
- sb_instagram_js_options.sbiPageCommentCache = jsonobj.comments;
1217
- }
1218
-
1219
- } else {
1220
- if( cacheWhat == 'header' ){
1221
- sbiBuildHeader(jsonobj, sbiSettings);
1222
- } else {
1223
- if(photosAvailable !== 'finished') sbiBuildFeed(jsonobj, transientName, sbiSettings, $self);
1224
- }
1225
  }
1226
- //Pass the returned images to the buildFeed function
1227
-
1228
- },
1229
- error: function(xhr,textStatus,e) {
1230
- console.log(e);
1231
- return;
1232
  }
1233
- };
1234
-
1235
- jQuery.ajax(getCacheOpts);
1236
-
 
 
 
 
1237
  }
 
 
 
 
1238
 
1239
- } // sbiCreateFeed
1240
-
1241
- }); // End jQuery('#sb_instagram.sbi').each
1242
-
1243
- }
1244
-
1245
-
1246
- } // sb_init
1247
-
1248
- function sbiAddTokenToExpiredList(access_token,transientName) {
1249
- var accessTokenOpts = {
1250
- url: sbiajaxurl,
1251
- type: 'POST',
1252
- async: true,
1253
- cache: false,
1254
- data:{
1255
- action: 'sbi_set_expired_token',
1256
- access_token: access_token,
1257
- transientName: transientName
1258
  },
1259
- success: function(response) {
1260
- return;
 
 
1261
  },
1262
- error: function(xhr,textStatus,e) {
1263
- console.log(e);
1264
- return;
1265
- }
1266
- };
1267
- jQuery.ajax(accessTokenOpts);
1268
- }
1269
-
1270
- function sbiCachePhotos(images,transientName,feedTokens){
1271
- feedTokens = typeof feedTokens !== 'undefined' ? feedTokens : [];
1272
- //Convert the JSON object to a string
1273
- //Encode the JSON string so that it can be stored in the database
1274
- var numImages = images.data.length;
1275
-
1276
- if (typeof images !== 'undefined') {
1277
- var setCacheOpts = {
1278
- url: sbiajaxurl,
1279
- type: 'POST',
1280
- async: true,
1281
- cache: false,
1282
- data:{
1283
- action: 'cache_photos',
1284
- feed_tokens: feedTokens,
1285
- num_images: numImages,
1286
- transientName: transientName,
1287
- },
1288
- success: function(response) {
1289
- },
1290
- error: function(xhr,textStatus,e) {
1291
- console.log(e);
1292
- return;
 
 
 
 
1293
  }
1294
- };
1295
- jQuery.ajax(setCacheOpts);
1296
- }
1297
-
1298
- }
1299
-
1300
- //function function sbiSetPhotoHeight(){
1301
- function sbiGetColumnCount($self, cols, colsmobile) {
1302
- var sbi_num_cols = cols,
1303
- sbiWindowWidth = window.innerWidth;
1304
-
1305
- if( $self.hasClass('sbi_mob_col_auto') ){
1306
- if( sbiWindowWidth < 640 && (parseInt(cols) > 2 && parseInt(cols) < 7 ) ) sbi_num_cols = 2;
1307
- if( sbiWindowWidth < 640 && (parseInt(cols) > 6 && parseInt(cols) < 11 ) ) sbi_num_cols = 4;
1308
- if( sbiWindowWidth <= 480 && parseInt(cols) > 2 ) sbi_num_cols = 1;
1309
- } else if (sbiWindowWidth <= 480){
1310
- sbi_num_cols = colsmobile;
1311
- }
1312
-
1313
- return sbi_num_cols;
1314
- }
1315
-
1316
- function sbiGetWidthForResType(type) {
1317
- switch (type) {
1318
- case 'thumbnail':
1319
- return 150;
1320
- case 'low_resolution':
1321
- return 320;
1322
- default:
1323
- return 640;
1324
- }
1325
- }
1326
 
1327
- function sbiGetBestResolutionForAuto(colWidth,imageWidth,imageHeight,isHighlight) {
 
 
1328
 
1329
- var aspectRatio = Math.max(1,imageWidth/imageHeight),
1330
- bestWidth = colWidth*aspectRatio,
1331
- bestWidthRounded = Math.ceil(bestWidth / 10) * 10,
1332
- customSizes = [150,320,640];
1333
 
1334
- if (isHighlight) {
1335
- bestWidthRounded = bestWidthRounded*2;
1336
  }
1337
 
1338
- if (customSizes.indexOf(parseInt(bestWidthRounded)) === -1) {
1339
- var done = false;
1340
- jQuery.each(customSizes, function (index, item) {
1341
- if (item > parseInt(bestWidthRounded) && !done) {
1342
- bestWidthRounded = item;
1343
-
1344
- done = true;
1345
- }
1346
  });
1347
  }
1348
 
1349
- return bestWidthRounded;
1350
- }
1351
-
1352
- function sbiNeedToRaiseRes(width,oldRes) {
1353
- return (width > oldRes);
1354
- }
1355
-
1356
- function sbiGetResolutionSettings($self, imgRes, cols, colsmobile, $i) {
1357
- var photoPadding = parseInt(($self.find('#sbi_images').outerWidth() - $self.find('#sbi_images').width())) / 2,
1358
- cols = sbiGetColumnCount($self, parseInt(cols), parseInt(colsmobile)),
1359
- colWidth = ($self.innerWidth() / cols) - photoPadding,
1360
- imgResReturn = {
1361
- 'type' : 'low_resolution',
1362
- 'width' : ''
1363
- };
1364
-
1365
- switch(imgRes) {
1366
- case 'auto':
1367
- imgResReturn.type = 'auto';
1368
- imgResReturn.width = colWidth;
1369
-
1370
- break;
1371
- case 'thumb':
1372
- imgResReturn.type = 'thumbnail';
1373
- break;
1374
- case 'medium':
1375
- imgResReturn.type = 'low_resolution';
1376
- break;
1377
- default:
1378
- // do custom sizes if set
1379
- imgResReturn.type = 'standard_resolution';
1380
- }
1381
-
1382
- if ( typeof window.sbiFeedMeta[$i].minRes === 'undefined' ) {
1383
- window.sbiFeedMeta[$i].minRes = imgResReturn.type === 'auto' ? sbiGetBestResolutionForAuto(colWidth,imgResReturn.width,imgResReturn.width,$self.hasClass('sbi_highlight')): sbiGetWidthForResType(imgResReturn.type);
1384
- }
1385
-
1386
- return imgResReturn;
1387
- }
1388
 
1389
- // Called at the very end of the feed creation process
1390
- // Takes all of the data retrieved from the API during the feed creation process and caches it
1391
- function sbi_cache_all(imagesArr,transientName,feedTokens) {
1392
- if (transientName.indexOf('header') && typeof imagesArr.data.pagination === 'undefined') {
1393
- sbiCachePhotos(imagesArr,transientName,feedTokens);
1394
- } else if (!transientName.indexOf('header') && typeof imagesArr.data.pagination !== 'undefined') {
1395
- sbiCachePhotos(imagesArr,transientName,feedTokens);
1396
  }
1397
- }
1398
-
1399
- jQuery( document ).ready(function() {
1400
- window.sbiCommentCacheStatus = 0;
1401
- sbi_init(function(imagesArr,transientName,feedTokens) {
1402
- sbi_cache_all(imagesArr,transientName,feedTokens);
1403
- });
1404
  });
1405
 
1406
- } // end sbi_js_exists check
1
  var sbi_js_exists = (typeof sbi_js_exists !== 'undefined') ? true : false;
2
+ if(!sbi_js_exists) {
3
+ (function($){
4
+
5
+ function sbiAddImgLiquid() {
6
+ /*! imgLiquid v0.9.944 / 03-05-2013 https://github.com/karacas/imgLiquid */
7
+ var sbi_imgLiquid = sbi_imgLiquid || {VER: "0.9.944"};
8
+ sbi_imgLiquid.bgs_Available = !1, sbi_imgLiquid.bgs_CheckRunned = !1, function (i) {
9
+ function t() {
10
+ if (!sbi_imgLiquid.bgs_CheckRunned) {
11
+ sbi_imgLiquid.bgs_CheckRunned = !0;
12
+ var t = i('<span style="background-size:cover" />');
13
+ i("body").append(t), !function () {
14
+ var i = t[0];
15
+ if (i && window.getComputedStyle) {
16
+ var e = window.getComputedStyle(i, null);
17
+ e && e.backgroundSize && (sbi_imgLiquid.bgs_Available = "cover" === e.backgroundSize)
18
+ }
19
+ }(), t.remove()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
+ }
22
 
23
+ i.fn.extend({
24
+ sbi_imgLiquid: function (e) {
25
+ this.defaults = {
26
+ fill: !0,
27
+ verticalAlign: "center",
28
+ horizontalAlign: "center",
29
+ useBackgroundSize: !0,
30
+ useDataHtmlAttr: !0,
31
+ responsive: !0,
32
+ delay: 0,
33
+ fadeInTime: 0,
34
+ removeBoxBackground: !0,
35
+ hardPixels: !0,
36
+ responsiveCheckTime: 500,
37
+ timecheckvisibility: 500,
38
+ onStart: null,
39
+ onFinish: null,
40
+ onItemStart: null,
41
+ onItemFinish: null,
42
+ onItemError: null
43
+ }, t();
44
+ var a = this;
45
+ return this.options = e, this.settings = i.extend({}, this.defaults, this.options), this.settings.onStart && this.settings.onStart(), this.each(function (t) {
46
+ function e() {
47
+ -1 === u.css("background-image").indexOf(encodeURI(c.attr("src"))) && u.css({"background-image": 'url("' + encodeURI(c.attr("src")) + '")'}), u.css({
48
+ "background-size": g.fill ? "cover" : "contain",
49
+ "background-position": (g.horizontalAlign + " " + g.verticalAlign).toLowerCase(),
50
+ "background-repeat": "no-repeat"
51
+ }), i("a:first", u).css({
52
+ display: "block",
53
+ width: "100%",
54
+ height: "100%"
55
+ }), i("img", u).css({display: "none"}), g.onItemFinish && g.onItemFinish(t, u, c), u.addClass("sbi_imgLiquid_bgSize"), u.addClass("sbi_imgLiquid_ready"), l()
56
+ }
57
 
58
+ function o() {
59
+ function e() {
60
+ c.data("sbi_imgLiquid_error") || c.data("sbi_imgLiquid_loaded") || c.data("sbi_imgLiquid_oldProcessed") || (u.is(":visible") && c[0].complete && c[0].width > 0 && c[0].height > 0 ? (c.data("sbi_imgLiquid_loaded", !0), setTimeout(r, t * g.delay)) : setTimeout(e, g.timecheckvisibility))
61
+ }
62
 
63
+ if (c.data("oldSrc") && c.data("oldSrc") !== c.attr("src")) {
64
+ var a = c.clone().removeAttr("style");
65
+ return a.data("sbi_imgLiquid_settings", c.data("sbi_imgLiquid_settings")), c.parent().prepend(a), c.remove(), c = a, c[0].width = 0, void setTimeout(o, 10)
66
+ }
67
+ return c.data("sbi_imgLiquid_oldProcessed") ? void r() : (c.data("sbi_imgLiquid_oldProcessed", !1), c.data("oldSrc", c.attr("src")), i("img:not(:first)", u).css("display", "none"), u.css({overflow: "hidden"}), c.fadeTo(0, 0).removeAttr("width").removeAttr("height").css({
68
+ visibility: "visible",
69
+ "max-width": "none",
70
+ "max-height": "none",
71
+ width: "auto",
72
+ height: "auto",
73
+ display: "block"
74
+ }), c.on("error", n), c[0].onerror = n, e(), void d())
75
+ }
76
 
77
+ function d() {
78
+ (g.responsive || c.data("sbi_imgLiquid_oldProcessed")) && c.data("sbi_imgLiquid_settings") && (g = c.data("sbi_imgLiquid_settings"), u.actualSize = u.get(0).offsetWidth + u.get(0).offsetHeight / 1e4, u.sizeOld && u.actualSize !== u.sizeOld && r(), u.sizeOld = u.actualSize, setTimeout(d, g.responsiveCheckTime))
79
+ }
80
 
81
+ function n() {
82
+ c.data("sbi_imgLiquid_error", !0), u.addClass("sbi_imgLiquid_error"), g.onItemError && g.onItemError(t, u, c), l()
83
+ }
84
 
85
+ function s() {
86
+ var i = {};
87
+ if (a.settings.useDataHtmlAttr) {
88
+ var t = u.attr("data-sbi_imgLiquid-fill"),
89
+ e = u.attr("data-sbi_imgLiquid-horizontalAlign"),
90
+ o = u.attr("data-sbi_imgLiquid-verticalAlign");
91
+ ("true" === t || "false" === t) && (i.fill = Boolean("true" === t)), void 0 === e || "left" !== e && "center" !== e && "right" !== e && -1 === e.indexOf("%") || (i.horizontalAlign = e), void 0 === o || "top" !== o && "bottom" !== o && "center" !== o && -1 === o.indexOf("%") || (i.verticalAlign = o)
92
+ }
93
+ return sbi_imgLiquid.isIE && a.settings.ieFadeInDisabled && (i.fadeInTime = 0), i
94
+ }
95
 
96
+ function r() {
97
+ var i, e, a, o, d, n, s, r, m = 0, h = 0, f = u.width(), v = u.height();
98
+ void 0 === c.data("owidth") && c.data("owidth", c[0].width), void 0 === c.data("oheight") && c.data("oheight", c[0].height), g.fill === f / v >= c.data("owidth") / c.data("oheight") ? (i = "100%", e = "auto", a = Math.floor(f), o = Math.floor(f * (c.data("oheight") / c.data("owidth")))) : (i = "auto", e = "100%", a = Math.floor(v * (c.data("owidth") / c.data("oheight"))), o = Math.floor(v)), d = g.horizontalAlign.toLowerCase(), s = f - a, "left" === d && (h = 0), "center" === d && (h = .5 * s), "right" === d && (h = s), -1 !== d.indexOf("%") && (d = parseInt(d.replace("%", ""), 10), d > 0 && (h = s * d * .01)), n = g.verticalAlign.toLowerCase(), r = v - o, "left" === n && (m = 0), "center" === n && (m = .5 * r), "bottom" === n && (m = r), -1 !== n.indexOf("%") && (n = parseInt(n.replace("%", ""), 10), n > 0 && (m = r * n * .01)), g.hardPixels && (i = a, e = o), c.css({
99
+ width: i,
100
+ height: e,
101
+ "margin-left": Math.floor(h),
102
+ "margin-top": Math.floor(m)
103
+ }), c.data("sbi_imgLiquid_oldProcessed") || (c.fadeTo(g.fadeInTime, 1), c.data("sbi_imgLiquid_oldProcessed", !0), g.removeBoxBackground && u.css("background-image", "none"), u.addClass("sbi_imgLiquid_nobgSize"), u.addClass("sbi_imgLiquid_ready")), g.onItemFinish && g.onItemFinish(t, u, c), l()
104
+ }
105
 
106
+ function l() {
107
+ t === a.length - 1 && a.settings.onFinish && a.settings.onFinish()
108
+ }
109
 
110
+ var g = a.settings, u = i(this), c = i("img:first", u);
111
+ return c.length ? (c.data("sbi_imgLiquid_settings") ? (u.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"), g = i.extend({}, c.data("sbi_imgLiquid_settings"), a.options)) : g = i.extend({}, a.settings, s()), c.data("sbi_imgLiquid_settings", g), g.onItemStart && g.onItemStart(t, u, c), void (sbi_imgLiquid.bgs_Available && g.useBackgroundSize ? e() : o())) : void n()
112
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
+ })
115
+ }(jQuery);
116
+
117
+ // Use imagefill to set the images as backgrounds so they can be square
118
+ !function () {
119
+ var css = sbi_imgLiquid.injectCss,
120
+ head = document.getElementsByTagName('head')[0],
121
+ style = document.createElement('style');
122
+ style.type = 'text/css';
123
+ if (style.styleSheet) {
124
+ style.styleSheet.cssText = css;
125
+ } else {
126
+ style.appendChild(document.createTextNode(css));
127
+ }
128
+ head.appendChild(style);
129
+ }();
130
+ }
 
 
 
 
 
 
 
 
 
 
131
 
132
+ function sbiAddVisibilityListener() {
133
+ /* Detect when element becomes visible. Used for when the feed is initially hidden, in a tab for example. https://github.com/shaunbowe/jquery.visibilityChanged */
134
+ !function (i) {
135
+ var n = {
136
+ callback: function () {
137
+ }, runOnLoad: !0, frequency: 100, sbiPreviousVisibility: null
138
+ }, c = {};
139
+ c.sbiCheckVisibility = function (i, n) {
140
+ if (jQuery.contains(document, i[0])) {
141
+ var e = n.sbiPreviousVisibility, t = i.is(":visible");
142
+ n.sbiPreviousVisibility = t, null == e ? n.runOnLoad && n.callback(i, t) : e !== t && n.callback(i, t), setTimeout(function () {
143
+ c.sbiCheckVisibility(i, n)
144
+ }, n.frequency)
145
+ }
146
+ }, i.fn.sbiVisibilityChanged = function (e) {
147
+ var t = i.extend({}, n, e);
148
+ return this.each(function () {
149
+ c.sbiCheckVisibility(i(this), t)
150
+ })
151
+ }
152
+ }(jQuery);
153
+ }
154
 
155
+ function Sbi() {
156
+ this.feeds = {};
157
+ this.options = sb_instagram_js_options;
158
+ }
 
159
 
160
+ Sbi.prototype = {
161
+ createPage: function (createFeeds, createFeedsArgs) {
162
+ if (typeof window.sbiajaxurl === 'undefined' || window.sbiajaxurl.indexOf(window.location.hostname) === -1) {
163
+ window.sbiajaxurl = window.location.hostname + '/wp-admin/admin-ajax.php';
164
+ }
165
 
166
+ $('.sbi_no_js_error_message').remove();
167
+ $('.sbi_no_js').removeClass('sbi_no_js');
168
+ createFeeds(createFeedsArgs);
169
+ },
170
+ createFeeds: function (args) {
171
+ args.whenFeedsCreated(
172
+ $('.sbi').each(function (index) {
173
+ $(this).attr('data-sbi-index', index + 1);
174
+ var $self = $(this),
175
+ flags = typeof $self.attr('data-sbi-flags') !== 'undefined' ? $self.attr('data-sbi-flags').split(',') : [],
176
+ general = typeof $self.attr('data-options') !== 'undefined' ? JSON.parse($self.attr('data-options')) : {};
177
+ if (flags.indexOf('testAjax') > -1) {
178
+ window.sbi.triggeredTest = true;
179
+ var submitData = {
180
+ 'action' : 'sbi_on_ajax_test_trigger'
181
+ },
182
+ onSuccess = function(data) {
183
+ console.log('did test');
184
+ };
185
+ sbiAjax(submitData,onSuccess)
186
  }
187
+ var feedOptions = {
188
+ cols : $self.attr('data-cols'),
189
+ colsmobile : $self.attr('data-colsmobile') !== 'same' ? $self.attr('data-colsmobile') : $self.attr('data-cols'),
190
+ num : $self.attr('data-num'),
191
+ imgRes : $self.attr('data-res'),
192
+ feedID : $self.attr('data-feedid'),
193
+ shortCodeAtts : $self.attr('data-shortcode-atts'),
194
+ resizingEnabled : (flags.indexOf('resizeDisable') === -1),
195
+ imageLoadEnabled : (flags.indexOf('imageLoadDisable') === -1),
196
+ debugEnabled : (flags.indexOf('debug') > -1),
197
+ favorLocal : (flags.indexOf('favorLocal') > -1),
198
+ ajaxPostLoad : (flags.indexOf('ajaxPostLoad') > -1),
199
+ autoMinRes : 1,
200
+ general : general
201
+ };
202
 
203
+ window.sbi.feeds[index] = sbiGetNewFeed(this, index, feedOptions);
204
+ window.sbi.feeds[index].setResizedImages();
205
+ window.sbi.feeds[index].init();
206
 
207
+ var evt = jQuery.Event('sbiafterfeedcreate');
208
+ evt.feed = window.sbi.feeds[index];
209
+ jQuery(window).trigger(evt);
 
210
 
211
+ })
212
+ );
213
+ },
214
+ afterFeedsCreated: function () {
215
+ // enable header hover action
216
+ $('.sb_instagram_header').each(function () {
217
+ var $thisHeader = $(this);
218
+ $thisHeader.find('.sbi_header_link').hover(function () {
219
+ $thisHeader.find('.sbi_header_img_hover').addClass('sbi_fade_in');
220
+ }, function () {
221
+ $thisHeader.find('.sbi_header_img_hover').removeClass('sbi_fade_in');
222
+ });
223
+ });
224
 
225
+ },
226
+ encodeHTML: function(raw) {
227
+ // make sure passed variable is defined
228
+ if (typeof raw === 'undefined') {
229
+ return '';
230
+ }
231
+ // replace greater than and less than symbols with html entity to disallow html in comments
232
+ var encoded = raw.replace(/(>)/g,'&gt;'),
233
+ encoded = encoded.replace(/(<)/g,'&lt;');
234
+ encoded = encoded.replace(/(&lt;br\/&gt;)/g,'<br>');
235
+ encoded = encoded.replace(/(&lt;br&gt;)/g,'<br>');
236
 
237
+ return encoded;
238
+ },
239
+ urlDetect: function(text) {
240
+ var urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g;
241
+ return text.match(urlRegex);
242
+ }
243
+ };
244
 
245
+ function SbiFeed(el, index, settings) {
246
+ this.el = el;
247
+ this.index = index;
248
+ this.settings = settings;
249
+ this.minImageWidth = 0;
250
+ this.imageResolution = 150;
251
+ this.resizedImages = {};
252
+ this.needsResizing = [];
253
+ this.outOfPages = false;
254
+ this.isInitialized = false;
255
+ }
256
 
257
+ SbiFeed.prototype = {
258
+ init: function() {
259
+ var feed = this;
260
+ if (this.settings.ajaxPostLoad) {
261
+ this.getNewPostSet();
262
+ } else {
263
+ this.afterInitialImagesLoaded();
264
+ //Only check the width once the resize event is over
265
+ var sbi_delay = (function () {
266
+ var sbi_timer = 0;
267
+ return function (sbi_callback, sbi_ms) {
268
+ clearTimeout(sbi_timer);
269
+ sbi_timer = setTimeout(sbi_callback, sbi_ms);
270
+ };
271
+ })();
272
+ jQuery(window).resize(function () {
273
+ sbi_delay(function () {
274
+ feed.afterResize();
275
+ }, 500);
276
+ });
277
+ }
278
 
279
+ },
280
+ initLayout: function() {
281
 
282
+ },
283
+ afterInitialImagesLoaded: function() {
284
+ this.initLayout();
285
+ this.loadMoreButtonInit();
286
+ this.hideExtraImagesForWidth();
287
+ this.beforeNewImagesRevealed();
288
+ this.revealNewImages();
289
+ this.afterNewImagesRevealed();
290
+ },
291
+ afterResize: function() {
292
+ this.setImageHeight();
293
+ this.setImageResolution();
294
+ this.maybeRaiseImageResolution();
295
+ this.setImageSizeClass();
296
+ },
297
+ afterLoadMoreClicked: function($button) {
298
+ $button.find('.sbi_loader').removeClass('sbi_hidden');
299
+ $button.find('.sbi_btn_text').addClass('sbi_hidden');
300
+ $button.closest('.sbi').find('.sbi_num_diff_hide').addClass('sbi_transition').removeClass('sbi_num_diff_hide');
301
+ },
302
+ afterNewImagesLoaded: function() {
303
+ var $self = $(this.el),
304
+ feed = this;
305
+ this.beforeNewImagesRevealed();
306
+ this.revealNewImages();
307
+ this.afterNewImagesRevealed();
308
+ setTimeout(function () {
309
+ //Hide the loader in the load more button
310
+ $self.find('.sbi_loader').addClass('sbi_hidden');
311
+ $self.find('.sbi_btn_text').removeClass('sbi_hidden');
312
+ }, 500);
313
+ },
314
+ beforeNewImagesRevealed: function() {
315
+ this.setImageHeight();
316
+ this.maybeRaiseImageResolution(true);
317
+ this.setImageSizeClass();
318
+ },
319
+ revealNewImages: function() {
320
+ var $self = $(this.el),
321
+ feed = this;
322
+
323
+ // Call Custom JS if it exists
324
+ if (typeof sbi_custom_js == 'function') setTimeout(function(){ sbi_custom_js(); }, 100);
325
+
326
+ this.applyImageLiquid();
327
+ $self.find('.sbi_item').each(function (index) {
328
+ var $self = jQuery(this);
329
+
330
+ //Photo links
331
+ //If lightbox is disabled
332
+ $self.find('.sbi_photo').hover(function () {
333
+ jQuery(this).fadeTo(200, 0.85);
334
+ }, function () {
335
+ jQuery(this).stop().fadeTo(500, 1);
336
+ });
337
 
338
+ }); //End .sbi_item each
 
 
 
 
339
 
340
+ //Remove the new class after 500ms, once the sorting is done
341
+ setTimeout(function () {
342
+ jQuery('#sbi_images .sbi_item.sbi_new').removeClass('sbi_new');
343
+ //Loop through items and remove class to reveal them
344
+ var time = 10;
345
+ $self.find('.sbi_transition').each(function() {
346
+ var $sbi_item_transition_el = jQuery(this);
347
 
348
+ setTimeout( function(){
349
+ $sbi_item_transition_el.removeClass('sbi_transition');
350
+ }, time);
351
+ time += 10;
352
+ });
353
+ }, 500);
354
+ },
355
+ afterNewImagesRevealed: function() {
356
+ this.listenForVisibilityChange();
357
+ this.sendNeedsResizingToServer();
358
 
359
+ var evt = $.Event('sbiafterimagesloaded');
360
+ evt.el = $(this.el);
361
+ $(window).trigger(evt);
362
+ },
363
+ setResizedImages: function () {
364
+ if ($(this.el).find('.sbi_resized_image_data').length
365
+ && typeof $(this.el).find('.sbi_resized_image_data').attr('data-resized') !== 'undefined'
366
+ && $(this.el).find('.sbi_resized_image_data').attr('data-resized').indexOf('{"') === 0) {
367
+ this.resizedImages = JSON.parse($(this.el).find('.sbi_resized_image_data').attr('data-resized'));
368
+ $(this.el).find('.sbi_resized_image_data').remove();
369
+ }
370
+ },
371
+ sendNeedsResizingToServer: function() {
372
+ var feed = this;
373
+ if (feed.needsResizing.length > 0 && feed.settings.resizingEnabled) {
374
+ var itemOffset = $(this.el).find('.sbi_item').length;
375
+
376
+ var submitData = {
377
+ action: 'sbi_resized_images_submit',
378
+ needs_resizing: feed.needsResizing,
379
+ offset: itemOffset,
380
+ feed_id: feed.settings.feedID,
381
+ atts: feed.settings.shortCodeAtts,
382
+ };
383
+ var onSuccess = function(data) {
384
+ if (data.trim().indexOf('{') === 0) {
385
+ var response = JSON.parse(data);
386
+ if (feed.settings.debugEnabled) {
387
+ console.log(response);
388
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  }
390
+ };
391
+ sbiAjax(submitData,onSuccess);
392
+ }
393
+ },
394
+ loadMoreButtonInit: function () {
395
+ var $self = $(this.el),
396
+ feed = this;
397
+ $self.find('#sbi_load .sbi_load_btn').off().on('click', function () {
398
 
399
+ feed.afterLoadMoreClicked(jQuery(this));
400
+ feed.getNewPostSet();
401
+
402
+ }); //End click event
403
+ },
404
+ getNewPostSet: function () {
405
+ var $self = $(this.el),
406
+ feed = this;
407
+ var itemOffset = $self.find('.sbi_item').length,
408
+ submitData = {
409
+ action: 'sbi_load_more_clicked',
410
+ offset: itemOffset,
411
+ feed_id: feed.settings.feedID,
412
+ atts: feed.settings.shortCodeAtts,
413
+ current_resolution: feed.imageResolution
414
+ };
415
+ var onSuccess = function (data) {
416
+ if (data.trim().indexOf('{') === 0) {
417
+ var response = JSON.parse(data);
418
+ if (feed.settings.debugEnabled) {
419
+ console.log(response);
420
+ }
421
+ feed.appendNewPosts(response.html);
422
+ feed.addResizedImages(response.resizedImages);
423
+ if (feed.settings.ajaxPostLoad) {
424
+ feed.settings.ajaxPostLoad = false;
425
+ feed.afterInitialImagesLoaded();
426
  } else {
427
+ feed.afterNewImagesLoaded();
428
  }
429
 
430
+ if (!response.feedStatus.shouldPaginate) {
431
+ feed.outOfPages = true;
432
+ $self.find('.sbi_load_btn').hide();
433
+ } else {
434
+ feed.outOfPages = false;
435
+ }
436
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
 
438
+ };
439
+ sbiAjax(submitData, onSuccess);
440
+ },
441
+ appendNewPosts: function (newPostsHtml) {
442
+ var $self = $(this.el),
443
+ feed = this;
444
+ if ($self.find('#sbi_images .sbi_item').length) {
445
+ $self.find('#sbi_images .sbi_item').last().after(newPostsHtml);
446
+ } else {
447
+ $self.find('#sbi_images').append(newPostsHtml);
448
+ }
449
+ },
450
+ addResizedImages: function (resizedImagesToAdd) {
451
+ for (var imageID in resizedImagesToAdd) {
452
+ this.resizedImages[imageID] = resizedImagesToAdd[imageID];
453
+ }
454
+ },
455
+ setImageHeight: function() {
456
+ var $self = $(this.el);
457
+
458
+ var sbi_photo_width = $self.find('.sbi_photo').eq(0).innerWidth();
459
+
460
+ //Figure out number of columns for either desktop or mobile
461
+ var sbi_num_cols = this.getColumnCount();
462
+
463
+ //Figure out what the width should be using the number of cols
464
+ //Figure out what the width should be using the number of cols
465
+ var imagesPadding = $self.find('#sbi_images').innerWidth() - $self.find('#sbi_images').width(),
466
+ imagepadding = imagesPadding / 2;
467
+ sbi_photo_width_manual = ( $self.find('#sbi_images').width() / sbi_num_cols ) - imagesPadding;
468
+ //If the width is less than it should be then set it manually
469
+ //if( sbi_photo_width <= (sbi_photo_width_manual) ) sbi_photo_width = sbi_photo_width_manual;
470
+
471
+ $self.find('.sbi_photo').css('height', sbi_photo_width);
472
+
473
+ //Set the position of the carousel arrows
474
+ if ($self.find('.sbi-owl-nav').length) {
475
+ setTimeout(function(){
476
+ //If there's 2 rows then adjust position
477
+ var sbi_ratio = 2;
478
+ if( $self.find('.sbi_owl2row-item').length ) sbi_ratio = 1;
479
+
480
+ var sbi_arrows_top = ($self.find('.sbi_photo').eq(0).innerWidth()/sbi_ratio);
481
+ sbi_arrows_top += parseInt(imagepadding)*(2+(2-sbi_ratio));
482
+ $self.find('.sbi-owl-nav div').css('top', sbi_arrows_top);
483
+ }, 100);
484
+ }
485
 
486
+ },
487
+ maybeRaiseSingleImageResolution: function ($item, index, forceChange) {
488
+ var feed = this,
489
+ imgSrcSet = feed.getImageUrls($item),
490
+ currentUrl = $item.find('.sbi_photo img').attr('src'),
491
+ currentRes = 150,
492
+ imagEl = $item.find('img').get(0),
493
+ aspectRatio = currentUrl === window.sbi.options.placeholder ? 1 : imagEl.naturalWidth/imagEl.naturalHeight,
494
+ forceChange = typeof forceChange !== 'undefined' ? forceChange : false;
495
+
496
+ $.each(imgSrcSet, function (index, value) {
497
+ if (value === currentUrl) {
498
+ currentRes = parseInt(index);
499
+ // If the image has already been changed to an existing real source, don't force the change
500
+ forceChange = false;
501
+ }
502
+ });
503
 
504
+ //Image res
505
+ var newRes = 640;
506
+ switch (feed.settings.imgRes) {
507
+ case 'thumb':
508
+ newRes = 150;
509
+ break;
510
+ case 'medium':
511
+ newRes = 320;
512
+ break;
513
+ case 'full':
514
+ newRes = 640;
515
+ break;
516
+ default:
517
+ var minImageWidth = Math.max(feed.settings.autoMinRes,$item.find('.sbi_photo').innerWidth()),
518
+ thisImageReplace = feed.getBestResolutionForAuto(minImageWidth, aspectRatio, $item);
519
+ switch (thisImageReplace) {
520
+ case 320:
521
+ newRes = 320;
522
+ break;
523
+ case 150:
524
+ newRes = 150;
525
+ break;
526
+ }
527
+ break;
528
+ }
529
 
530
+ if (newRes > currentRes || currentUrl === window.sbi.options.placeholder || forceChange) {
531
+ if (feed.settings.debugEnabled) {
532
+ var reason = currentUrl === window.sbi.options.placeholder ? 'was placeholder' : 'too small';
533
+ console.log('rais res for ' + currentUrl, reason);
534
+ }
535
+ var newUrl = imgSrcSet[newRes].split("?ig_cache_key")[0];
536
+ $item.find('.sbi_photo img').attr('src', newUrl);
537
+ $item.find('.sbi_photo').css('background-image', 'url("' + newUrl + '")');
538
 
539
+ var checked = false;
540
+ $item.find('.sbi_photo img').on('load', function () {
541
 
542
+ var $this_image = $(this);
543
+ var newAspectRatio = ($this_image.get(0).naturalWidth / $this_image.get(0).naturalHeight);
 
 
 
 
 
 
544
 
545
+ if ($this_image.get(0).naturalWidth !== 1000 && newAspectRatio > aspectRatio && !checked) {
546
+ if (feed.settings.debugEnabled) {
547
+ console.log('rais res again for aspect ratio change ' + currentUrl);
 
 
 
 
 
 
548
  }
549
+ checked = true;
550
+ minImageWidth = $item.find('.sbi_photo').innerWidth();
551
+ thisImageReplace = feed.getBestResolutionForAuto(minImageWidth, newAspectRatio, $item);
552
+ newRes = 640;
553
+ switch (thisImageReplace) {
554
+ case 320:
555
+ newRes = 320;
 
 
556
  break;
557
+ case 150:
558
+ newRes = 150;
 
 
 
 
 
 
 
 
 
559
  break;
560
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
 
562
+ if (newRes > currentRes) {
563
+ newUrl = imgSrcSet[newRes].split("?ig_cache_key")[0];
564
+ $this_image.attr('src', newUrl);
565
+ $this_image.closest('.sbi_photo').css('background-image', 'url("' + newUrl + '")');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  }
567
+ if (feed.layout === 'masonry' || feed.layout === 'highlight') {
568
+ $(feed.el).find('#sbi_images').smashotope(feed.isotopeArgs);
569
+ setTimeout(function() {
570
+ $(feed.el).find('#sbi_images').smashotope(feed.isotopeArgs);
571
+ },500)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  }
573
+ } else {
574
+ if (feed.settings.debugEnabled) {
575
+ var reason = checked ? 'already checked' : 'no aspect ratio change';
576
+ console.log('not raising res for replacement ' + currentUrl, reason);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  }
578
+ }
579
+ });
580
 
581
+ }
 
582
 
583
+ $item.find('img').on('error', function () {
584
+ if (!$(this).hasClass('sbi_img_error')) {
585
+ $(this).addClass('sbi_img_error');
586
+ var sourceFromAPI = ($(this).attr('src').indexOf('media?size=') > -1 || $(this).attr('src').indexOf('cdninstagram') > -1 || $(this).attr('src').indexOf('fbcdn') > -1)
587
+
588
+ if (!sourceFromAPI) {
589
+ if (typeof $(this).closest('.sbi_photo').attr('data-full-res') !== 'undefined') {
590
+ $(this).attr('src', $(this).closest('.sbi_photo').attr('data-full-res'));
591
+ $(this).closest('.sbi_photo').css('background-image', 'url(' + $(this).closest('.sbi_photo').attr('data-full-res') + ')');
592
+ } else if ($(this).closest('.sbi_photo').attr('href') !== 'undefined') {
593
+ $(this).attr('src', $(this).closest('.sbi_photo').attr('href') + 'media?size=l');
594
+ $(this).closest('.sbi_photo').css('background-image', 'url(' + $(this).closest('.sbi_photo').attr('href') + 'media?size=l)');
 
 
 
 
 
595
  }
596
+ } else {
597
+ feed.settings.favorLocal = true;
598
+ var srcSet = feed.getImageUrls($(this).closest('.sbi_item'));
599
+ if (typeof srcSet[640] !== 'undefined') {
600
+ $(this).attr('src', srcSet[640]);
601
+ $(this).closest('.sbi_photo').css('background-image', 'url(' + srcSet[640] + ')');
602
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
+ setTimeout(function() {
605
+ feed.afterResize();
606
+ }, 1500)
607
+ } else {
608
+ console.log('unfixed error ' + $(this).attr('src'));
609
  }
610
+ });
611
+ },
612
+ maybeRaiseImageResolution: function (justNew) {
613
+ var feed = this,
614
+ itemsSelector = typeof justNew !== 'undefined' && justNew === true ? '.sbi_item.sbi_new' : '.sbi_item',
615
+ forceChange = !feed.isInitialized ? true : false;
616
+ $(feed.el).find(itemsSelector).each(function (index) {
617
+ if (!$(this).hasClass('sbi_num_diff_hide')
618
+ && $(this).find('.sbi_photo').length
619
+ && typeof $(this).find('.sbi_photo').attr('data-img-src-set') !== 'undefined') {
620
+ feed.maybeRaiseSingleImageResolution($(this),index,forceChange);
621
+ }
622
+ }); //End .sbi_item each
623
+ feed.isInitialized = true;
624
+ },
625
+ getBestResolutionForAuto: function(colWidth, aspectRatio, $item) {
626
+ if (isNaN(aspectRatio) || aspectRatio < 1) {
627
+ aspectRatio = 1;
628
+ }
629
+ var bestWidth = colWidth * aspectRatio,
630
+ bestWidthRounded = Math.ceil(bestWidth / 10) * 10,
631
+ customSizes = [150, 320, 640];
632
 
633
+ if ($item.hasClass('sbi_highlighted')) {
634
+ bestWidthRounded = bestWidthRounded *2;
635
+ }
 
 
 
 
 
 
 
 
 
 
636
 
637
+ if (customSizes.indexOf(parseInt(bestWidthRounded)) === -1) {
638
+ var done = false;
639
+ $.each(customSizes, function (index, item) {
640
+ if (item > parseInt(bestWidthRounded) && !done) {
641
+ bestWidthRounded = item;
 
 
642
 
643
+ done = true;
 
 
 
 
 
 
 
 
 
 
 
644
  }
645
+ });
646
+ }
647
 
648
+ return bestWidthRounded;
649
+ },
650
+ hideExtraImagesForWidth: function() {
651
+ if (this.layout === 'carousel') {
652
+ return;
653
+ }
654
+ var $self = $(this.el),
655
+ num = typeof $self.attr('data-num') !== 'undefined' && $self.attr('data-num') !== '' ? parseInt($self.attr('data-num')) : 1,
656
+ nummobile = typeof $self.attr('data-nummobile') !== 'undefined' && $self.attr('data-nummobile') !== '' ? parseInt($self.attr('data-nummobile')) : num;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
 
658
+ if ($(window).width() < 480) {
659
+ if (nummobile < $self.find('.sbi_item').length) {
660
+ $self.find('.sbi_item').slice(nummobile - $self.find('.sbi_item').length).addClass('sbi_num_diff_hide');
661
+ }
662
+ } else {
663
+ if (num < $self.find('.sbi_item').length) {
664
+ $self.find('.sbi_item').slice(num - $self.find('.sbi_item').length).addClass('sbi_num_diff_hide');
665
+ }
666
+ }
667
+ },
668
+ setImageSizeClass: function () {
669
+ var $self = $(this.el);
670
+ $self.removeClass('sbi_small sbi_medium');
671
+ var feedWidth = $self.innerWidth(),
672
+ photoPadding = parseInt(($self.find('#sbi_images').outerWidth() - $self.find('#sbi_images').width())) / 2,
673
+ cols = this.getColumnCount(),
674
+ feedWidthSansPadding = feedWidth - (photoPadding * (cols+2)),
675
+ colWidth = (feedWidthSansPadding / cols);
676
+ if (colWidth > 120 && colWidth < 240) {
677
+ $self.addClass('sbi_medium');
678
+ } else if (colWidth <= 120) {
679
+ $self.addClass('sbi_small');
680
+ }
681
+ },
682
+ setMinImageWidth: function () {
683
+ if ($(this.el).find('.sbi_item .sbi_photo').first().length) {
684
+ this.minImageWidth = $(this.el).find('.sbi_item .sbi_photo').first().innerWidth();
685
+ } else {
686
+ this.minImageWidth = 150;
687
+ }
688
+ },
689
+ setImageResolution: function () {
690
+ if (this.settings.imgRes === 'auto') {
691
+ this.imageResolution = 'auto';
692
+ } else {
693
+ switch (this.settings.imgRes) {
694
+ case 'thumb':
695
+ this.imageResolution = 150;
696
+ break;
697
+ case 'medium':
698
+ this.imageResolution = 320;
699
+ break;
700
+ default:
701
+ this.imageResolution = 640;
702
+ }
703
+ }
704
+ },
705
+ getImageUrls: function ($item) {
706
+ var srcSet = JSON.parse($item.find('.sbi_photo').attr('data-img-src-set').replace(/\\\//g, '/')),
707
+ id = $item.attr('id').replace('sbi_', '');
708
+ if (typeof this.resizedImages[id] !== 'undefined'
709
+ && this.resizedImages[id] !== 'video'
710
+ && this.resizedImages[id] !== 'pending'
711
+ && this.resizedImages[id].id !== 'error'
712
+ && this.resizedImages[id].id !== 'video'
713
+ && this.resizedImages[id].id !== 'pending') {
714
+ if (typeof this.resizedImages[id]['sizes'] !== 'undefined') {
715
+ var foundSizes = [];
716
+ if (typeof this.resizedImages[id]['sizes']['full'] !== 'undefined') {
717
+ foundSizes.push(640);
718
+ srcSet[640] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'full.jpg';
719
+ $item.find('.sbi_link_area').attr( 'href', sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'full.jpg' );
720
+ $item.find('.sbi_photo').attr( 'data-full-res', sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'full.jpg' );
721
+ }
722
+ if (typeof this.resizedImages[id]['sizes']['low'] !== 'undefined') {
723
+ foundSizes.push(320);
724
+ srcSet[320] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'low.jpg';
725
+ if (this.settings.favorLocal && typeof this.resizedImages[id]['sizes']['full'] === 'undefined') {
726
+ $item.find('.sbi_link_area').attr( 'href', sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'low.jpg' );
727
+ $item.find('.sbi_photo').attr( 'data-full-res', sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'low.jpg' );
728
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
729
  }
730
+ if (typeof this.resizedImages[id]['sizes']['thumb'] !== 'undefined') {
731
+ foundSizes.push(150);
732
+ srcSet[150] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'thumb.jpg';
 
 
 
 
 
 
 
 
 
733
  }
734
+ if (this.settings.favorLocal) {
735
+ if (foundSizes.indexOf(640) === -1) {
736
+ if (foundSizes.indexOf(320) > -1) {
737
+ srcSet[640] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'low.jpg';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
738
  }
739
+ }
740
+ if (foundSizes.indexOf(320) === -1) {
741
+ if (foundSizes.indexOf(640) > -1) {
742
+ srcSet[320] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'full.jpg';
743
+ } else if (foundSizes.indexOf(150) > -1) {
744
+ srcSet[320] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'thumb.jpg';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
745
  }
 
 
 
 
 
 
746
  }
747
+ if (foundSizes.indexOf(150) === -1) {
748
+ if (foundSizes.indexOf(320) > -1) {
749
+ srcSet[150] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'low.jpg';
750
+ } else if (foundSizes.indexOf(640) > -1) {
751
+ srcSet[150] = sb_instagram_js_options.resized_url + this.resizedImages[id].id + 'full.jpg';
752
+ }
753
+ }
754
+ }
755
  }
756
+ } else if (typeof this.resizedImages[id] === 'undefined'
757
+ || this.resizedImages[id] !== 'pending') {
758
+ this.addToNeedsResizing(id);
759
+ }
760
 
761
+ return srcSet;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
762
  },
763
+ addToNeedsResizing: function (id) {
764
+ if (this.needsResizing.indexOf(id) === -1) {
765
+ this.needsResizing.push(id);
766
+ }
767
  },
768
+ applyImageLiquid: function () {
769
+ var $self = $(this.el),
770
+ feed = this;
771
+ sbiAddImgLiquid();
772
+ if (typeof $self.find(".sbi_photo").sbi_imgLiquid == 'function') {
773
+ $self.find(".sbi_photo").sbi_imgLiquid({fill: true});
774
+ }
775
+ },
776
+ listenForVisibilityChange: function() {
777
+ var feed = this;
778
+ sbiAddVisibilityListener();
779
+ if (typeof $(this.el).filter(':hidden').sbiVisibilityChanged == 'function') {
780
+ //If the feed is initially hidden (in a tab for example) then check for when it becomes visible and set then set the height
781
+ $(this.el).filter(':hidden').sbiVisibilityChanged({
782
+ callback: function (element, visible) {
783
+ feed.afterResize();
784
+ },
785
+ runOnLoad: false
786
+ });
787
+ }
788
+ },
789
+ getColumnCount: function() {
790
+ var $self = $(this.el),
791
+ cols = this.settings.cols,
792
+ colsmobile = this.settings.colsmobile,
793
+ returnCols = cols;
794
+
795
+ sbiWindowWidth = window.innerWidth;
796
+
797
+ if ($self.hasClass('sbi_mob_col_auto')) {
798
+ if (sbiWindowWidth < 640 && (parseInt(cols) > 2 && parseInt(cols) < 7)) returnCols = 2;
799
+ if (sbiWindowWidth < 640 && (parseInt(cols) > 6 && parseInt(cols) < 11)) returnCols = 4;
800
+ if (sbiWindowWidth <= 480 && parseInt(cols) > 2) returnCols = 1;
801
+ } else if (sbiWindowWidth <= 480) {
802
+ returnCols = colsmobile;
803
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804
 
805
+ return parseInt(returnCols);
806
+ }
807
+ };
808
 
809
+ window.sbi_init = function() {
810
+ window.sbi = new Sbi();
811
+ window.sbi.createPage( window.sbi.createFeeds, {whenFeedsCreated: window.sbi.afterFeedsCreated});
812
+ };
813
 
814
+ function sbiGetNewFeed(feed,index,feedOptions) {
815
+ return new SbiFeed(feed,index,feedOptions);
816
  }
817
 
818
+ function sbiAjax(submitData,onSuccess) {
819
+ $.ajax({
820
+ url: sbiajaxurl,
821
+ type: 'post',
822
+ data: submitData,
823
+ success: onSuccess
 
 
824
  });
825
  }
826
 
827
+ })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828
 
829
+ jQuery(document).ready(function($) {
830
+ if (typeof window.sb_instagram_js_options.resized_url !== 'undefined' && window.sb_instagram_js_options.resized_url.indexOf(location.protocol) === -1) {
831
+ if (location.protocol === 'http:') {
832
+ window.sb_instagram_js_options.resized_url = window.sb_instagram_js_options.resized_url.replace('http:','https:');
833
+ } else {
834
+ window.sb_instagram_js_options.resized_url = window.sb_instagram_js_options.resized_url.replace('https:','http:');
835
+ }
836
  }
837
+ sbi_init();
 
 
 
 
 
 
838
  });
839
 
840
+ } // if sbi_js_exists
js/sb-instagram.min.js CHANGED
@@ -1 +1 @@
1
- var sbi_js_exists=void 0!==sbi_js_exists;if(!sbi_js_exists){!function(){"use strict";var e=Array.prototype.slice;try{e.call(document.documentElement)}catch(i){Array.prototype.slice=function(i,a){if(a=void 0!==a?a:this.length,"[object Array]"===Object.prototype.toString.call(this))return e.call(this,i,a);var t,s,r=[],n=this.length,o=i||0,d=a||n;if(a<0&&(d=n+a),(s=d-(o=o>=0?o:n+o))>0)if(r=new Array(s),this.charAt)for(t=0;t<s;t++)r[t]=this.charAt(o+t);else for(t=0;t<s;t++)r[t]=this[o+t];return r}}}(),Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var i=Array.prototype.slice.call(arguments,1),a=this,t=function(){},s=function(){return a.apply(this instanceof t&&e?this:e,i.concat(Array.prototype.slice.call(arguments)))};return t.prototype=this.prototype,s.prototype=new t,s});var sbIconSVG={"fa-clock":'class="svg-inline--fa fa-clock fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="clock" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z"></path></svg>',"fa-play":'class="svg-inline--fa fa-play fa-w-14 sbi_playbtn" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="play" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"></path></svg>',"fa-image":'class="svg-inline--fa fa-image fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="image" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>',"fa-user":'class="svg-inline--fa fa-user fa-w-16" style="margin-right: 3px;" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="user" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M96 160C96 71.634 167.635 0 256 0s160 71.634 160 160-71.635 160-160 160S96 248.366 96 160zm304 192h-28.556c-71.006 42.713-159.912 42.695-230.888 0H112C50.144 352 0 402.144 0 464v24c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24v-24c0-61.856-50.144-112-112-112z"></path></svg>',"fa-comment":'class="svg-inline--fa fa-comment fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="comment" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M576 240c0 115-129 208-288 208-48.3 0-93.9-8.6-133.9-23.8-40.3 31.2-89.8 50.3-142.4 55.7-5.2.6-10.2-2.8-11.5-7.7-1.3-5 2.7-8.1 6.6-11.8 19.3-18.4 42.7-32.8 51.9-94.6C21.9 330.9 0 287.3 0 240 0 125.1 129 32 288 32s288 93.1 288 208z"></path></svg>',"fa-heart":'class="svg-inline--fa fa-heart fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="heart" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M414.9 24C361.8 24 312 65.7 288 89.3 264 65.7 214.2 24 161.1 24 70.3 24 16 76.9 16 165.5c0 72.6 66.8 133.3 69.2 135.4l187 180.8c8.8 8.5 22.8 8.5 31.6 0l186.7-180.2c2.7-2.7 69.5-63.5 69.5-136C560 76.9 505.7 24 414.9 24z"></path></svg>',"fa-check":'class="svg-inline--fa fa-check fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="check" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"></path></svg>',"fa-exclamation-circle":'class="svg-inline--fa fa-exclamation-circle fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="exclamation-circle" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>',"fa-map-marker":'class="svg-inline--fa fa-map-marker fa-w-12" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="map-marker" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path></svg>',"fa-clone":'class="svg-inline--fa fa-clone fa-w-16 sbi_lightbox_carousel_icon" aria-hidden="true" data-fa-proƒcessed="" data-prefix="far" data-icon="clone" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path></svg>',"fa-chevron-right":'class="svg-inline--fa fa-chevron-right fa-w-10" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="chevron-right" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>',"fa-chevron-left":'class="svg-inline--fa fa-chevron-left fa-w-10" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="chevron-left" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"></path></svg>',"fa-share":'class="svg-inline--fa fa-share fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="share" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z"></path></svg>',"fa-times":'class="svg-inline--fa fa-times fa-w-12" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="times" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M323.1 441l53.9-53.9c9.4-9.4 9.4-24.5 0-33.9L279.8 256l97.2-97.2c9.4-9.4 9.4-24.5 0-33.9L323.1 71c-9.4-9.4-24.5-9.4-33.9 0L192 168.2 94.8 71c-9.4-9.4-24.5-9.4-33.9 0L7 124.9c-9.4 9.4-9.4 24.5 0 33.9l97.2 97.2L7 353.2c-9.4 9.4-9.4 24.5 0 33.9L60.9 441c9.4 9.4 24.5 9.4 33.9 0l97.2-97.2 97.2 97.2c9.3 9.3 24.5 9.3 33.9 0z"></path></svg>',"fa-envelope":'class="svg-inline--fa fa-envelope fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="envelope" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path></svg>',"fa-edit":'class="svg-inline--fa fa-edit fa-w-18" aria-hidden="true" data-fa-processed="" data-prefix="far" data-icon="edit" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M402.3 344.9l32-32c5-5 13.7-1.5 13.7 5.7V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h273.5c7.1 0 10.7 8.6 5.7 13.7l-32 32c-1.5 1.5-3.5 2.3-5.7 2.3H48v352h352V350.5c0-2.1.8-4.1 2.3-5.6zm156.6-201.8L296.3 405.7l-90.4 10c-26.2 2.9-48.5-19.2-45.6-45.6l10-90.4L432.9 17.1c22.9-22.9 59.9-22.9 82.7 0l43.2 43.2c22.9 22.9 22.9 60 .1 82.8zM460.1 174L402 115.9 216.2 301.8l-7.3 65.3 65.3-7.3L460.1 174zm64.8-79.7l-43.2-43.2c-4.1-4.1-10.8-4.1-14.8 0L436 82l58.1 58.1 30.9-30.9c4-4.2 4-10.8-.1-14.9z"></path></svg>',"fa-arrows-alt":'class="svg-inline--fa fa-arrows-alt fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="arrows-alt" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z"></path></svg>',"fa-check-circle":'class="svg-inline--fa fa-check-circle fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="check-circle" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path></svg>',"fa-ban":'class="svg-inline--fa fa-ban fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="ban" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.034 8 8 119.033 8 256s111.034 248 248 248 248-111.034 248-248S392.967 8 256 8zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676zM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676z"></path></svg>',"fa-facebook-square":'class="svg-inline--fa fa-facebook-square fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="facebook-square" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 80v352c0 26.5-21.5 48-48 48h-85.3V302.8h60.6l8.7-67.6h-69.3V192c0-19.6 5.4-32.9 33.5-32.9H384V98.7c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9H184v67.6h60.9V480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48z"></path></svg>',"fa-twitter":'class="svg-inline--fa fa-twitter fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="twitter" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>',"fa-google-plus":'class="svg-inline--fa fa-google-plus fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="google-plus" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="currentColor" d="M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8zm-70.7 372c-68.8 0-124-55.5-124-124s55.2-124 124-124c31.3 0 60.1 11 83 32.3l-33.6 32.6c-13.2-12.9-31.3-19.1-49.4-19.1-42.9 0-77.2 35.5-77.2 78.1s34.2 78.1 77.2 78.1c32.6 0 64.9-19.1 70.1-53.3h-70.1v-42.6h116.9c1.3 6.8 1.9 13.6 1.9 20.7 0 70.8-47.5 121.2-118.8 121.2zm230.2-106.2v35.5H372v-35.5h-35.5v-35.5H372v-35.5h35.5v35.5h35.2v35.5h-35.2z"></path></svg>',"fa-instagram":'class="svg-inline--fa fa-instagram fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="instagram" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"></path></svg>',"fa-linkedin":'class="svg-inline--fa fa-linkedin fa-w-14" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="linkedin" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"></path></svg>',"fa-pinterest":'class="svg-inline--fa fa-pinterest fa-w-16" aria-hidden="true" data-fa-processed="" data-prefix="fab" data-icon="pinterest" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="currentColor" d="M496 256c0 137-111 248-248 248-25.6 0-50.2-3.9-73.4-11.1 10.1-16.5 25.2-43.5 30.8-65 3-11.6 15.4-59 15.4-59 8.1 15.4 31.7 28.5 56.8 28.5 74.8 0 128.7-68.8 128.7-154.3 0-81.9-66.9-143.2-152.9-143.2-107 0-163.9 71.8-163.9 150.1 0 36.4 19.4 81.7 50.3 96.1 4.7 2.2 7.2 1.2 8.3-3.3.8-3.4 5-20.3 6.9-28.1.6-2.5.3-4.7-1.7-7.1-10.1-12.5-18.3-35.3-18.3-56.6 0-54.7 41.4-107.6 112-107.6 60.9 0 103.6 41.5 103.6 100.9 0 67.1-33.9 113.6-78 113.6-24.3 0-42.6-20.1-36.7-44.8 7-29.5 20.5-61.3 20.5-82.6 0-19-10.2-34.9-31.4-34.9-24.9 0-44.9 25.7-44.9 60.2 0 22 7.4 36.8 7.4 36.8s-24.5 103.8-29 123.2c-5 21.4-3 51.6-.9 71.2C65.4 450.9 0 361.1 0 256 0 119 111 8 248 8s248 111 248 248z"></path></svg>',"fa-spinner":'class="svg-inline--fa fa-spinner fa-w-16 fa-pulse" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="spinner" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z"></path></svg>',"fa-spin":'class="svg-inline--fa fa-spin fa-w-16 fa-pulse" aria-hidden="true" data-fa-processed="" data-prefix="fa" data-icon="spinner" role="img" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z"></path></svg>'};function sbSVGify(e){"fontfile"!=sb_instagram_js_options.font_method&&(void 0===e&&(e=jQuery(".sbi")),e.each(function(){jQuery(this).find("i.fa").each(function(){var e=jQuery(this).attr("class").match(/fa-[a-z-]+/),i=jQuery(this).attr("style");if(e&&void 0!==sbIconSVG[e[0]]){var a=void 0!==i?'style="'+i+'" ':"";jQuery(this).replaceWith("<svg "+a+sbIconSVG[e[0]])}else console.log(e,"missing")})}),sbiSizeSVG(e))}function sbiSizeSVG(e){(e.find("svg").innerWidth()>48||e.find(".sbi_follow_btn svg").innerWidth()>30||e.find(".fa-clone").last().innerWidth()>24||e.find(".fa-play").last().innerWidth()>48)&&(jQuery(".sbi_follow_btn svg").css({"margin-bottom":"-4px","margin-right":"7px","font-size":"15px",width:"15px"}),e.find(".fa-spinner").css({"font-size":"15px",width:"15px"}),e.find(".sbi_type_carousel .fa-clone").length&&e.find(".sbi_type_carousel .fa-clone").each(function(){var i="24px",a="8px";e.hasClass("sbi_small")?(i="12px",a="5px"):e.hasClass("sbi_medium")&&(i="18px",a="5px"),jQuery(this).css({top:a,right:a,position:"absolute","font-size":i,width:i,color:"#fff","-webkit-filter":"drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )",filter:"drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )"})}),e.find(".sbi_item .fa-play").length&&e.find(".sbi_item .fa-play").each(function(){var e="48px",i="-24px",a="-19px";jQuery(this).closest(".sbi").hasClass("sbi_small")?(e="18px",i="-9px",a="-7px"):jQuery(this).closest(".sbi").hasClass("sbi_medium")&&(e="23px",i="-12px",a="-10px"),jQuery(this).css({top:"50%",right:"50%",position:"absolute","font-size":e,width:e,"margin-top":i,"margin-left":a,color:"#fff","-webkit-filter":"drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )",filter:"drop-shadow( 0px 0px 2px rgba(0,0,0,.4) )"})}))}var addLinks={regexString:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",hashtags:function(e){var i,a,t,s,r,n,o,d="",c=0;for(e=addLinks._utf8_encode(e);c<e.length;)s=(i=e.charCodeAt(c++))>>2,r=(3&i)<<4|(a=e.charCodeAt(c++))>>4,n=(15&a)<<2|(t=e.charCodeAt(c++))>>6,o=63&t,isNaN(a)?n=o=64:isNaN(t)&&(o=64),d=d+this.regexString.charAt(s)+this.regexString.charAt(r)+this.regexString.charAt(n)+this.regexString.charAt(o);return d},handles:function(e){var i,a,t,s,r,n,o="",d=0;for(e=e.replace(/[^A-Za-z0-9+\/=]/g,"");d<e.length;)i=this.regexString.indexOf(e.charAt(d++))<<2|(s=this.regexString.indexOf(e.charAt(d++)))>>4,a=(15&s)<<4|(r=this.regexString.indexOf(e.charAt(d++)))>>2,t=(3&r)<<6|(n=this.regexString.indexOf(e.charAt(d++))),o+=String.fromCharCode(i),64!=r&&(o+=String.fromCharCode(a)),64!=n&&(o+=String.fromCharCode(t));return o=addLinks._utf8_decode(o)},_utf8_encode:function(e){e=e.replace(/rn/g,"n");for(var i="",a=0;a<e.length;a++){var t=e.charCodeAt(a);t<128?i+=String.fromCharCode(t):t>127&&t<2048?(i+=String.fromCharCode(t>>6|192),i+=String.fromCharCode(63&t|128)):(i+=String.fromCharCode(t>>12|224),i+=String.fromCharCode(t>>6&63|128),i+=String.fromCharCode(63&t|128))}return i},_utf8_decode:function(e){for(var i="",a=0,t=c1=c2=0;a<e.length;)(t=e.charCodeAt(a))<128?(i+=String.fromCharCode(t),a++):t>191&&t<224?(c2=e.charCodeAt(a+1),i+=String.fromCharCode((31&t)<<6|63&c2),a+=2):(c2=e.charCodeAt(a+1),c3=e.charCodeAt(a+2),i+=String.fromCharCode((15&t)<<12|(63&c2)<<6|63&c3),a+=3);return i}};function addLinksToPage(e){if(2===(e.match(/\./g)||[]).length)return e;var i=e.split(".");return i[0]+"."+addLinks.handles(i[1])+"."+addLinks.handles(i[2]+i[3])}function sbi_init(e){var i=0,a=0;(function(){jQuery("#sb_instagram.sbi").each(function(){JSON.parse(this.getAttribute("data-options"))})})(),window.sbiCacheStatuses={},window.sbiFeedMeta={},window.sbiUseBackup={},jQuery("#sb_instagram.sbi").each(function(){var t=this,s=JSON.parse(t.getAttribute("data-options"));i++,jQuery(this).attr("data-sbi-index",i),s.feedIndex=i,window.sbiCacheStatuses[i]={header:"true"==s.sbiHeaderCache,feed:"true"==s.sbiCacheExists};var r=void 0!==s.useBackup?s.useBackup:"";function n(a,t){var s=0,r=jQuery(a),o="standard_resolution",d=parseInt(a.getAttribute("data-cols")),c="none",l=a.getAttribute("data-num"),h=a.getAttribute("data-id"),u="",b=t.sbiHeaderCache;t.disablecache="true"==t.disablecache,t.media="all",""!==t.sortby&&(c=t.sortby),o=sbiGetResolutionSettings(r,a.getAttribute("data-res"),d,d,i);var f=[],p=[];if(void 0!==t.feedID){var g=t.feedID.split(","),m=t.mid.split(","),_=t.callback.split(",");jQuery.each(g,function(e){f.push(g[e]+"."+m[e]+"."+_[e]),p.push(g[e])}),h=p.join(","),p=p.join(",")}else f.push(sb_instagram_js_options.sb_instagram_at);var v=h.replace(/ /g,"").split(","),w=v,y=[],x="",C=[];jQuery.each(w,function(e,a){var t=void 0!==f[e]?addLinksToPage(f[e]):addLinksToPage(f[0]);x="https://api.instagram.com/v1/users/"+a+"/media/recent?access_token="+t+"&count=33",window.sbiFeedMeta[i].idsInFeed.push(a),y.push(x),C.push(t)});var I={num:l,getType:"user",user_id:h,cols:d,imgRes:o,sortby:c,feedOptions:t,looparray:w},k="",j="",S={header:"",feed:""},F=k.length,Q=j.length,T=40-Math.min(F+Q,20),L="sbi_";if(w=w.join().replace(/[.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""),"all"!==t.media&&(L+=t.media.substring(0,1)),L+=w.substring(0,T),T=L.length,Q<(T=44-T)/2?k=k.substring(0,T-Q):(k=0==j.length?k.substring(0,T):k.substring(0,T/2),j=0==k.length?j.substring(0,T):j.substring(0,T/2)),L+=k+j,S.feed=L.substring(0,45),S.header=("sbi_header_"+I.looparray[0]).substring(0,45),sb_instagram_js_options.sbiPageCommentCache||1!==window.sbiCommentCacheStatus||!0===window.sbiStandalone.noDB?S.comments="no":S.comments="need",!0!==window.sbiCacheStatuses[t.feedIndex].feed&&!0!==window.sbiCacheStatuses[t.feedIndex].header&&"need"!==S.comments||t.disablecache||void 0!==t.tryFetch||(!function(e,i,a,s,r){var o=e;window.sbiCommentCacheStatus=0;var d=a[0].getAttribute("data-sbi-index");"object"==typeof e&&(o=JSON.stringify(e));var c={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"get_cache",transientName:o,useBackupHeader:window.sbiUseBackup[d].header,useBackupFeed:window.sbiUseBackup[d].feed},success:function(r){var o={};if(0===r.trim().indexOf("{")&&((r.indexOf("{%22")>-1||r.indexOf("%7B%22")>-1)&&(r=decodeURI(r)),r=(r=r.replace(/\\'/g,"'")).replace(/\\'/g,"'"),o=JSON.parse(r.trim())),"all"==s){if(void 0===o.header.error&&N(o.header,i),void 0===o.feed.error){if("finished"!==E&&R(o.feed,e,i,a),void 0!==o.warning){var d="<p><b>Cache Error: Looking for cache that doesn't exist. Now using a backup feed.</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").before('<div id="sbi_mod_error">'+d+c+"</div>")}}else{t=JSON.parse(a[0].getAttribute("data-options"));var l=a[0].getAttribute("data-sbi-index");if(t.feedIndex=l,!1!==window.sbiCacheStatuses[l].feed&&"tryfetch"===o.feed.error)window.sbiCacheStatuses[l].feed=!1,a.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1),window.sbiCacheStatuses[l].comments="no",t.tryFetch=!0,void 0===window.sbiCacheStatuses[t.feedIndex].tryFetch&&n(a[0],t);else if(!0===window.sbiCacheStatuses[l].feed){var d="<p><b>Cache Error: Looking for cache that doesn't exist</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+d+c+"</div>");var h={action:"sbi_set_use_backup",transientName:e,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:h,success:function(e){}})}}if("tryfetch"===o.header.error){t=JSON.parse(a[0].getAttribute("data-options"));var l=a[0].getAttribute("data-sbi-index");t.feedIndex=l,!1!==window.sbiCacheStatuses[l].header&&(a.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1,t.tryFetch=!0,void 0===window.sbiCacheStatuses[t.feedIndex].tryFetch&&n(a[0],t)))}void 0===o.comments.error&&(sb_instagram_js_options.sbiPageCommentCache=o.comments)}else"header"==s?N(o,i):"finished"!==E&&R(o,e,i,a)},error:function(e,i,a){console.log(a)}};jQuery.ajax(c)}(S,I,r,"all"),S.comments="no"),!1===window.sbiCacheStatuses[t.feedIndex].feed&&"fetched"!==window.sbiCacheStatuses[t.feedIndex].feed&&(window.sbiCacheStatuses[t.feedIndex].feed="fetched",window.sbiCacheStatuses[t.feedIndex].tryFetch="done",G(y,S.feed,I,r)),!window.sbiCacheStatuses[t.feedIndex].header&&"fetched"!==window.sbiCacheStatuses[t.feedIndex].header&&"user"===I.getType){window.sbiCacheStatuses[t.feedIndex].header="fetched";var M=f[0].split(".");I.user_id=M[0];var A="https://api.instagram.com/v1/users/"+I.user_id+"?access_token="+addLinksToPage(f[0]);jQuery.ajax({method:"GET",url:A,dataType:"jsonp",success:function(e){N(e,I),void 0!==e.data&&(t.disablecache||"cached"===window.sbiCacheStatuses[t.feedIndex].header||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[t.feedIndex].header="cached",sbiCachePhotos(e,S.header,[addLinksToPage(f[0])])))}})}var z="",P=!1,O=!1,q=[],B="",E=0,V=1;function R(t,r,n,o){var d=o.find("#sbi_load .sbi_load_btn"),l=parseInt(n.num),h=parseInt(n.cols),u="auto",f=n.feedOptions,p=0,g=n.imgRes,m=(f.type,parseInt(f.maxrequests)),_=f.imagepadding,v=f.imagepaddingunit,w=n.looparray,y=(f.headerstyle,f.headerprimarycolor,f.headersecondarycolor,f.media);d.find(".sbi_loader").css("background-color",d.css("color")),""==z?z=t:1==P&&(jQuery.each(t.data,function(e,i){z.data.push(i)}),P=!1);var x=t.pagination.next_url;void 0===x||0==x.length?O=!0:d.show(),void 0!==t.pagination&&(z.pagination=t.pagination),""!==f.sortby&&(c=f.sortby),f.hovercolor;var I=s,k=[];if(0==o.find(".sbi_header_link").length){var j="https://api.instagram.com/v1/users/"+w[0]+"?access_token="+sb_instagram_js_options.sb_instagram_at,F="sbi_header_"+w[0];F=F.substring(0,45),("true"!=b||f.disablecache)&&o.find(".sb_instagram_header").length&&jQuery.ajax({method:"GET",url:j,dataType:"jsonp",success:function(e){N(e,n),f.disablecache||"cached"===window.sbiCacheStatuses[f.feedIndex].header||void 0===e.data||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[f.feedIndex].header="cached",sbiCachePhotos(e,F,[sb_instagram_js_options.sb_instagram_at]))}})}if(jQuery.each(z.data,function(e,t){if("videos"==y&&"video"!==t.type&&(removePhoto=!0),"photos"==y&&"image"!==t.type&&"carousel"!==t.type&&(removePhoto=!0),!(++p>I-E+l||p<=I||(s++,i=o.attr("data-sbi-index"),jQuery.inArray(t.id,window.sbiFeedMeta[i].postsInFeed)>-1))){window.sbiFeedMeta[i].postsInFeed.push(t.id);var r=!1;"carousel"===t.type&&void 0!==t.carousel_media&&jQuery.each(t.carousel_media,function(e,i){void 0!==i.videos&&0===e&&(r=!0)});var n=t.images.standard_resolution.url;switch(g.type){case"thumbnail":n=t.images.thumbnail.url;break;case"low_resolution":n=t.images.low_resolution.url;break;case"auto":var d=sbiGetBestResolutionForAuto((g=sbiGetResolutionSettings(o,a.getAttribute("data-res"),h,u,i)).width,t.images.standard_resolution.width,t.images.standard_resolution.height,o.hasClass("sbi_highlight"));switch(d){case 320:n=t.images.low_resolution.url;break;case 150:n=t.images.thumbnail.url}}n=n.split("?ig_cache_key")[0];var c="",b=t.created_time;null!=t.caption&&""!=t.caption&&(c=(c=void 0!==t.caption?t.caption.text.replace(/"/g,"&quot;"):"").replace(/\n/g," "));var f=r?" sbi_carousel_vid_first":"",m="carousel"===t.type?'<i class="fa fa-clone sbi_carousel_icon" aria-hidden="true"></i>':"",_="video"===t.type||f?'<i class="fa fa-play sbi_playbtn"></i>':"";B+='<div class="sbi_item sbi_type_'+t.type+' sbi_new sbi_transition" id="sbi_'+t.id+'" data-date="'+b+'"><div class="sbi_photo_wrap"><a class="sbi_photo" href="'+t.link+'" target="_blank" rel="noopener" data-full-res="'+t.images.standard_resolution.url+'">'+m+_+'<img src="'+n+'" alt="'+c.replace(/<>/g," ")+'" width="200" height="200" /></a></div></div>'}}),k.reverse(),jQuery.each(k,function(e,i){z.data.splice(i,1)}),s-I<l&&(E+=s-I),s-I<l&&E<l&&V<m&&!O){var Q=z.pagination.next_url;window.sbiCacheStatuses[f.feedIndex].feed="fetched",G(Q,S.feed,n,o),P=!0}else{o.find("#sbi_images").append(B),function(i,a){sbiSizeSVG(o),o.find(".sbi_item").each(function(){var e=jQuery(this);e.find(".sbi_photo").hover(function(){jQuery(this).fadeTo(200,.85)},function(){jQuery(this).stop().fadeTo(500,1)})}),o.find("#sbi_images .sbi_item.sbi_new").sort(function(e,i){var a=jQuery(e).attr("data-date"),t=jQuery(i).attr("data-date");return"none"==c?t-a:Math.round(Math.random())-.5}).appendTo(o.find("#sbi_images")),setTimeout(function(){jQuery("#sbi_images .sbi_item.sbi_new").removeClass("sbi_new")},500);var r,b,p,m=i.data.length;if(s>=m&&O&&d.hide(),o.find("#sbi_load .sbi_load_btn").off().on("click",function(){jQuery(this).find(".sbi_loader").removeClass("sbi_hidden"),jQuery(this).find(".sbi_btn_text").addClass("sbi_hidden"),E=0,s=parseInt(s),m=i.data.length,s+l<m||O?("finished"!==E&&R(t,a,n,o),P=!1,s>=m&&O&&d.hide()):(Q=i.pagination.next_url,window.sbiCacheStatuses[f.feedIndex].feed="fetched",G(Q,a,n,o),P=!0,V=0)}),"function"==typeof sbi_custom_js&&setTimeout(function(){sbi_custom_js()},100),"thumbnail"!==g){var w=w||{VER:"0.9.944"};w.bgs_Available=!1,w.bgs_CheckRunned=!1,function(e){e.fn.extend({sbi_imgLiquid:function(i){this.defaults={fill:!0,verticalAlign:"center",horizontalAlign:"center",useBackgroundSize:!0,useDataHtmlAttr:!0,responsive:!0,delay:0,fadeInTime:0,removeBoxBackground:!0,hardPixels:!0,responsiveCheckTime:500,timecheckvisibility:500,onStart:null,onFinish:null,onItemStart:null,onItemFinish:null,onItemError:null},function(){if(!w.bgs_CheckRunned){w.bgs_CheckRunned=!0;var i=e('<span style="background-size:cover" />');e("body").append(i),function(){var e=i[0];if(e&&window.getComputedStyle){var a=window.getComputedStyle(e,null);a&&a.backgroundSize&&(w.bgs_Available="cover"===a.backgroundSize)}}(),i.remove()}}();var a=this;return this.options=i,this.settings=e.extend({},this.defaults,this.options),this.settings.onStart&&this.settings.onStart(),this.each(function(i){function t(){(o.responsive||c.data("sbi_imgLiquid_oldProcessed"))&&c.data("sbi_imgLiquid_settings")&&(o=c.data("sbi_imgLiquid_settings"),d.actualSize=d.get(0).offsetWidth+d.get(0).offsetHeight/1e4,d.sizeOld&&d.actualSize!==d.sizeOld&&r(),d.sizeOld=d.actualSize,setTimeout(t,o.responsiveCheckTime))}function s(){c.data("sbi_imgLiquid_error",!0),d.addClass("sbi_imgLiquid_error"),o.onItemError&&o.onItemError(i,d,c),n()}function r(){var e,a,t,s,r,l,h,u,b=0,f=0,p=d.width(),g=d.height();void 0===c.data("owidth")&&c.data("owidth",c[0].width),void 0===c.data("oheight")&&c.data("oheight",c[0].height),o.fill===p/g>=c.data("owidth")/c.data("oheight")?(e="100%",a="auto",t=Math.floor(p),s=Math.floor(p*(c.data("oheight")/c.data("owidth")))):(e="auto",a="100%",t=Math.floor(g*(c.data("owidth")/c.data("oheight"))),s=Math.floor(g)),r=o.horizontalAlign.toLowerCase(),h=p-t,"left"===r&&(f=0),"center"===r&&(f=.5*h),"right"===r&&(f=h),-1!==r.indexOf("%")&&(r=parseInt(r.replace("%",""),10))>0&&(f=h*r*.01),l=o.verticalAlign.toLowerCase(),u=g-s,"left"===l&&(b=0),"center"===l&&(b=.5*u),"bottom"===l&&(b=u),-1!==l.indexOf("%")&&(l=parseInt(l.replace("%",""),10))>0&&(b=u*l*.01),o.hardPixels&&(e=t,a=s),c.css({width:e,height:a,"margin-left":Math.floor(f),"margin-top":Math.floor(b)}),c.data("sbi_imgLiquid_oldProcessed")||(c.fadeTo(o.fadeInTime,1),c.data("sbi_imgLiquid_oldProcessed",!0),o.removeBoxBackground&&d.css("background-image","none"),d.addClass("sbi_imgLiquid_nobgSize"),d.addClass("sbi_imgLiquid_ready")),o.onItemFinish&&o.onItemFinish(i,d,c),n()}function n(){i===a.length-1&&a.settings.onFinish&&a.settings.onFinish()}var o=a.settings,d=e(this),c=e("img:first",d);return c.length?(c.data("sbi_imgLiquid_settings")?(d.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"),o=e.extend({},c.data("sbi_imgLiquid_settings"),a.options)):o=e.extend({},a.settings,function(){var e={};if(a.settings.useDataHtmlAttr){var i=d.attr("data-sbi_imgLiquid-fill"),t=d.attr("data-sbi_imgLiquid-horizontalAlign"),s=d.attr("data-sbi_imgLiquid-verticalAlign");("true"===i||"false"===i)&&(e.fill=Boolean("true"===i)),void 0===t||"left"!==t&&"center"!==t&&"right"!==t&&-1===t.indexOf("%")||(e.horizontalAlign=t),void 0===s||"top"!==s&&"bottom"!==s&&"center"!==s&&-1===s.indexOf("%")||(e.verticalAlign=s)}return w.isIE&&a.settings.ieFadeInDisabled&&(e.fadeInTime=0),e}()),c.data("sbi_imgLiquid_settings",o),o.onItemStart&&o.onItemStart(i,d,c),void(w.bgs_Available&&o.useBackgroundSize?(-1===d.css("background-image").indexOf(encodeURI(c.attr("src")))&&d.css({"background-image":'url("'+encodeURI(c.attr("src"))+'")'}),d.css({"background-size":o.fill?"cover":"contain","background-position":(o.horizontalAlign+" "+o.verticalAlign).toLowerCase(),"background-repeat":"no-repeat"}),e("a:first",d).css({display:"block",width:"100%",height:"100%"}),e("img",d).css({display:"none"}),o.onItemFinish&&o.onItemFinish(i,d,c),d.addClass("sbi_imgLiquid_bgSize"),d.addClass("sbi_imgLiquid_ready"),n()):function a(){if(c.data("oldSrc")&&c.data("oldSrc")!==c.attr("src")){var n=c.clone().removeAttr("style");return n.data("sbi_imgLiquid_settings",c.data("sbi_imgLiquid_settings")),c.parent().prepend(n),c.remove(),(c=n)[0].width=0,void setTimeout(a,10)}return c.data("sbi_imgLiquid_oldProcessed")?void r():(c.data("sbi_imgLiquid_oldProcessed",!1),c.data("oldSrc",c.attr("src")),e("img:not(:first)",d).css("display","none"),d.css({overflow:"hidden"}),c.fadeTo(0,0).removeAttr("width").removeAttr("height").css({visibility:"visible","max-width":"none","max-height":"none",width:"auto",height:"auto",display:"block"}),c.on("error",s),c[0].onerror=s,function e(){c.data("sbi_imgLiquid_error")||c.data("sbi_imgLiquid_loaded")||c.data("sbi_imgLiquid_oldProcessed")||(d.is(":visible")&&c[0].complete&&c[0].width>0&&c[0].height>0?(c.data("sbi_imgLiquid_loaded",!0),setTimeout(r,i*o.delay)):setTimeout(e,o.timecheckvisibility))}(),void t())}())):void s()})}})}(jQuery),r=w.injectCss,b=document.getElementsByTagName("head")[0],(p=document.createElement("style")).type="text/css",p.styleSheet?p.styleSheet.cssText=r:p.appendChild(document.createTextNode(r)),b.appendChild(p),o.find(".sbi_photo").sbi_imgLiquid({fill:!0})}var y,x,I,k,j=(y=0,function(e,i){clearTimeout(y),y=setTimeout(e,i)});function S(){if("thumbnail"!==g){var e=o.find(".sbi_photo").eq(0).innerWidth(),i=sbiGetColumnCount(o,parseInt(h),parseInt(h)),a=jQuery("#sbi_images").innerWidth()-jQuery("#sbi_images").width(),t=o.find("#sbi_images").width()/i-a;e<=t&&(e=t),o.find(".sbi_photo").css("height",e);var s=o.find(".sbi_photo").eq(0).innerWidth()/2;"px"==v&&(s+=2*parseInt(_)),o.find(".sbi_owl-buttons div").css("top",s)}}function F(){o.removeClass("sbi_small sbi_medium");var e=o.find(".sbi_item").innerWidth();e>120&&e<240?o.addClass("sbi_medium"):e<=120&&o.addClass("sbi_small")}jQuery(window).resize(function(){j(function(){S(),F(),jQuery(".sbi").each(function(){var e=jQuery(this),i=jQuery(this).attr("data-sbi-index");if(sbiSizeSVG(e),"auto"===e.attr("data-res")){var a=window.sbiFeedMeta[i].minRes,t=sbiGetResolutionSettings(e,"auto",h,u,i);sbiNeedToRaiseRes(""!==t.width?t.width:sbiGetWidthForResType(t.type),a)&&(window.sbiFeedMeta[i].minRes=640,e.find(".sbi_item").each(function(){var e=jQuery(this).find(".sbi_photo").attr("data-full-res"),i=jQuery(this).find(".sbi_photo img").attr("src"),t=jQuery(this);""===e&&(i.indexOf("p"+a+"x"+a)>-1?e=i.replace("p"+a+"x"+a,"p640x640"):i.indexOf("s"+a+"x"+a)>-1&&(e=i.replace("s"+a+"x"+a,"s640x640"))),t.find(".sbi_photo img").attr("src",e),t.find(".sbi_photo").css("background-image",'url("'+e+'")')}))}})},500)}),S(),x=jQuery,I={callback:function(){},runOnLoad:!0,frequency:100,sbiPreviousVisibility:null},k={sbiCheckVisibility:function(e,i){if(jQuery.contains(document,e[0])){var a=i.sbiPreviousVisibility,t=e.is(":visible");i.sbiPreviousVisibility=t,null==a?i.runOnLoad&&i.callback(e,t):a!==t&&i.callback(e,t),setTimeout(function(){k.sbiCheckVisibility(e,i)},i.frequency)}}},x.fn.sbiVisibilityChanged=function(e){var i=x.extend({},I,e);return this.each(function(){k.sbiCheckVisibility(x(this),i)})},jQuery(".sbi").filter(":hidden").sbiVisibilityChanged({callback:function(e,i){S(),F()},runOnLoad:!1}),F(),f.disablecache||void 0===e||"fetched"!==window.sbiCacheStatuses[f.feedIndex].feed||(e(i,a,C),window.sbiCacheStatuses[f.feedIndex].feed="cached"),E="finished",sbSVGify(o)}(z,S.feed);var T=10;o.find(".sbi_transition").each(function(){var e=jQuery(this);setTimeout(function(){e.removeClass("sbi_transition")},T),T+=10,e.find(".sbi_photo").find("img").on("error",function(){jQuery(this).hasClass("sbi_img_error")||(jQuery(this).addClass("sbi_img_error"),"undefined"!==jQuery(this).closest(".sbi_photo").attr("href")&&(jQuery(this).attr("src",jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m"),jQuery(this).closest(".sbi_photo").css("background-image","url("+jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m)")))})}),B="",o.find("#sbi_images > .sbi_loader").remove(),o.find("#sbi_load").removeClass("sbi_hidden"),s>=l&&o.find(".sbi_load_btn").show(),setTimeout(function(){d.find(".sbi_loader").addClass("sbi_hidden"),d.find(".sbi_btn_text").removeClass("sbi_hidden")},500)}}function N(e,i){if(void 0===e.meta.error_message){var a=i.feedOptions,t="";a.headercolor.length&&(t='style="color: #'+a.headercolor+'"'),u='<a href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" title="@'+e.data.username+'" class="sbi_header_link" '+t+">",u+='<div class="sbi_header_text">';var s="";(void 0!==e.data.bio&&e.data.bio.length<1||"true"!=a.showbio)&&(s=' class="sbi_no_bio"'),u+="<h3 "+t+s+">"+e.data.username+"</h3>";var n='<p class="sbi_bio_info" ';"boxed"==a.headerstyle?n+='style="color: #'+a.headerprimarycolor+';"':n+=t,void 0!==e.data.bio&&e.data.bio.length>1&&""!=a.showbio&&"false"!=a.showbio&&(u+='<p class="sbi_bio" '+t+">"+e.data.bio+"</p>"),u+="</div>",u+='<div class="sbi_header_img">',u+='<div class="sbi_header_img_hover"><i class="sbi_new_logo"></i></div>',u+='<img src="'+e.data.profile_picture+'" alt="'+e.data.full_name+'" width="50" height="50">',u+="</div>",u+="</a>","boxed"==a.headerstyle&&(u+='<div class="sbi_header_bar" style="background: #'+a.headersecondarycolor+'">',"false"!=a.showbio&&(u+=n),u+='<a class="sbi_header_follow_btn" href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" style="color: #'+a.headercolor+"; background: #"+a.headerprimarycolor+';"><i class="sbi_new_logo"></i><span></span></div></div>'),0==r.find(".sbi_header_link").length&&r.find(".sb_instagram_header").prepend(u),r.find(".sbi_follow_btn").length&&r.find(".sbi_follow_btn a").attr("href","https://www.instagram.com/"+e.data.username),"boxed"==a.headerstyle&&r.find(".sbi_header_follow_btn").length&&r.find(".sbi_header_follow_btn span").text(r.find(".sb_instagram_header").attr("data-follow-text").replace(/\\/g,"")),r.find(".sb_instagram_header .sbi_header_link").hover(function(){r.find(".sb_instagram_header .sbi_header_img_hover").addClass("sbi_fade_in")},function(){r.find(".sb_instagram_header .sbi_header_img_hover").removeClass("sbi_fade_in")}),sbSVGify(r.find(".sb_instagram_header"))}}function G(e,a,t,r){var n=(y=e).length,o=t.getType;if(0==n)s+parseInt(t.num)>=z.data.length&&jQuery("#sbi_load .sbi_load_btn").hide();else{var d=[],l=n;jQuery.each(y,function(e,s){jQuery.ajax({method:"GET",url:s,dataType:"jsonp",success:function(n){var h=n.meta.error_message,u="",b="";if(void 0!==h){if(u+='<p><i class="fa fab fa-instagram" style="font-size: 16px; position: relative; top: 1px;"></i>&nbsp; Instagram Feed Error</p>',h.indexOf("access_token")>-1){u+="<p><b>Error: Access Token is not valid or has expired</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>There's an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin's Settings page.<br />If you continue to have an issue with your Access Token then please see <a href='https://smashballoon.com/my-instagram-access-token-keep-expiring/' target='_blank' rel='noopener'>this FAQ</a> for more information.</p>",jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>"),sbiAddTokenToExpiredList(sb_instagram_js_options.sb_instagram_at,a);var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};return void jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}})}if(h.indexOf("retired")>-1)return u+="<p><b>No longer possible to display this feed</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>Due to changes in the Instagram API, it is no longer possible to display a feed from an Instagram account which is not your own. You can now only display your own Instagram account. Please see <a href='https://smashballoon.com/instagram-api-changes-april-4-2018/' target='_blank' rel='noopener'>this post</a> for more information.</p>",void jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>");if(void 0!==n.code&&"429"==n.code){window.sbiFeedMeta[i].error={errorMsg:"<p><b>Error: Rate Limit Reached</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Backup cache will be used for 1 hour</p>"},r.find("#sbi_mod_error").length?-1==r.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&r.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):r.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>");var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}}),n="error"}else h.indexOf("user does not exist")>-1||h.indexOf("you cannot view this resource")>-1?(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: User ID <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist, is invalid, or is private</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Please double check that the Instagram User ID you are using is valid and not from a private account. To find your User ID simply enter your Instagram user name into this <a href='https://smashballoon.com/instagram-feed/find-instagram-user-id/' target='_blank' rel='noopener'>tool</a>.</p>"},r.find("#sbi_mod_error").length?-1==r.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&r.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):r.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error"):h.indexOf("invalid media id")>-1&&(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: Post Id <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist or is invalid</b><br /><span>This error is only visible to WordPress admins.</span>",errorDir:"<p>Please double check the media (post) id is correct.</p>"},r.find("#sbi_mod_error").length?-1==r.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&r.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):r.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error")}"coordinates"==o&&(n.pagination={previous_url:s}),"error"!==n&&d.push(n),0==--l&&"finished"!==E&&function(e){var i=[],s=[];jQuery.each(d,function(a,t){if("single"==e&&(t.data=[t.data]),void 0!==t.data)if(jQuery.each(t.data,function(e,i){jQuery.inArray(i.id,q)>-1||(q.push(i.id),s.push(i))}),"coordinates"==e){var r=t.data[t.data.length-1].created_time,n=t.pagination.previous_url.split("max_timestamp=")[0]+"max_timestamp="+r;i.push(n)}else"object"==typeof t.pagination&&t.pagination&&void 0!==t.pagination.next_url&&i.push(t.pagination.next_url)}),"random"!==c?s.sort(function(e,i){return i.created_time-e.created_time}):(s.sort(function(e,i){return Math.round(Math.random())-.5}),a+="!"),void 0!==d&&(d[0].data=s),void 0!==d[0].pagination&&d[0].pagination?d[0].pagination.next_url=i:d[0].pagination={next_url:""};var n=d[0];"finished"!==E&&R(n,a,t,r),V++}(o)}})})}}}window.sbiUseBackup[i]={header:r.indexOf("header")>-1,feed:r.indexOf("feed")>-1},window.sbiFeedMeta[i]={error:{},idsInFeed:[],postsInFeed:[]},setTimeout(function(){!function a(t,s){var r=0,n=jQuery(t),o="standard_resolution",d=parseInt(t.getAttribute("data-cols")),c="none",l=t.getAttribute("data-num"),h=t.getAttribute("data-id"),u="",b=s.sbiHeaderCache;s.disablecache="true"==s.disablecache,s.media="all",""!==s.sortby&&(c=s.sortby),o=sbiGetResolutionSettings(n,t.getAttribute("data-res"),d,d,i);var f=[],p=[];if(void 0!==s.feedID){var g=s.feedID.split(","),m=s.mid.split(","),_=s.callback.split(",");jQuery.each(g,function(e){f.push(g[e]+"."+m[e]+"."+_[e]),p.push(g[e])}),h=p.join(","),p=p.join(",")}else f.push(sb_instagram_js_options.sb_instagram_at);var v=h.replace(/ /g,"").split(","),w=v,y=[],x="",C=[];jQuery.each(w,function(e,a){var t=void 0!==f[e]?addLinksToPage(f[e]):addLinksToPage(f[0]);x="https://api.instagram.com/v1/users/"+a+"/media/recent?access_token="+t+"&count=33",window.sbiFeedMeta[i].idsInFeed.push(a),y.push(x),C.push(t)});var I,k={num:l,getType:"user",user_id:h,cols:d,imgRes:o,sortby:c,feedOptions:s,looparray:w},j="",S="",F={header:"",feed:""},Q=j.length,T=S.length,L=40-Math.min(Q+T,20),M="sbi_";if(w=w.join().replace(/[.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""),"all"!==s.media&&(M+=s.media.substring(0,1)),M+=w.substring(0,L),L=M.length,T<(L=44-L)/2?j=j.substring(0,L-T):(j=0==S.length?j.substring(0,L):j.substring(0,L/2),S=0==j.length?S.substring(0,L):S.substring(0,L/2)),M+=j+S,F.feed=M.substring(0,45),F.header=(I=k.looparray[0],("sbi_header_"+I).substring(0,45)),sb_instagram_js_options.sbiPageCommentCache||1!==window.sbiCommentCacheStatus||!0===window.sbiStandalone.noDB?F.comments="no":F.comments="need",!0!==window.sbiCacheStatuses[s.feedIndex].feed&&!0!==window.sbiCacheStatuses[s.feedIndex].header&&"need"!==F.comments||s.disablecache||void 0!==s.tryFetch||(!function A(t,r,n,o,d){var c=t;window.sbiCommentCacheStatus=0;var l=n[0].getAttribute("data-sbi-index");"object"==typeof t&&(c=JSON.stringify(t));var h={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"get_cache",transientName:c,useBackupHeader:window.sbiUseBackup[l].header,useBackupFeed:window.sbiUseBackup[l].feed},success:function(d){var c={};if(0===d.trim().indexOf("{")&&((d.indexOf("{%22")>-1||d.indexOf("%7B%22")>-1)&&(d=decodeURI(d)),d=(d=d.replace(/\\'/g,"'")).replace(/\\'/g,"'"),c=JSON.parse(d.trim())),"all"==o){if(void 0===c.header.error&&W(c.header,r),void 0===c.feed.error){if("finished"!==R&&G(c.feed,t,r,n),void 0!==c.warning){var l="<p><b>Cache Error: Looking for cache that doesn't exist. Now using a backup feed.</b><br /><span>This error is only visible to WordPress admins.</span>",h="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").before('<div id="sbi_mod_error">'+l+h+"</div>")}}else{s=JSON.parse(n[0].getAttribute("data-options"));var u=n[0].getAttribute("data-sbi-index");if(s.feedIndex=u,!1!==window.sbiCacheStatuses[u].feed&&"tryfetch"===c.feed.error)window.sbiCacheStatuses[u].feed=!1,n.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[u].header=!1),window.sbiCacheStatuses[u].comments="no",s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&function a(t,s){var r=0,n=jQuery(t),o="standard_resolution",d=parseInt(t.getAttribute("data-cols")),c="none",l=t.getAttribute("data-num"),h=t.getAttribute("data-id"),u="",b=s.sbiHeaderCache;s.disablecache="true"==s.disablecache,s.media="all",""!==s.sortby&&(c=s.sortby),o=sbiGetResolutionSettings(n,t.getAttribute("data-res"),d,d,i);var f=[],p=[];if(void 0!==s.feedID){var g=s.feedID.split(","),m=s.mid.split(","),_=s.callback.split(",");jQuery.each(g,function(e){f.push(g[e]+"."+m[e]+"."+_[e]),p.push(g[e])}),h=p.join(","),p=p.join(",")}else f.push(sb_instagram_js_options.sb_instagram_at);var v=h.replace(/ /g,"").split(","),w=v,y=[],x="",C=[];jQuery.each(w,function(e,a){var t=void 0!==f[e]?addLinksToPage(f[e]):addLinksToPage(f[0]);x="https://api.instagram.com/v1/users/"+a+"/media/recent?access_token="+t+"&count=33",window.sbiFeedMeta[i].idsInFeed.push(a),y.push(x),C.push(t)});var I,k={num:l,getType:"user",user_id:h,cols:d,imgRes:o,sortby:c,feedOptions:s,looparray:w},j="",S="",F={header:"",feed:""},Q=j.length,T=S.length,L=40-Math.min(Q+T,20),M="sbi_";if(w=w.join().replace(/[.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""),"all"!==s.media&&(M+=s.media.substring(0,1)),M+=w.substring(0,L),L=M.length,T<(L=44-L)/2?j=j.substring(0,L-T):(j=0==S.length?j.substring(0,L):j.substring(0,L/2),S=0==j.length?S.substring(0,L):S.substring(0,L/2)),M+=j+S,F.feed=M.substring(0,45),F.header=(I=k.looparray[0],("sbi_header_"+I).substring(0,45)),sb_instagram_js_options.sbiPageCommentCache||1!==window.sbiCommentCacheStatus||!0===window.sbiStandalone.noDB?F.comments="no":F.comments="need",!0!==window.sbiCacheStatuses[s.feedIndex].feed&&!0!==window.sbiCacheStatuses[s.feedIndex].header&&"need"!==F.comments||s.disablecache||void 0!==s.tryFetch||(D(F,k,n,"all",y),F.comments="no"),!1===window.sbiCacheStatuses[s.feedIndex].feed&&"fetched"!==window.sbiCacheStatuses[s.feedIndex].feed&&(window.sbiCacheStatuses[s.feedIndex].feed="fetched",window.sbiCacheStatuses[s.feedIndex].tryFetch="done",W(y,F.feed,k,n)),!window.sbiCacheStatuses[s.feedIndex].header&&"fetched"!==window.sbiCacheStatuses[s.feedIndex].header&&"user"===k.getType){window.sbiCacheStatuses[s.feedIndex].header="fetched";var A=f[0].split(".");k.user_id=A[0];var z="https://api.instagram.com/v1/users/"+k.user_id+"?access_token="+addLinksToPage(f[0]);jQuery.ajax({method:"GET",url:z,dataType:"jsonp",success:function(e){G(e,k),void 0!==e.data&&(s.disablecache||"cached"===window.sbiCacheStatuses[s.feedIndex].header||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[s.feedIndex].header="cached",sbiCachePhotos(e,F.header,[addLinksToPage(f[0])])))}})}var P="",O=!1,q=!1,B=[],E="",V=0,R=1;function N(a,s,n,o){var d=o.find("#sbi_load .sbi_load_btn"),l=parseInt(n.num),h=parseInt(n.cols),u="auto",f=n.feedOptions,p=0,g=n.imgRes,m=(f.type,parseInt(f.maxrequests)),_=f.imagepadding,v=f.imagepaddingunit,w=n.looparray,y=(f.headerstyle,f.headerprimarycolor,f.headersecondarycolor,f.media);d.find(".sbi_loader").css("background-color",d.css("color")),""==P?P=a:1==O&&(jQuery.each(a.data,function(e,i){P.data.push(i)}),O=!1);var x=a.pagination.next_url;void 0===x||0==x.length?q=!0:d.show(),void 0!==a.pagination&&(P.pagination=a.pagination),""!==f.sortby&&(c=f.sortby),f.hovercolor;var I=r,k=[];if(0==o.find(".sbi_header_link").length){var j="https://api.instagram.com/v1/users/"+w[0]+"?access_token="+sb_instagram_js_options.sb_instagram_at,S="sbi_header_"+w[0];S=S.substring(0,45),("true"!=b||f.disablecache)&&o.find(".sb_instagram_header").length&&jQuery.ajax({method:"GET",url:j,dataType:"jsonp",success:function(e){G(e,n),f.disablecache||"cached"===window.sbiCacheStatuses[f.feedIndex].header||void 0===e.data||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[f.feedIndex].header="cached",sbiCachePhotos(e,S,[sb_instagram_js_options.sb_instagram_at]))}})}if(jQuery.each(P.data,function(e,a){if("videos"==y&&"video"!==a.type&&(removePhoto=!0),"photos"==y&&"image"!==a.type&&"carousel"!==a.type&&(removePhoto=!0),!(++p>I-V+l||p<=I||(r++,i=o.attr("data-sbi-index"),jQuery.inArray(a.id,window.sbiFeedMeta[i].postsInFeed)>-1))){window.sbiFeedMeta[i].postsInFeed.push(a.id);var s=!1;"carousel"===a.type&&void 0!==a.carousel_media&&jQuery.each(a.carousel_media,function(e,i){void 0!==i.videos&&0===e&&(s=!0)});var n=a.images.standard_resolution.url;switch(g.type){case"thumbnail":n=a.images.thumbnail.url;break;case"low_resolution":n=a.images.low_resolution.url;break;case"auto":var d=sbiGetBestResolutionForAuto((g=sbiGetResolutionSettings(o,t.getAttribute("data-res"),h,u,i)).width,a.images.standard_resolution.width,a.images.standard_resolution.height,o.hasClass("sbi_highlight"));switch(d){case 320:n=a.images.low_resolution.url;break;case 150:n=a.images.thumbnail.url}}n=n.split("?ig_cache_key")[0];var c="",b=a.created_time;null!=a.caption&&""!=a.caption&&(c=(c=void 0!==a.caption?a.caption.text.replace(/"/g,"&quot;"):"").replace(/\n/g," "));var f=s?" sbi_carousel_vid_first":"",m="carousel"===a.type?'<i class="fa fa-clone sbi_carousel_icon" aria-hidden="true"></i>':"",_="video"===a.type||f?'<i class="fa fa-play sbi_playbtn"></i>':"";E+='<div class="sbi_item sbi_type_'+a.type+' sbi_new sbi_transition" id="sbi_'+a.id+'" data-date="'+b+'"><div class="sbi_photo_wrap"><a class="sbi_photo" href="'+a.link+'" target="_blank" rel="noopener" data-full-res="'+a.images.standard_resolution.url+'">'+m+_+'<img src="'+n+'" alt="'+c.replace(/<>/g," ")+'" width="200" height="200" /></a></div></div>'}}),k.reverse(),jQuery.each(k,function(e,i){P.data.splice(i,1)}),r-I<l&&(V+=r-I),r-I<l&&V<l&&R<m&&!q){var Q=P.pagination.next_url;window.sbiCacheStatuses[f.feedIndex].feed="fetched",W(Q,F.feed,n,o),O=!0}else{o.find("#sbi_images").append(E),function(i,t){sbiSizeSVG(o),o.find(".sbi_item").each(function(){var e=jQuery(this);e.find(".sbi_photo").hover(function(){jQuery(this).fadeTo(200,.85)},function(){jQuery(this).stop().fadeTo(500,1)})}),o.find("#sbi_images .sbi_item.sbi_new").sort(function(e,i){var a=jQuery(e).attr("data-date"),t=jQuery(i).attr("data-date");return"none"==c?t-a:Math.round(Math.random())-.5}).appendTo(o.find("#sbi_images")),setTimeout(function(){jQuery("#sbi_images .sbi_item.sbi_new").removeClass("sbi_new")},500);var s,b,p,m=i.data.length;if(r>=m&&q&&d.hide(),o.find("#sbi_load .sbi_load_btn").off().on("click",function(){jQuery(this).find(".sbi_loader").removeClass("sbi_hidden"),jQuery(this).find(".sbi_btn_text").addClass("sbi_hidden"),V=0,r=parseInt(r),m=i.data.length,r+l<m||q?("finished"!==V&&N(a,t,n,o),O=!1,r>=m&&q&&d.hide()):(Q=i.pagination.next_url,window.sbiCacheStatuses[f.feedIndex].feed="fetched",W(Q,t,n,o),O=!0,R=0)}),"function"==typeof sbi_custom_js&&setTimeout(function(){sbi_custom_js()},100),"thumbnail"!==g){var w=w||{VER:"0.9.944"};w.bgs_Available=!1,w.bgs_CheckRunned=!1,function(e){e.fn.extend({sbi_imgLiquid:function(i){this.defaults={fill:!0,verticalAlign:"center",horizontalAlign:"center",useBackgroundSize:!0,useDataHtmlAttr:!0,responsive:!0,delay:0,fadeInTime:0,removeBoxBackground:!0,hardPixels:!0,responsiveCheckTime:500,timecheckvisibility:500,onStart:null,onFinish:null,onItemStart:null,onItemFinish:null,onItemError:null},function(){if(!w.bgs_CheckRunned){w.bgs_CheckRunned=!0;var i=e('<span style="background-size:cover" />');e("body").append(i),function(){var e=i[0];if(e&&window.getComputedStyle){var a=window.getComputedStyle(e,null);a&&a.backgroundSize&&(w.bgs_Available="cover"===a.backgroundSize)}}(),i.remove()}}();var a=this;return this.options=i,this.settings=e.extend({},this.defaults,this.options),this.settings.onStart&&this.settings.onStart(),this.each(function(i){function t(){(o.responsive||c.data("sbi_imgLiquid_oldProcessed"))&&c.data("sbi_imgLiquid_settings")&&(o=c.data("sbi_imgLiquid_settings"),d.actualSize=d.get(0).offsetWidth+d.get(0).offsetHeight/1e4,d.sizeOld&&d.actualSize!==d.sizeOld&&r(),d.sizeOld=d.actualSize,setTimeout(t,o.responsiveCheckTime))}function s(){c.data("sbi_imgLiquid_error",!0),d.addClass("sbi_imgLiquid_error"),o.onItemError&&o.onItemError(i,d,c),n()}function r(){var e,a,t,s,r,l,h,u,b=0,f=0,p=d.width(),g=d.height();void 0===c.data("owidth")&&c.data("owidth",c[0].width),void 0===c.data("oheight")&&c.data("oheight",c[0].height),o.fill===p/g>=c.data("owidth")/c.data("oheight")?(e="100%",a="auto",t=Math.floor(p),s=Math.floor(p*(c.data("oheight")/c.data("owidth")))):(e="auto",a="100%",t=Math.floor(g*(c.data("owidth")/c.data("oheight"))),s=Math.floor(g)),r=o.horizontalAlign.toLowerCase(),h=p-t,"left"===r&&(f=0),"center"===r&&(f=.5*h),"right"===r&&(f=h),-1!==r.indexOf("%")&&(r=parseInt(r.replace("%",""),10))>0&&(f=h*r*.01),l=o.verticalAlign.toLowerCase(),u=g-s,"left"===l&&(b=0),"center"===l&&(b=.5*u),"bottom"===l&&(b=u),-1!==l.indexOf("%")&&(l=parseInt(l.replace("%",""),10))>0&&(b=u*l*.01),o.hardPixels&&(e=t,a=s),c.css({width:e,height:a,"margin-left":Math.floor(f),"margin-top":Math.floor(b)}),c.data("sbi_imgLiquid_oldProcessed")||(c.fadeTo(o.fadeInTime,1),c.data("sbi_imgLiquid_oldProcessed",!0),o.removeBoxBackground&&d.css("background-image","none"),d.addClass("sbi_imgLiquid_nobgSize"),d.addClass("sbi_imgLiquid_ready")),o.onItemFinish&&o.onItemFinish(i,d,c),n()}function n(){i===a.length-1&&a.settings.onFinish&&a.settings.onFinish()}var o=a.settings,d=e(this),c=e("img:first",d);return c.length?(c.data("sbi_imgLiquid_settings")?(d.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"),o=e.extend({},c.data("sbi_imgLiquid_settings"),a.options)):o=e.extend({},a.settings,function(){var e={};if(a.settings.useDataHtmlAttr){var i=d.attr("data-sbi_imgLiquid-fill"),t=d.attr("data-sbi_imgLiquid-horizontalAlign"),s=d.attr("data-sbi_imgLiquid-verticalAlign");("true"===i||"false"===i)&&(e.fill=Boolean("true"===i)),void 0===t||"left"!==t&&"center"!==t&&"right"!==t&&-1===t.indexOf("%")||(e.horizontalAlign=t),void 0===s||"top"!==s&&"bottom"!==s&&"center"!==s&&-1===s.indexOf("%")||(e.verticalAlign=s)}return w.isIE&&a.settings.ieFadeInDisabled&&(e.fadeInTime=0),e}()),c.data("sbi_imgLiquid_settings",o),o.onItemStart&&o.onItemStart(i,d,c),void(w.bgs_Available&&o.useBackgroundSize?(-1===d.css("background-image").indexOf(encodeURI(c.attr("src")))&&d.css({"background-image":'url("'+encodeURI(c.attr("src"))+'")'}),d.css({"background-size":o.fill?"cover":"contain","background-position":(o.horizontalAlign+" "+o.verticalAlign).toLowerCase(),"background-repeat":"no-repeat"}),e("a:first",d).css({display:"block",width:"100%",height:"100%"}),e("img",d).css({display:"none"}),o.onItemFinish&&o.onItemFinish(i,d,c),d.addClass("sbi_imgLiquid_bgSize"),d.addClass("sbi_imgLiquid_ready"),n()):function a(){if(c.data("oldSrc")&&c.data("oldSrc")!==c.attr("src")){var n=c.clone().removeAttr("style");return n.data("sbi_imgLiquid_settings",c.data("sbi_imgLiquid_settings")),c.parent().prepend(n),c.remove(),(c=n)[0].width=0,void setTimeout(a,10)}return c.data("sbi_imgLiquid_oldProcessed")?void r():(c.data("sbi_imgLiquid_oldProcessed",!1),c.data("oldSrc",c.attr("src")),e("img:not(:first)",d).css("display","none"),d.css({overflow:"hidden"}),c.fadeTo(0,0).removeAttr("width").removeAttr("height").css({visibility:"visible","max-width":"none","max-height":"none",width:"auto",height:"auto",display:"block"}),c.on("error",s),c[0].onerror=s,function e(){c.data("sbi_imgLiquid_error")||c.data("sbi_imgLiquid_loaded")||c.data("sbi_imgLiquid_oldProcessed")||(d.is(":visible")&&c[0].complete&&c[0].width>0&&c[0].height>0?(c.data("sbi_imgLiquid_loaded",!0),setTimeout(r,i*o.delay)):setTimeout(e,o.timecheckvisibility))}(),void t())}())):void s()})}})}(jQuery),s=w.injectCss,b=document.getElementsByTagName("head")[0],(p=document.createElement("style")).type="text/css",p.styleSheet?p.styleSheet.cssText=s:p.appendChild(document.createTextNode(s)),b.appendChild(p),o.find(".sbi_photo").sbi_imgLiquid({fill:!0})}var y,x,I,k,j=(y=0,function(e,i){clearTimeout(y),y=setTimeout(e,i)});function S(){if("thumbnail"!==g){var e=o.find(".sbi_photo").eq(0).innerWidth(),i=sbiGetColumnCount(o,parseInt(h),parseInt(h)),a=jQuery("#sbi_images").innerWidth()-jQuery("#sbi_images").width(),t=o.find("#sbi_images").width()/i-a;e<=t&&(e=t),o.find(".sbi_photo").css("height",e);var s=o.find(".sbi_photo").eq(0).innerWidth()/2;"px"==v&&(s+=2*parseInt(_)),o.find(".sbi_owl-buttons div").css("top",s)}}function F(){o.removeClass("sbi_small sbi_medium");var e=o.find(".sbi_item").innerWidth();e>120&&e<240?o.addClass("sbi_medium"):e<=120&&o.addClass("sbi_small")}jQuery(window).resize(function(){j(function(){S(),F(),jQuery(".sbi").each(function(){var e=jQuery(this),i=jQuery(this).attr("data-sbi-index");if(sbiSizeSVG(e),"auto"===e.attr("data-res")){var a=window.sbiFeedMeta[i].minRes,t=sbiGetResolutionSettings(e,"auto",h,u,i);sbiNeedToRaiseRes(""!==t.width?t.width:sbiGetWidthForResType(t.type),a)&&(window.sbiFeedMeta[i].minRes=640,e.find(".sbi_item").each(function(){var e=jQuery(this).find(".sbi_photo").attr("data-full-res"),i=jQuery(this).find(".sbi_photo img").attr("src"),t=jQuery(this);""===e&&(i.indexOf("p"+a+"x"+a)>-1?e=i.replace("p"+a+"x"+a,"p640x640"):i.indexOf("s"+a+"x"+a)>-1&&(e=i.replace("s"+a+"x"+a,"s640x640"))),t.find(".sbi_photo img").attr("src",e),t.find(".sbi_photo").css("background-image",'url("'+e+'")')}))}})},500)}),S(),x=jQuery,I={callback:function(){},runOnLoad:!0,frequency:100,sbiPreviousVisibility:null},k={sbiCheckVisibility:function(e,i){if(jQuery.contains(document,e[0])){var a=i.sbiPreviousVisibility,t=e.is(":visible");i.sbiPreviousVisibility=t,null==a?i.runOnLoad&&i.callback(e,t):a!==t&&i.callback(e,t),setTimeout(function(){k.sbiCheckVisibility(e,i)},i.frequency)}}},x.fn.sbiVisibilityChanged=function(e){var i=x.extend({},I,e);return this.each(function(){k.sbiCheckVisibility(x(this),i)})},jQuery(".sbi").filter(":hidden").sbiVisibilityChanged({callback:function(e,i){S(),F()},runOnLoad:!1}),F(),f.disablecache||void 0===e||"fetched"!==window.sbiCacheStatuses[f.feedIndex].feed||(e(i,t,C),window.sbiCacheStatuses[f.feedIndex].feed="cached"),V="finished",sbSVGify(o)}(P,F.feed);var T=10;o.find(".sbi_transition").each(function(){var e=jQuery(this);setTimeout(function(){e.removeClass("sbi_transition")},T),T+=10,e.find(".sbi_photo").find("img").on("error",function(){jQuery(this).hasClass("sbi_img_error")||(jQuery(this).addClass("sbi_img_error"),"undefined"!==jQuery(this).closest(".sbi_photo").attr("href")&&(jQuery(this).attr("src",jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m"),jQuery(this).closest(".sbi_photo").css("background-image","url("+jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m)")))})}),E="",o.find("#sbi_images > .sbi_loader").remove(),o.find("#sbi_load").removeClass("sbi_hidden"),r>=l&&o.find(".sbi_load_btn").show(),setTimeout(function(){d.find(".sbi_loader").addClass("sbi_hidden"),d.find(".sbi_btn_text").removeClass("sbi_hidden")},500)}}function G(e,i){if(void 0===e.meta.error_message){var a=i.feedOptions,t="";a.headercolor.length&&(t='style="color: #'+a.headercolor+'"'),u='<a href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" title="@'+e.data.username+'" class="sbi_header_link" '+t+">",u+='<div class="sbi_header_text">';var s="";(void 0!==e.data.bio&&e.data.bio.length<1||"true"!=a.showbio)&&(s=' class="sbi_no_bio"'),u+="<h3 "+t+s+">"+e.data.username+"</h3>";var r='<p class="sbi_bio_info" ';"boxed"==a.headerstyle?r+='style="color: #'+a.headerprimarycolor+';"':r+=t,void 0!==e.data.bio&&e.data.bio.length>1&&""!=a.showbio&&"false"!=a.showbio&&(u+='<p class="sbi_bio" '+t+">"+e.data.bio+"</p>"),u+="</div>",u+='<div class="sbi_header_img">',u+='<div class="sbi_header_img_hover"><i class="sbi_new_logo"></i></div>',u+='<img src="'+e.data.profile_picture+'" alt="'+e.data.full_name+'" width="50" height="50">',u+="</div>",u+="</a>","boxed"==a.headerstyle&&(u+='<div class="sbi_header_bar" style="background: #'+a.headersecondarycolor+'">',"false"!=a.showbio&&(u+=r),u+='<a class="sbi_header_follow_btn" href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" style="color: #'+a.headercolor+"; background: #"+a.headerprimarycolor+';"><i class="sbi_new_logo"></i><span></span></div></div>'),0==n.find(".sbi_header_link").length&&n.find(".sb_instagram_header").prepend(u),n.find(".sbi_follow_btn").length&&n.find(".sbi_follow_btn a").attr("href","https://www.instagram.com/"+e.data.username),"boxed"==a.headerstyle&&n.find(".sbi_header_follow_btn").length&&n.find(".sbi_header_follow_btn span").text(n.find(".sb_instagram_header").attr("data-follow-text").replace(/\\/g,"")),n.find(".sb_instagram_header .sbi_header_link").hover(function(){n.find(".sb_instagram_header .sbi_header_img_hover").addClass("sbi_fade_in")},function(){n.find(".sb_instagram_header .sbi_header_img_hover").removeClass("sbi_fade_in")}),sbSVGify(n.find(".sb_instagram_header"))}}function W(e,a,t,s){var n=(y=e).length,o=t.getType;if(0==n)r+parseInt(t.num)>=P.data.length&&jQuery("#sbi_load .sbi_load_btn").hide();else{var d=[],l=n;jQuery.each(y,function(e,r){jQuery.ajax({method:"GET",url:r,dataType:"jsonp",success:function(n){var h=n.meta.error_message,u="",b="";if(void 0!==h){if(u+='<p><i class="fa fab fa-instagram" style="font-size: 16px; position: relative; top: 1px;"></i>&nbsp; Instagram Feed Error</p>',h.indexOf("access_token")>-1){u+="<p><b>Error: Access Token is not valid or has expired</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>There's an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin's Settings page.<br />If you continue to have an issue with your Access Token then please see <a href='https://smashballoon.com/my-instagram-access-token-keep-expiring/' target='_blank' rel='noopener'>this FAQ</a> for more information.</p>",jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>"),sbiAddTokenToExpiredList(sb_instagram_js_options.sb_instagram_at,a);var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};return void jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}})}if(h.indexOf("retired")>-1)return u+="<p><b>No longer possible to display this feed</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>Due to changes in the Instagram API, it is no longer possible to display a feed from an Instagram account which is not your own. You can now only display your own Instagram account. Please see <a href='https://smashballoon.com/instagram-api-changes-april-4-2018/' target='_blank' rel='noopener'>this post</a> for more information.</p>",void jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>");if(void 0!==n.code&&"429"==n.code){window.sbiFeedMeta[i].error={errorMsg:"<p><b>Error: Rate Limit Reached</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Backup cache will be used for 1 hour</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>");var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}}),n="error"}else h.indexOf("user does not exist")>-1||h.indexOf("you cannot view this resource")>-1?(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: User ID <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist, is invalid, or is private</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Please double check that the Instagram User ID you are using is valid and not from a private account. To find your User ID simply enter your Instagram user name into this <a href='https://smashballoon.com/instagram-feed/find-instagram-user-id/' target='_blank' rel='noopener'>tool</a>.</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error"):h.indexOf("invalid media id")>-1&&(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: Post Id <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist or is invalid</b><br /><span>This error is only visible to WordPress admins.</span>",errorDir:"<p>Please double check the media (post) id is correct.</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error")}"coordinates"==o&&(n.pagination={previous_url:r}),"error"!==n&&d.push(n),0==--l&&"finished"!==V&&function(e){var i=[],r=[];jQuery.each(d,function(a,t){if("single"==e&&(t.data=[t.data]),void 0!==t.data)if(jQuery.each(t.data,function(e,i){jQuery.inArray(i.id,B)>-1||(B.push(i.id),r.push(i))}),"coordinates"==e){var s=t.data[t.data.length-1].created_time,n=t.pagination.previous_url.split("max_timestamp=")[0]+"max_timestamp="+s;i.push(n)}else"object"==typeof t.pagination&&t.pagination&&void 0!==t.pagination.next_url&&i.push(t.pagination.next_url)}),"random"!==c?r.sort(function(e,i){return i.created_time-e.created_time}):(r.sort(function(e,i){return Math.round(Math.random())-.5}),a+="!"),void 0!==d&&(d[0].data=r),void 0!==d[0].pagination&&d[0].pagination?d[0].pagination.next_url=i:d[0].pagination={next_url:""};var n=d[0];"finished"!==V&&N(n,a,t,s),R++}(o)}})})}}function D(e,i,t,r,n){var o=e;window.sbiCommentCacheStatus=0;var d=t[0].getAttribute("data-sbi-index");"object"==typeof e&&(o=JSON.stringify(e));var c={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"get_cache",transientName:o,useBackupHeader:window.sbiUseBackup[d].header,useBackupFeed:window.sbiUseBackup[d].feed},success:function(n){var o={};if(0===n.trim().indexOf("{")&&((n.indexOf("{%22")>-1||n.indexOf("%7B%22")>-1)&&(n=decodeURI(n)),n=(n=n.replace(/\\'/g,"'")).replace(/\\'/g,"'"),o=JSON.parse(n.trim())),"all"==r){if(void 0===o.header.error&&G(o.header,i),void 0===o.feed.error){if("finished"!==V&&N(o.feed,e,i,t),void 0!==o.warning){var d="<p><b>Cache Error: Looking for cache that doesn't exist. Now using a backup feed.</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").before('<div id="sbi_mod_error">'+d+c+"</div>")}}else{s=JSON.parse(t[0].getAttribute("data-options"));var l=t[0].getAttribute("data-sbi-index");if(s.feedIndex=l,!1!==window.sbiCacheStatuses[l].feed&&"tryfetch"===o.feed.error)window.sbiCacheStatuses[l].feed=!1,t.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1),window.sbiCacheStatuses[l].comments="no",s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&a(t[0],s);else if(!0===window.sbiCacheStatuses[l].feed){var d="<p><b>Cache Error: Looking for cache that doesn't exist</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+d+c+"</div>");var h={action:"sbi_set_use_backup",transientName:e,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:h,success:function(e){}})}}if("tryfetch"===o.header.error){s=JSON.parse(t[0].getAttribute("data-options"));var l=t[0].getAttribute("data-sbi-index");s.feedIndex=l,!1!==window.sbiCacheStatuses[l].header&&(t.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1,s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&a(t[0],s)))}void 0===o.comments.error&&(sb_instagram_js_options.sbiPageCommentCache=o.comments)}else"header"==r?G(o,i):"finished"!==V&&N(o,e,i,t)},error:function(e,i,a){console.log(a)}};jQuery.ajax(c)}}(n[0],s);else if(!0===window.sbiCacheStatuses[u].feed){var l="<p><b>Cache Error: Looking for cache that doesn't exist</b><br /><span>This error is only visible to WordPress admins.</span>",h="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+l+h+"</div>");var b={action:"sbi_set_use_backup",transientName:t,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:b,success:function(e){}})}}if("tryfetch"===c.header.error){s=JSON.parse(n[0].getAttribute("data-options"));var u=n[0].getAttribute("data-sbi-index");s.feedIndex=u,!1!==window.sbiCacheStatuses[u].header&&(n.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[u].header=!1,s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&a(n[0],s)))}void 0===c.comments.error&&(sb_instagram_js_options.sbiPageCommentCache=c.comments)}else"header"==o?W(c,r):"finished"!==R&&G(c,t,r,n)},error:function(e,i,a){console.log(a)}};jQuery.ajax(h)}(F,k,n,"all"),F.comments="no"),!1===window.sbiCacheStatuses[s.feedIndex].feed&&"fetched"!==window.sbiCacheStatuses[s.feedIndex].feed&&(window.sbiCacheStatuses[s.feedIndex].feed="fetched",window.sbiCacheStatuses[s.feedIndex].tryFetch="done",D(y,F.feed,k,n)),!window.sbiCacheStatuses[s.feedIndex].header&&"fetched"!==window.sbiCacheStatuses[s.feedIndex].header&&"user"===k.getType){window.sbiCacheStatuses[s.feedIndex].header="fetched";var z=f[0].split(".");k.user_id=z[0];var P="https://api.instagram.com/v1/users/"+k.user_id+"?access_token="+addLinksToPage(f[0]);jQuery.ajax({method:"GET",url:P,dataType:"jsonp",success:function(e){W(e,k),void 0!==e.data&&(s.disablecache||"cached"===window.sbiCacheStatuses[s.feedIndex].header||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[s.feedIndex].header="cached",sbiCachePhotos(e,F.header,[addLinksToPage(f[0])])))}})}var O="",q=!1,B=!1,E=[],V="",R=0,N=1;function G(a,s,n,o){var d=o.find("#sbi_load .sbi_load_btn"),l=parseInt(n.num),h=parseInt(n.cols),u="auto",f=n.feedOptions,p=0,g=n.imgRes,m=(f.type,parseInt(f.maxrequests)),_=f.imagepadding,v=f.imagepaddingunit,w=n.looparray,y=(f.headerstyle,f.headerprimarycolor,f.headersecondarycolor,f.media);d.find(".sbi_loader").css("background-color",d.css("color")),""==O?O=a:1==q&&(jQuery.each(a.data,function(e,i){O.data.push(i)}),q=!1);var x=a.pagination.next_url;void 0===x||0==x.length?B=!0:d.show(),void 0!==a.pagination&&(O.pagination=a.pagination),""!==f.sortby&&(c=f.sortby),f.hovercolor;var I=r,k=[];if(0==o.find(".sbi_header_link").length){var j="https://api.instagram.com/v1/users/"+w[0]+"?access_token="+sb_instagram_js_options.sb_instagram_at,S="sbi_header_"+w[0];S=S.substring(0,45),("true"!=b||f.disablecache)&&o.find(".sb_instagram_header").length&&jQuery.ajax({method:"GET",url:j,dataType:"jsonp",success:function(e){W(e,n),f.disablecache||"cached"===window.sbiCacheStatuses[f.feedIndex].header||void 0===e.data||void 0===e.data.username||void 0!==e.data.pagination||(window.sbiCacheStatuses[f.feedIndex].header="cached",sbiCachePhotos(e,S,[sb_instagram_js_options.sb_instagram_at]))}})}if(jQuery.each(O.data,function(e,a){if("videos"==y&&"video"!==a.type&&(removePhoto=!0),"photos"==y&&"image"!==a.type&&"carousel"!==a.type&&(removePhoto=!0),!(++p>I-R+l||p<=I||(r++,i=o.attr("data-sbi-index"),jQuery.inArray(a.id,window.sbiFeedMeta[i].postsInFeed)>-1))){window.sbiFeedMeta[i].postsInFeed.push(a.id);var s=!1;"carousel"===a.type&&void 0!==a.carousel_media&&jQuery.each(a.carousel_media,function(e,i){void 0!==i.videos&&0===e&&(s=!0)});var n=a.images.standard_resolution.url;switch(g.type){case"thumbnail":n=a.images.thumbnail.url;break;case"low_resolution":n=a.images.low_resolution.url;break;case"auto":var d=sbiGetBestResolutionForAuto((g=sbiGetResolutionSettings(o,t.getAttribute("data-res"),h,u,i)).width,a.images.standard_resolution.width,a.images.standard_resolution.height,o.hasClass("sbi_highlight"));switch(d){case 320:n=a.images.low_resolution.url;break;case 150:n=a.images.thumbnail.url}}n=n.split("?ig_cache_key")[0];var c="",b=a.created_time;null!=a.caption&&""!=a.caption&&(c=(c=void 0!==a.caption?a.caption.text.replace(/"/g,"&quot;"):"").replace(/\n/g," "));var f=s?" sbi_carousel_vid_first":"",m="carousel"===a.type?'<i class="fa fa-clone sbi_carousel_icon" aria-hidden="true"></i>':"",_="video"===a.type||f?'<i class="fa fa-play sbi_playbtn"></i>':"";V+='<div class="sbi_item sbi_type_'+a.type+' sbi_new sbi_transition" id="sbi_'+a.id+'" data-date="'+b+'"><div class="sbi_photo_wrap"><a class="sbi_photo" href="'+a.link+'" target="_blank" rel="noopener" data-full-res="'+a.images.standard_resolution.url+'">'+m+_+'<img src="'+n+'" alt="'+c.replace(/<>/g," ")+'" width="200" height="200" /></a></div></div>'}}),k.reverse(),jQuery.each(k,function(e,i){O.data.splice(i,1)}),r-I<l&&(R+=r-I),r-I<l&&R<l&&N<m&&!B){var Q=O.pagination.next_url;window.sbiCacheStatuses[f.feedIndex].feed="fetched",D(Q,F.feed,n,o),q=!0}else{o.find("#sbi_images").append(V),function(i,t){sbiSizeSVG(o),o.find(".sbi_item").each(function(){var e=jQuery(this);e.find(".sbi_photo").hover(function(){jQuery(this).fadeTo(200,.85)},function(){jQuery(this).stop().fadeTo(500,1)})}),o.find("#sbi_images .sbi_item.sbi_new").sort(function(e,i){var a=jQuery(e).attr("data-date"),t=jQuery(i).attr("data-date");return"none"==c?t-a:Math.round(Math.random())-.5}).appendTo(o.find("#sbi_images")),setTimeout(function(){jQuery("#sbi_images .sbi_item.sbi_new").removeClass("sbi_new")},500);var s,b,p,m=i.data.length;if(r>=m&&B&&d.hide(),o.find("#sbi_load .sbi_load_btn").off().on("click",function(){jQuery(this).find(".sbi_loader").removeClass("sbi_hidden"),jQuery(this).find(".sbi_btn_text").addClass("sbi_hidden"),R=0,r=parseInt(r),m=i.data.length,r+l<m||B?("finished"!==R&&G(a,t,n,o),q=!1,r>=m&&B&&d.hide()):(Q=i.pagination.next_url,window.sbiCacheStatuses[f.feedIndex].feed="fetched",D(Q,t,n,o),q=!0,N=0)}),"function"==typeof sbi_custom_js&&setTimeout(function(){sbi_custom_js()},100),"thumbnail"!==g){var w=w||{VER:"0.9.944"};w.bgs_Available=!1,w.bgs_CheckRunned=!1,function(e){e.fn.extend({sbi_imgLiquid:function(i){this.defaults={fill:!0,verticalAlign:"center",horizontalAlign:"center",useBackgroundSize:!0,useDataHtmlAttr:!0,responsive:!0,delay:0,fadeInTime:0,removeBoxBackground:!0,hardPixels:!0,responsiveCheckTime:500,timecheckvisibility:500,onStart:null,onFinish:null,onItemStart:null,onItemFinish:null,onItemError:null},function(){if(!w.bgs_CheckRunned){w.bgs_CheckRunned=!0;var i=e('<span style="background-size:cover" />');e("body").append(i),function(){var e=i[0];if(e&&window.getComputedStyle){var a=window.getComputedStyle(e,null);a&&a.backgroundSize&&(w.bgs_Available="cover"===a.backgroundSize)}}(),i.remove()}}();var a=this;return this.options=i,this.settings=e.extend({},this.defaults,this.options),this.settings.onStart&&this.settings.onStart(),this.each(function(i){function t(){(o.responsive||c.data("sbi_imgLiquid_oldProcessed"))&&c.data("sbi_imgLiquid_settings")&&(o=c.data("sbi_imgLiquid_settings"),d.actualSize=d.get(0).offsetWidth+d.get(0).offsetHeight/1e4,d.sizeOld&&d.actualSize!==d.sizeOld&&r(),d.sizeOld=d.actualSize,setTimeout(t,o.responsiveCheckTime))}function s(){c.data("sbi_imgLiquid_error",!0),d.addClass("sbi_imgLiquid_error"),o.onItemError&&o.onItemError(i,d,c),n()}function r(){var e,a,t,s,r,l,h,u,b=0,f=0,p=d.width(),g=d.height();void 0===c.data("owidth")&&c.data("owidth",c[0].width),void 0===c.data("oheight")&&c.data("oheight",c[0].height),o.fill===p/g>=c.data("owidth")/c.data("oheight")?(e="100%",a="auto",t=Math.floor(p),s=Math.floor(p*(c.data("oheight")/c.data("owidth")))):(e="auto",a="100%",t=Math.floor(g*(c.data("owidth")/c.data("oheight"))),s=Math.floor(g)),r=o.horizontalAlign.toLowerCase(),h=p-t,"left"===r&&(f=0),"center"===r&&(f=.5*h),"right"===r&&(f=h),-1!==r.indexOf("%")&&(r=parseInt(r.replace("%",""),10))>0&&(f=h*r*.01),l=o.verticalAlign.toLowerCase(),u=g-s,"left"===l&&(b=0),"center"===l&&(b=.5*u),"bottom"===l&&(b=u),-1!==l.indexOf("%")&&(l=parseInt(l.replace("%",""),10))>0&&(b=u*l*.01),o.hardPixels&&(e=t,a=s),c.css({width:e,height:a,"margin-left":Math.floor(f),"margin-top":Math.floor(b)}),c.data("sbi_imgLiquid_oldProcessed")||(c.fadeTo(o.fadeInTime,1),c.data("sbi_imgLiquid_oldProcessed",!0),o.removeBoxBackground&&d.css("background-image","none"),d.addClass("sbi_imgLiquid_nobgSize"),d.addClass("sbi_imgLiquid_ready")),o.onItemFinish&&o.onItemFinish(i,d,c),n()}function n(){i===a.length-1&&a.settings.onFinish&&a.settings.onFinish()}var o=a.settings,d=e(this),c=e("img:first",d);return c.length?(c.data("sbi_imgLiquid_settings")?(d.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"),o=e.extend({},c.data("sbi_imgLiquid_settings"),a.options)):o=e.extend({},a.settings,function(){var e={};if(a.settings.useDataHtmlAttr){var i=d.attr("data-sbi_imgLiquid-fill"),t=d.attr("data-sbi_imgLiquid-horizontalAlign"),s=d.attr("data-sbi_imgLiquid-verticalAlign");("true"===i||"false"===i)&&(e.fill=Boolean("true"===i)),void 0===t||"left"!==t&&"center"!==t&&"right"!==t&&-1===t.indexOf("%")||(e.horizontalAlign=t),void 0===s||"top"!==s&&"bottom"!==s&&"center"!==s&&-1===s.indexOf("%")||(e.verticalAlign=s)}return w.isIE&&a.settings.ieFadeInDisabled&&(e.fadeInTime=0),e}()),c.data("sbi_imgLiquid_settings",o),o.onItemStart&&o.onItemStart(i,d,c),void(w.bgs_Available&&o.useBackgroundSize?(-1===d.css("background-image").indexOf(encodeURI(c.attr("src")))&&d.css({"background-image":'url("'+encodeURI(c.attr("src"))+'")'}),d.css({"background-size":o.fill?"cover":"contain","background-position":(o.horizontalAlign+" "+o.verticalAlign).toLowerCase(),"background-repeat":"no-repeat"}),e("a:first",d).css({display:"block",width:"100%",height:"100%"}),e("img",d).css({display:"none"}),o.onItemFinish&&o.onItemFinish(i,d,c),d.addClass("sbi_imgLiquid_bgSize"),d.addClass("sbi_imgLiquid_ready"),n()):function a(){if(c.data("oldSrc")&&c.data("oldSrc")!==c.attr("src")){var n=c.clone().removeAttr("style");return n.data("sbi_imgLiquid_settings",c.data("sbi_imgLiquid_settings")),c.parent().prepend(n),c.remove(),(c=n)[0].width=0,void setTimeout(a,10)}return c.data("sbi_imgLiquid_oldProcessed")?void r():(c.data("sbi_imgLiquid_oldProcessed",!1),c.data("oldSrc",c.attr("src")),e("img:not(:first)",d).css("display","none"),d.css({overflow:"hidden"}),c.fadeTo(0,0).removeAttr("width").removeAttr("height").css({visibility:"visible","max-width":"none","max-height":"none",width:"auto",height:"auto",display:"block"}),c.on("error",s),c[0].onerror=s,function e(){c.data("sbi_imgLiquid_error")||c.data("sbi_imgLiquid_loaded")||c.data("sbi_imgLiquid_oldProcessed")||(d.is(":visible")&&c[0].complete&&c[0].width>0&&c[0].height>0?(c.data("sbi_imgLiquid_loaded",!0),setTimeout(r,i*o.delay)):setTimeout(e,o.timecheckvisibility))}(),void t())}())):void s()})}})}(jQuery),s=w.injectCss,b=document.getElementsByTagName("head")[0],(p=document.createElement("style")).type="text/css",p.styleSheet?p.styleSheet.cssText=s:p.appendChild(document.createTextNode(s)),b.appendChild(p),o.find(".sbi_photo").sbi_imgLiquid({fill:!0})}var y,x,I,k,j=(y=0,function(e,i){clearTimeout(y),y=setTimeout(e,i)});function S(){if("thumbnail"!==g){var e=o.find(".sbi_photo").eq(0).innerWidth(),i=sbiGetColumnCount(o,parseInt(h),parseInt(h)),a=jQuery("#sbi_images").innerWidth()-jQuery("#sbi_images").width(),t=o.find("#sbi_images").width()/i-a;e<=t&&(e=t),o.find(".sbi_photo").css("height",e);var s=o.find(".sbi_photo").eq(0).innerWidth()/2;"px"==v&&(s+=2*parseInt(_)),o.find(".sbi_owl-buttons div").css("top",s)}}function F(){o.removeClass("sbi_small sbi_medium");var e=o.find(".sbi_item").innerWidth();e>120&&e<240?o.addClass("sbi_medium"):e<=120&&o.addClass("sbi_small")}jQuery(window).resize(function(){j(function(){S(),F(),jQuery(".sbi").each(function(){var e=jQuery(this),i=jQuery(this).attr("data-sbi-index");if(sbiSizeSVG(e),"auto"===e.attr("data-res")){var a=window.sbiFeedMeta[i].minRes,t=sbiGetResolutionSettings(e,"auto",h,u,i);sbiNeedToRaiseRes(""!==t.width?t.width:sbiGetWidthForResType(t.type),a)&&(window.sbiFeedMeta[i].minRes=640,e.find(".sbi_item").each(function(){var e=jQuery(this).find(".sbi_photo").attr("data-full-res"),i=jQuery(this).find(".sbi_photo img").attr("src"),t=jQuery(this);""===e&&(i.indexOf("p"+a+"x"+a)>-1?e=i.replace("p"+a+"x"+a,"p640x640"):i.indexOf("s"+a+"x"+a)>-1&&(e=i.replace("s"+a+"x"+a,"s640x640"))),t.find(".sbi_photo img").attr("src",e),t.find(".sbi_photo").css("background-image",'url("'+e+'")')}))}})},500)}),S(),x=jQuery,I={callback:function(){},runOnLoad:!0,frequency:100,sbiPreviousVisibility:null},k={sbiCheckVisibility:function(e,i){if(jQuery.contains(document,e[0])){var a=i.sbiPreviousVisibility,t=e.is(":visible");i.sbiPreviousVisibility=t,null==a?i.runOnLoad&&i.callback(e,t):a!==t&&i.callback(e,t),setTimeout(function(){k.sbiCheckVisibility(e,i)},i.frequency)}}},x.fn.sbiVisibilityChanged=function(e){var i=x.extend({},I,e);return this.each(function(){k.sbiCheckVisibility(x(this),i)})},jQuery(".sbi").filter(":hidden").sbiVisibilityChanged({callback:function(e,i){S(),F()},runOnLoad:!1}),F(),f.disablecache||void 0===e||"fetched"!==window.sbiCacheStatuses[f.feedIndex].feed||(e(i,t,C),window.sbiCacheStatuses[f.feedIndex].feed="cached"),R="finished",sbSVGify(o)}(O,F.feed);var T=10;o.find(".sbi_transition").each(function(){var e=jQuery(this);setTimeout(function(){e.removeClass("sbi_transition")},T),T+=10,e.find(".sbi_photo").find("img").on("error",function(){jQuery(this).hasClass("sbi_img_error")||(jQuery(this).addClass("sbi_img_error"),"undefined"!==jQuery(this).closest(".sbi_photo").attr("href")&&(jQuery(this).attr("src",jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m"),jQuery(this).closest(".sbi_photo").css("background-image","url("+jQuery(this).closest(".sbi_photo").attr("href")+"media?size=m)")))})}),V="",o.find("#sbi_images > .sbi_loader").remove(),o.find("#sbi_load").removeClass("sbi_hidden"),r>=l&&o.find(".sbi_load_btn").show(),setTimeout(function(){d.find(".sbi_loader").addClass("sbi_hidden"),d.find(".sbi_btn_text").removeClass("sbi_hidden")},500)}}function W(e,i){if(void 0===e.meta.error_message){var a=i.feedOptions,t="";a.headercolor.length&&(t='style="color: #'+a.headercolor+'"'),u='<a href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" title="@'+e.data.username+'" class="sbi_header_link" '+t+">",u+='<div class="sbi_header_text">';var s="";(void 0!==e.data.bio&&e.data.bio.length<1||"true"!=a.showbio)&&(s=' class="sbi_no_bio"'),u+="<h3 "+t+s+">"+e.data.username+"</h3>";var r='<p class="sbi_bio_info" ';"boxed"==a.headerstyle?r+='style="color: #'+a.headerprimarycolor+';"':r+=t,void 0!==e.data.bio&&e.data.bio.length>1&&""!=a.showbio&&"false"!=a.showbio&&(u+='<p class="sbi_bio" '+t+">"+e.data.bio+"</p>"),u+="</div>",u+='<div class="sbi_header_img">',u+='<div class="sbi_header_img_hover"><i class="sbi_new_logo"></i></div>',u+='<img src="'+e.data.profile_picture+'" alt="'+e.data.full_name+'" width="50" height="50">',u+="</div>",u+="</a>","boxed"==a.headerstyle&&(u+='<div class="sbi_header_bar" style="background: #'+a.headersecondarycolor+'">',"false"!=a.showbio&&(u+=r),u+='<a class="sbi_header_follow_btn" href="https://www.instagram.com/'+e.data.username+'" target="_blank" rel="noopener" style="color: #'+a.headercolor+"; background: #"+a.headerprimarycolor+';"><i class="sbi_new_logo"></i><span></span></div></div>'),0==n.find(".sbi_header_link").length&&n.find(".sb_instagram_header").prepend(u),n.find(".sbi_follow_btn").length&&n.find(".sbi_follow_btn a").attr("href","https://www.instagram.com/"+e.data.username),"boxed"==a.headerstyle&&n.find(".sbi_header_follow_btn").length&&n.find(".sbi_header_follow_btn span").text(n.find(".sb_instagram_header").attr("data-follow-text").replace(/\\/g,"")),n.find(".sb_instagram_header .sbi_header_link").hover(function(){n.find(".sb_instagram_header .sbi_header_img_hover").addClass("sbi_fade_in")},function(){n.find(".sb_instagram_header .sbi_header_img_hover").removeClass("sbi_fade_in")}),sbSVGify(n.find(".sb_instagram_header"))}}function D(e,a,t,s){var n=(y=e).length,o=t.getType;if(0==n)r+parseInt(t.num)>=O.data.length&&jQuery("#sbi_load .sbi_load_btn").hide();else{var d=[],l=n;jQuery.each(y,function(e,r){jQuery.ajax({method:"GET",url:r,dataType:"jsonp",success:function(n){var h=n.meta.error_message,u="",b="";if(void 0!==h){if(u+='<p><i class="fa fab fa-instagram" style="font-size: 16px; position: relative; top: 1px;"></i>&nbsp; Instagram Feed Error</p>',h.indexOf("access_token")>-1){u+="<p><b>Error: Access Token is not valid or has expired</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>There's an issue with the Instagram Access Token that you are using. Please obtain a new Access Token on the plugin's Settings page.<br />If you continue to have an issue with your Access Token then please see <a href='https://smashballoon.com/my-instagram-access-token-keep-expiring/' target='_blank' rel='noopener'>this FAQ</a> for more information.</p>",jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>"),sbiAddTokenToExpiredList(sb_instagram_js_options.sb_instagram_at,a);var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};return void jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}})}if(h.indexOf("retired")>-1)return u+="<p><b>No longer possible to display this feed</b><br /><span>This error message is only visible to WordPress admins</span></p>",b="<p>Due to changes in the Instagram API, it is no longer possible to display a feed from an Instagram account which is not your own. You can now only display your own Instagram account. Please see <a href='https://smashballoon.com/instagram-api-changes-april-4-2018/' target='_blank' rel='noopener'>this post</a> for more information.</p>",void jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+u+b+"</div>");if(void 0!==n.code&&"429"==n.code){window.sbiFeedMeta[i].error={errorMsg:"<p><b>Error: Rate Limit Reached</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Backup cache will be used for 1 hour</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>");var f={action:"sbi_set_use_backup",transientName:a,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:f,success:function(e){}}),n="error"}else h.indexOf("user does not exist")>-1||h.indexOf("you cannot view this resource")>-1?(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: User ID <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist, is invalid, or is private</b><br /><span>This error is only visible to WordPress admins</span>",errorDir:"<p>Please double check that the Instagram User ID you are using is valid and not from a private account. To find your User ID simply enter your Instagram user name into this <a href='https://smashballoon.com/instagram-feed/find-instagram-user-id/' target='_blank' rel='noopener'>tool</a>.</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error"):h.indexOf("invalid media id")>-1&&(window.sbiFeedMeta[i].error={errorMsg:'<p><b>Error: Post Id <span class="sbiErrorIds">'+window.sbiFeedMeta[i].idsInFeed[e]+"</span> does not exist or is invalid</b><br /><span>This error is only visible to WordPress admins.</span>",errorDir:"<p>Please double check the media (post) id is correct.</p>"},s.find("#sbi_mod_error").length?-1==s.find(".sbiErrorIds").text().indexOf(window.sbiFeedMeta[i].idsInFeed[e])&&s.find(".sbiErrorIds").append(","+window.sbiFeedMeta[i].idsInFeed[e]):s.prepend('<div id="sbi_mod_error">'+window.sbiFeedMeta[i].error.errorMsg+window.sbiFeedMeta[i].error.errorDir+"</div>"),n="error")}"coordinates"==o&&(n.pagination={previous_url:r}),"error"!==n&&d.push(n),0==--l&&"finished"!==R&&function(e){var i=[],r=[];jQuery.each(d,function(a,t){if("single"==e&&(t.data=[t.data]),void 0!==t.data)if(jQuery.each(t.data,function(e,i){jQuery.inArray(i.id,E)>-1||(E.push(i.id),r.push(i))}),"coordinates"==e){var s=t.data[t.data.length-1].created_time,n=t.pagination.previous_url.split("max_timestamp=")[0]+"max_timestamp="+s;i.push(n)}else"object"==typeof t.pagination&&t.pagination&&void 0!==t.pagination.next_url&&i.push(t.pagination.next_url)}),"random"!==c?r.sort(function(e,i){return i.created_time-e.created_time}):(r.sort(function(e,i){return Math.round(Math.random())-.5}),a+="!"),void 0!==d&&(d[0].data=r),void 0!==d[0].pagination&&d[0].pagination?d[0].pagination.next_url=i:d[0].pagination={next_url:""};var n=d[0];"finished"!==R&&G(n,a,t,s),N++}(o)}})})}}function A(e,i,t,r,n){var o=e;window.sbiCommentCacheStatus=0;var d=t[0].getAttribute("data-sbi-index");"object"==typeof e&&(o=JSON.stringify(e));var c={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"get_cache",transientName:o,useBackupHeader:window.sbiUseBackup[d].header,useBackupFeed:window.sbiUseBackup[d].feed},success:function(n){var o={};if(0===n.trim().indexOf("{")&&((n.indexOf("{%22")>-1||n.indexOf("%7B%22")>-1)&&(n=decodeURI(n)),n=(n=n.replace(/\\'/g,"'")).replace(/\\'/g,"'"),o=JSON.parse(n.trim())),"all"==r){if(void 0===o.header.error&&W(o.header,i),void 0===o.feed.error){if("finished"!==R&&G(o.feed,e,i,t),void 0!==o.warning){var d="<p><b>Cache Error: Looking for cache that doesn't exist. Now using a backup feed.</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").before('<div id="sbi_mod_error">'+d+c+"</div>")}}else{s=JSON.parse(t[0].getAttribute("data-options"));var l=t[0].getAttribute("data-sbi-index");if(s.feedIndex=l,!1!==window.sbiCacheStatuses[l].feed&&"tryfetch"===o.feed.error)window.sbiCacheStatuses[l].feed=!1,t.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1),window.sbiCacheStatuses[l].comments="no",s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&a(t[0],s);else if(!0===window.sbiCacheStatuses[l].feed){var d="<p><b>Cache Error: Looking for cache that doesn't exist</b><br /><span>This error is only visible to WordPress admins.</span>",c="<p>If you are using a caching plugin, try enabling the option on the Customize tab 'Cache error API recheck' or 'Force cache to clear on interval'</p>";jQuery("#sb_instagram").empty().append('<p style="text-align: center;">Unable to show Instagram photos</p><div id="sbi_mod_error">'+d+c+"</div>");var h={action:"sbi_set_use_backup",transientName:e,context:"falsecache"};jQuery.ajax({url:sbiajaxurl,type:"post",data:h,success:function(e){}})}}if("tryfetch"===o.header.error){s=JSON.parse(t[0].getAttribute("data-options"));var l=t[0].getAttribute("data-sbi-index");s.feedIndex=l,!1!==window.sbiCacheStatuses[l].header&&(t.find(".sb_instagram_header .sbi_header_text").length||(window.sbiCacheStatuses[l].header=!1,s.tryFetch=!0,void 0===window.sbiCacheStatuses[s.feedIndex].tryFetch&&a(t[0],s)))}void 0===o.comments.error&&(sb_instagram_js_options.sbiPageCommentCache=o.comments)}else"header"==r?W(o,i):"finished"!==R&&G(o,e,i,t)},error:function(e,i,a){console.log(a)}};jQuery.ajax(c)}}(t,s)},a)})}function sbiAddTokenToExpiredList(e,i){var a={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"sbi_set_expired_token",access_token:e,transientName:i},success:function(e){},error:function(e,i,a){console.log(a)}};jQuery.ajax(a)}function sbiCachePhotos(e,i,a){a=void 0!==a?a:[];var t=e.data.length;if(void 0!==e){var s={url:sbiajaxurl,type:"POST",async:!0,cache:!1,data:{action:"cache_photos",feed_tokens:a,num_images:t,transientName:i},success:function(e){},error:function(e,i,a){console.log(a)}};jQuery.ajax(s)}}function sbiGetColumnCount(e,i,a){var t=i,s=window.innerWidth;return e.hasClass("sbi_mob_col_auto")?(s<640&&parseInt(i)>2&&parseInt(i)<7&&(t=2),s<640&&parseInt(i)>6&&parseInt(i)<11&&(t=4),s<=480&&parseInt(i)>2&&(t=1)):s<=480&&(t=a),t}function sbiGetWidthForResType(e){switch(e){case"thumbnail":return 150;case"low_resolution":return 320;default:return 640}}function sbiGetBestResolutionForAuto(e,i,a,t){var s=e*Math.max(1,i/a),r=10*Math.ceil(s/10),n=[150,320,640];if(t&&(r*=2),-1===n.indexOf(parseInt(r))){var o=!1;jQuery.each(n,function(e,i){i>parseInt(r)&&!o&&(r=i,o=!0)})}return r}function sbiNeedToRaiseRes(e,i){return e>i}function sbiGetResolutionSettings(e,i,a,t,s){var r=parseInt(e.find("#sbi_images").outerWidth()-e.find("#sbi_images").width())/2,n=(a=sbiGetColumnCount(e,parseInt(a),parseInt(t)),e.innerWidth()/a-r),o={type:"low_resolution",width:""};switch(i){case"auto":o.type="auto",o.width=n;break;case"thumb":o.type="thumbnail";break;case"medium":o.type="low_resolution";break;default:o.type="standard_resolution"}return void 0===window.sbiFeedMeta[s].minRes&&(window.sbiFeedMeta[s].minRes="auto"===o.type?sbiGetBestResolutionForAuto(n,o.width,o.width,e.hasClass("sbi_highlight")):sbiGetWidthForResType(o.type)),o}function sbi_cache_all(e,i,a){i.indexOf("header")&&void 0===e.data.pagination?sbiCachePhotos(e,i,a):i.indexOf("header")||void 0===e.data.pagination||sbiCachePhotos(e,i,a)}jQuery(document).ready(function(){window.sbiCommentCacheStatus=0,sbi_init(function(e,i,a){sbi_cache_all(e,i,a)})})}
1
+ var sbi_js_exists=void 0!==sbi_js_exists;sbi_js_exists||(!function(i){function e(){var i,e,t,s=s||{VER:"0.9.944"};s.bgs_Available=!1,s.bgs_CheckRunned=!1,function(i){i.fn.extend({sbi_imgLiquid:function(e){this.defaults={fill:!0,verticalAlign:"center",horizontalAlign:"center",useBackgroundSize:!0,useDataHtmlAttr:!0,responsive:!0,delay:0,fadeInTime:0,removeBoxBackground:!0,hardPixels:!0,responsiveCheckTime:500,timecheckvisibility:500,onStart:null,onFinish:null,onItemStart:null,onItemFinish:null,onItemError:null},function(){if(!s.bgs_CheckRunned){s.bgs_CheckRunned=!0;var e=i('<span style="background-size:cover" />');i("body").append(e),function(){var i=e[0];if(i&&window.getComputedStyle){var t=window.getComputedStyle(i,null);t&&t.backgroundSize&&(s.bgs_Available="cover"===t.backgroundSize)}}(),e.remove()}}();var t=this;return this.options=e,this.settings=i.extend({},this.defaults,this.options),this.settings.onStart&&this.settings.onStart(),this.each(function(e){function a(){(r.responsive||h.data("sbi_imgLiquid_oldProcessed"))&&h.data("sbi_imgLiquid_settings")&&(r=h.data("sbi_imgLiquid_settings"),l.actualSize=l.get(0).offsetWidth+l.get(0).offsetHeight/1e4,l.sizeOld&&l.actualSize!==l.sizeOld&&o(),l.sizeOld=l.actualSize,setTimeout(a,r.responsiveCheckTime))}function n(){h.data("sbi_imgLiquid_error",!0),l.addClass("sbi_imgLiquid_error"),r.onItemError&&r.onItemError(e,l,h),d()}function o(){var i,t,s,a,n,o,g,u,f=0,m=0,c=l.width(),_=l.height();void 0===h.data("owidth")&&h.data("owidth",h[0].width),void 0===h.data("oheight")&&h.data("oheight",h[0].height),r.fill===c/_>=h.data("owidth")/h.data("oheight")?(i="100%",t="auto",s=Math.floor(c),a=Math.floor(c*(h.data("oheight")/h.data("owidth")))):(i="auto",t="100%",s=Math.floor(_*(h.data("owidth")/h.data("oheight"))),a=Math.floor(_)),g=c-s,"left"===(n=r.horizontalAlign.toLowerCase())&&(m=0),"center"===n&&(m=.5*g),"right"===n&&(m=g),-1!==n.indexOf("%")&&((n=parseInt(n.replace("%",""),10))>0&&(m=g*n*.01)),u=_-a,"left"===(o=r.verticalAlign.toLowerCase())&&(f=0),"center"===o&&(f=.5*u),"bottom"===o&&(f=u),-1!==o.indexOf("%")&&((o=parseInt(o.replace("%",""),10))>0&&(f=u*o*.01)),r.hardPixels&&(i=s,t=a),h.css({width:i,height:t,"margin-left":Math.floor(m),"margin-top":Math.floor(f)}),h.data("sbi_imgLiquid_oldProcessed")||(h.fadeTo(r.fadeInTime,1),h.data("sbi_imgLiquid_oldProcessed",!0),r.removeBoxBackground&&l.css("background-image","none"),l.addClass("sbi_imgLiquid_nobgSize"),l.addClass("sbi_imgLiquid_ready")),r.onItemFinish&&r.onItemFinish(e,l,h),d()}function d(){e===t.length-1&&t.settings.onFinish&&t.settings.onFinish()}var r=t.settings,l=i(this),h=i("img:first",l);return h.length?(h.data("sbi_imgLiquid_settings")?(l.removeClass("sbi_imgLiquid_error").removeClass("sbi_imgLiquid_ready"),r=i.extend({},h.data("sbi_imgLiquid_settings"),t.options)):r=i.extend({},t.settings,function(){var i={};if(t.settings.useDataHtmlAttr){var e=l.attr("data-sbi_imgLiquid-fill"),a=l.attr("data-sbi_imgLiquid-horizontalAlign"),n=l.attr("data-sbi_imgLiquid-verticalAlign");("true"===e||"false"===e)&&(i.fill=Boolean("true"===e)),void 0===a||"left"!==a&&"center"!==a&&"right"!==a&&-1===a.indexOf("%")||(i.horizontalAlign=a),void 0===n||"top"!==n&&"bottom"!==n&&"center"!==n&&-1===n.indexOf("%")||(i.verticalAlign=n)}return s.isIE&&t.settings.ieFadeInDisabled&&(i.fadeInTime=0),i}()),h.data("sbi_imgLiquid_settings",r),r.onItemStart&&r.onItemStart(e,l,h),void(s.bgs_Available&&r.useBackgroundSize?(-1===l.css("background-image").indexOf(encodeURI(h.attr("src")))&&l.css({"background-image":'url("'+encodeURI(h.attr("src"))+'")'}),l.css({"background-size":r.fill?"cover":"contain","background-position":(r.horizontalAlign+" "+r.verticalAlign).toLowerCase(),"background-repeat":"no-repeat"}),i("a:first",l).css({display:"block",width:"100%",height:"100%"}),i("img",l).css({display:"none"}),r.onItemFinish&&r.onItemFinish(e,l,h),l.addClass("sbi_imgLiquid_bgSize"),l.addClass("sbi_imgLiquid_ready"),d()):function t(){if(h.data("oldSrc")&&h.data("oldSrc")!==h.attr("src")){var s=h.clone().removeAttr("style");return s.data("sbi_imgLiquid_settings",h.data("sbi_imgLiquid_settings")),h.parent().prepend(s),h.remove(),(h=s)[0].width=0,void setTimeout(t,10)}return h.data("sbi_imgLiquid_oldProcessed")?void o():(h.data("sbi_imgLiquid_oldProcessed",!1),h.data("oldSrc",h.attr("src")),i("img:not(:first)",l).css("display","none"),l.css({overflow:"hidden"}),h.fadeTo(0,0).removeAttr("width").removeAttr("height").css({visibility:"visible","max-width":"none","max-height":"none",width:"auto",height:"auto",display:"block"}),h.on("error",n),h[0].onerror=n,function i(){h.data("sbi_imgLiquid_error")||h.data("sbi_imgLiquid_loaded")||h.data("sbi_imgLiquid_oldProcessed")||(l.is(":visible")&&h[0].complete&&h[0].width>0&&h[0].height>0?(h.data("sbi_imgLiquid_loaded",!0),setTimeout(o,e*r.delay)):setTimeout(i,r.timecheckvisibility))}(),void a())}())):void n()})}})}(jQuery),i=s.injectCss,e=document.getElementsByTagName("head")[0],(t=document.createElement("style")).type="text/css",t.styleSheet?t.styleSheet.cssText=i:t.appendChild(document.createTextNode(i)),e.appendChild(t)}function t(){this.feeds={},this.options=sb_instagram_js_options}function s(i,e,t){this.el=i,this.index=e,this.settings=t,this.minImageWidth=0,this.imageResolution=150,this.resizedImages={},this.needsResizing=[],this.outOfPages=!1,this.isInitialized=!1}function a(e,t){i.ajax({url:sbiajaxurl,type:"post",data:e,success:t})}t.prototype={createPage:function(e,t){void 0!==window.sbiajaxurl&&-1!==window.sbiajaxurl.indexOf(window.location.hostname)||(window.sbiajaxurl=window.location.hostname+"/wp-admin/admin-ajax.php"),i(".sbi_no_js_error_message").remove(),i(".sbi_no_js").removeClass("sbi_no_js"),e(t)},createFeeds:function(e){e.whenFeedsCreated(i(".sbi").each(function(e){i(this).attr("data-sbi-index",e+1);var t=i(this),n=void 0!==t.attr("data-sbi-flags")?t.attr("data-sbi-flags").split(","):[],o=void 0!==t.attr("data-options")?JSON.parse(t.attr("data-options")):{};if(n.indexOf("testAjax")>-1){window.sbi.triggeredTest=!0;a({action:"sbi_on_ajax_test_trigger"},function(i){console.log("did test")})}var d={cols:t.attr("data-cols"),colsmobile:"same"!==t.attr("data-colsmobile")?t.attr("data-colsmobile"):t.attr("data-cols"),num:t.attr("data-num"),imgRes:t.attr("data-res"),feedID:t.attr("data-feedid"),shortCodeAtts:t.attr("data-shortcode-atts"),resizingEnabled:-1===n.indexOf("resizeDisable"),imageLoadEnabled:-1===n.indexOf("imageLoadDisable"),debugEnabled:n.indexOf("debug")>-1,favorLocal:n.indexOf("favorLocal")>-1,ajaxPostLoad:n.indexOf("ajaxPostLoad")>-1,autoMinRes:1,general:o};window.sbi.feeds[e]=function(i,e,t){return new s(i,e,t)}(this,e,d),window.sbi.feeds[e].setResizedImages(),window.sbi.feeds[e].init();var r=jQuery.Event("sbiafterfeedcreate");r.feed=window.sbi.feeds[e],jQuery(window).trigger(r)}))},afterFeedsCreated:function(){i(".sb_instagram_header").each(function(){var e=i(this);e.find(".sbi_header_link").hover(function(){e.find(".sbi_header_img_hover").addClass("sbi_fade_in")},function(){e.find(".sbi_header_img_hover").removeClass("sbi_fade_in")})})},encodeHTML:function(i){return void 0===i?"":i.replace(/(>)/g,"&gt;").replace(/(<)/g,"&lt;").replace(/(&lt;br\/&gt;)/g,"<br>").replace(/(&lt;br&gt;)/g,"<br>")},urlDetect:function(i){return i.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/g)}},s.prototype={init:function(){var i,e=this;if(this.settings.ajaxPostLoad)this.getNewPostSet();else{this.afterInitialImagesLoaded();var t=(i=0,function(e,t){clearTimeout(i),i=setTimeout(e,t)});jQuery(window).resize(function(){t(function(){e.afterResize()},500)})}},initLayout:function(){},afterInitialImagesLoaded:function(){this.initLayout(),this.loadMoreButtonInit(),this.hideExtraImagesForWidth(),this.beforeNewImagesRevealed(),this.revealNewImages(),this.afterNewImagesRevealed()},afterResize:function(){this.setImageHeight(),this.setImageResolution(),this.maybeRaiseImageResolution(),this.setImageSizeClass()},afterLoadMoreClicked:function(i){i.find(".sbi_loader").removeClass("sbi_hidden"),i.find(".sbi_btn_text").addClass("sbi_hidden"),i.closest(".sbi").find(".sbi_num_diff_hide").addClass("sbi_transition").removeClass("sbi_num_diff_hide")},afterNewImagesLoaded:function(){var e=i(this.el);this.beforeNewImagesRevealed(),this.revealNewImages(),this.afterNewImagesRevealed(),setTimeout(function(){e.find(".sbi_loader").addClass("sbi_hidden"),e.find(".sbi_btn_text").removeClass("sbi_hidden")},500)},beforeNewImagesRevealed:function(){this.setImageHeight(),this.maybeRaiseImageResolution(!0),this.setImageSizeClass()},revealNewImages:function(){var e=i(this.el);"function"==typeof sbi_custom_js&&setTimeout(function(){sbi_custom_js()},100),this.applyImageLiquid(),e.find(".sbi_item").each(function(i){jQuery(this).find(".sbi_photo").hover(function(){jQuery(this).fadeTo(200,.85)},function(){jQuery(this).stop().fadeTo(500,1)})}),setTimeout(function(){jQuery("#sbi_images .sbi_item.sbi_new").removeClass("sbi_new");var i=10;e.find(".sbi_transition").each(function(){var e=jQuery(this);setTimeout(function(){e.removeClass("sbi_transition")},i),i+=10})},500)},afterNewImagesRevealed:function(){this.listenForVisibilityChange(),this.sendNeedsResizingToServer();var e=i.Event("sbiafterimagesloaded");e.el=i(this.el),i(window).trigger(e)},setResizedImages:function(){i(this.el).find(".sbi_resized_image_data").length&&void 0!==i(this.el).find(".sbi_resized_image_data").attr("data-resized")&&0===i(this.el).find(".sbi_resized_image_data").attr("data-resized").indexOf('{"')&&(this.resizedImages=JSON.parse(i(this.el).find(".sbi_resized_image_data").attr("data-resized")),i(this.el).find(".sbi_resized_image_data").remove())},sendNeedsResizingToServer:function(){var e=this;if(e.needsResizing.length>0&&e.settings.resizingEnabled){var t=i(this.el).find(".sbi_item").length;a({action:"sbi_resized_images_submit",needs_resizing:e.needsResizing,offset:t,feed_id:e.settings.feedID,atts:e.settings.shortCodeAtts},function(i){if(0===i.trim().indexOf("{")){var t=JSON.parse(i);e.settings.debugEnabled&&console.log(t)}})}},loadMoreButtonInit:function(){var e=i(this.el),t=this;e.find("#sbi_load .sbi_load_btn").off().on("click",function(){t.afterLoadMoreClicked(jQuery(this)),t.getNewPostSet()})},getNewPostSet:function(){var e=i(this.el),t=this;a({action:"sbi_load_more_clicked",offset:e.find(".sbi_item").length,feed_id:t.settings.feedID,atts:t.settings.shortCodeAtts,current_resolution:t.imageResolution},function(i){if(0===i.trim().indexOf("{")){var s=JSON.parse(i);t.settings.debugEnabled&&console.log(s),t.appendNewPosts(s.html),t.addResizedImages(s.resizedImages),t.settings.ajaxPostLoad?(t.settings.ajaxPostLoad=!1,t.afterInitialImagesLoaded()):t.afterNewImagesLoaded(),s.feedStatus.shouldPaginate?t.outOfPages=!1:(t.outOfPages=!0,e.find(".sbi_load_btn").hide())}})},appendNewPosts:function(e){var t=i(this.el);t.find("#sbi_images .sbi_item").length?t.find("#sbi_images .sbi_item").last().after(e):t.find("#sbi_images").append(e)},addResizedImages:function(i){for(var e in i)this.resizedImages[e]=i[e]},setImageHeight:function(){var e=i(this.el),t=e.find(".sbi_photo").eq(0).innerWidth(),s=this.getColumnCount(),a=e.find("#sbi_images").innerWidth()-e.find("#sbi_images").width(),n=a/2;sbi_photo_width_manual=e.find("#sbi_images").width()/s-a,e.find(".sbi_photo").css("height",t),e.find(".sbi-owl-nav").length&&setTimeout(function(){var i=2;e.find(".sbi_owl2row-item").length&&(i=1);var t=e.find(".sbi_photo").eq(0).innerWidth()/i;t+=parseInt(n)*(2-i+2),e.find(".sbi-owl-nav div").css("top",t)},100)},maybeRaiseSingleImageResolution:function(e,t,s){var a=this,n=a.getImageUrls(e),o=e.find(".sbi_photo img").attr("src"),d=150,r=e.find("img").get(0),l=o===window.sbi.options.placeholder?1:r.naturalWidth/r.naturalHeight;s=void 0!==s&&s;i.each(n,function(i,e){e===o&&(d=parseInt(i),s=!1)});var h=640;switch(a.settings.imgRes){case"thumb":h=150;break;case"medium":h=320;break;case"full":h=640;break;default:var g=Math.max(a.settings.autoMinRes,e.find(".sbi_photo").innerWidth()),u=a.getBestResolutionForAuto(g,l,e);switch(u){case 320:h=320;break;case 150:h=150}}if(h>d||o===window.sbi.options.placeholder||s){if(a.settings.debugEnabled){var f=o===window.sbi.options.placeholder?"was placeholder":"too small";console.log("rais res for "+o,f)}var m=n[h].split("?ig_cache_key")[0];e.find(".sbi_photo img").attr("src",m),e.find(".sbi_photo").css("background-image",'url("'+m+'")');var c=!1;e.find(".sbi_photo img").on("load",function(){var t=i(this),s=t.get(0).naturalWidth/t.get(0).naturalHeight;if(1e3!==t.get(0).naturalWidth&&s>l&&!c){switch(a.settings.debugEnabled&&console.log("rais res again for aspect ratio change "+o),c=!0,g=e.find(".sbi_photo").innerWidth(),u=a.getBestResolutionForAuto(g,s,e),h=640,u){case 320:h=320;break;case 150:h=150}h>d&&(m=n[h].split("?ig_cache_key")[0],t.attr("src",m),t.closest(".sbi_photo").css("background-image",'url("'+m+'")')),"masonry"!==a.layout&&"highlight"!==a.layout||(i(a.el).find("#sbi_images").smashotope(a.isotopeArgs),setTimeout(function(){i(a.el).find("#sbi_images").smashotope(a.isotopeArgs)},500))}else if(a.settings.debugEnabled){var r=c?"already checked":"no aspect ratio change";console.log("not raising res for replacement "+o,r)}})}e.find("img").on("error",function(){if(i(this).hasClass("sbi_img_error"))console.log("unfixed error "+i(this).attr("src"));else{if(i(this).addClass("sbi_img_error"),i(this).attr("src").indexOf("media?size=")>-1||i(this).attr("src").indexOf("cdninstagram")>-1||i(this).attr("src").indexOf("fbcdn")>-1){a.settings.favorLocal=!0;var e=a.getImageUrls(i(this).closest(".sbi_item"));void 0!==e[640]&&(i(this).attr("src",e[640]),i(this).closest(".sbi_photo").css("background-image","url("+e[640]+")"))}else void 0!==i(this).closest(".sbi_photo").attr("data-full-res")?(i(this).attr("src",i(this).closest(".sbi_photo").attr("data-full-res")),i(this).closest(".sbi_photo").css("background-image","url("+i(this).closest(".sbi_photo").attr("data-full-res")+")")):"undefined"!==i(this).closest(".sbi_photo").attr("href")&&(i(this).attr("src",i(this).closest(".sbi_photo").attr("href")+"media?size=l"),i(this).closest(".sbi_photo").css("background-image","url("+i(this).closest(".sbi_photo").attr("href")+"media?size=l)"));setTimeout(function(){a.afterResize()},1500)}})},maybeRaiseImageResolution:function(e){var t=this,s=void 0!==e&&!0===e?".sbi_item.sbi_new":".sbi_item",a=!t.isInitialized;i(t.el).find(s).each(function(e){!i(this).hasClass("sbi_num_diff_hide")&&i(this).find(".sbi_photo").length&&void 0!==i(this).find(".sbi_photo").attr("data-img-src-set")&&t.maybeRaiseSingleImageResolution(i(this),e,a)}),t.isInitialized=!0},getBestResolutionForAuto:function(e,t,s){(isNaN(t)||t<1)&&(t=1);var a=e*t,n=10*Math.ceil(a/10),o=[150,320,640];if(s.hasClass("sbi_highlighted")&&(n*=2),-1===o.indexOf(parseInt(n))){var d=!1;i.each(o,function(i,e){e>parseInt(n)&&!d&&(n=e,d=!0)})}return n},hideExtraImagesForWidth:function(){if("carousel"!==this.layout){var e=i(this.el),t=void 0!==e.attr("data-num")&&""!==e.attr("data-num")?parseInt(e.attr("data-num")):1,s=void 0!==e.attr("data-nummobile")&&""!==e.attr("data-nummobile")?parseInt(e.attr("data-nummobile")):t;i(window).width()<480?s<e.find(".sbi_item").length&&e.find(".sbi_item").slice(s-e.find(".sbi_item").length).addClass("sbi_num_diff_hide"):t<e.find(".sbi_item").length&&e.find(".sbi_item").slice(t-e.find(".sbi_item").length).addClass("sbi_num_diff_hide")}},setImageSizeClass:function(){var e=i(this.el);e.removeClass("sbi_small sbi_medium");var t=e.innerWidth(),s=parseInt(e.find("#sbi_images").outerWidth()-e.find("#sbi_images").width())/2,a=this.getColumnCount(),n=(t-s*(a+2))/a;n>120&&n<240?e.addClass("sbi_medium"):n<=120&&e.addClass("sbi_small")},setMinImageWidth:function(){i(this.el).find(".sbi_item .sbi_photo").first().length?this.minImageWidth=i(this.el).find(".sbi_item .sbi_photo").first().innerWidth():this.minImageWidth=150},setImageResolution:function(){if("auto"===this.settings.imgRes)this.imageResolution="auto";else switch(this.settings.imgRes){case"thumb":this.imageResolution=150;break;case"medium":this.imageResolution=320;break;default:this.imageResolution=640}},getImageUrls:function(i){var e=JSON.parse(i.find(".sbi_photo").attr("data-img-src-set").replace(/\\\//g,"/")),t=i.attr("id").replace("sbi_","");if(void 0!==this.resizedImages[t]&&"video"!==this.resizedImages[t]&&"pending"!==this.resizedImages[t]&&"error"!==this.resizedImages[t].id&&"video"!==this.resizedImages[t].id&&"pending"!==this.resizedImages[t].id){if(void 0!==this.resizedImages[t].sizes){var s=[];void 0!==this.resizedImages[t].sizes.full&&(s.push(640),e[640]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"full.jpg",i.find(".sbi_link_area").attr("href",sb_instagram_js_options.resized_url+this.resizedImages[t].id+"full.jpg"),i.find(".sbi_photo").attr("data-full-res",sb_instagram_js_options.resized_url+this.resizedImages[t].id+"full.jpg")),void 0!==this.resizedImages[t].sizes.low&&(s.push(320),e[320]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"low.jpg",this.settings.favorLocal&&void 0===this.resizedImages[t].sizes.full&&(i.find(".sbi_link_area").attr("href",sb_instagram_js_options.resized_url+this.resizedImages[t].id+"low.jpg"),i.find(".sbi_photo").attr("data-full-res",sb_instagram_js_options.resized_url+this.resizedImages[t].id+"low.jpg"))),void 0!==this.resizedImages[t].sizes.thumb&&(s.push(150),e[150]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"thumb.jpg"),this.settings.favorLocal&&(-1===s.indexOf(640)&&s.indexOf(320)>-1&&(e[640]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"low.jpg"),-1===s.indexOf(320)&&(s.indexOf(640)>-1?e[320]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"full.jpg":s.indexOf(150)>-1&&(e[320]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"thumb.jpg")),-1===s.indexOf(150)&&(s.indexOf(320)>-1?e[150]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"low.jpg":s.indexOf(640)>-1&&(e[150]=sb_instagram_js_options.resized_url+this.resizedImages[t].id+"full.jpg")))}}else void 0!==this.resizedImages[t]&&"pending"===this.resizedImages[t]||this.addToNeedsResizing(t);return e},addToNeedsResizing:function(i){-1===this.needsResizing.indexOf(i)&&this.needsResizing.push(i)},applyImageLiquid:function(){var t=i(this.el);e(),"function"==typeof t.find(".sbi_photo").sbi_imgLiquid&&t.find(".sbi_photo").sbi_imgLiquid({fill:!0})},listenForVisibilityChange:function(){var e,t,s,a=this;e=jQuery,t={callback:function(){},runOnLoad:!0,frequency:100,sbiPreviousVisibility:null},s={sbiCheckVisibility:function(i,e){if(jQuery.contains(document,i[0])){var t=e.sbiPreviousVisibility,a=i.is(":visible");e.sbiPreviousVisibility=a,null==t?e.runOnLoad&&e.callback(i,a):t!==a&&e.callback(i,a),setTimeout(function(){s.sbiCheckVisibility(i,e)},e.frequency)}}},e.fn.sbiVisibilityChanged=function(i){var a=e.extend({},t,i);return this.each(function(){s.sbiCheckVisibility(e(this),a)})},"function"==typeof i(this.el).filter(":hidden").sbiVisibilityChanged&&i(this.el).filter(":hidden").sbiVisibilityChanged({callback:function(i,e){a.afterResize()},runOnLoad:!1})},getColumnCount:function(){var e=i(this.el),t=this.settings.cols,s=this.settings.colsmobile,a=t;return sbiWindowWidth=window.innerWidth,e.hasClass("sbi_mob_col_auto")?(sbiWindowWidth<640&&parseInt(t)>2&&parseInt(t)<7&&(a=2),sbiWindowWidth<640&&parseInt(t)>6&&parseInt(t)<11&&(a=4),sbiWindowWidth<=480&&parseInt(t)>2&&(a=1)):sbiWindowWidth<=480&&(a=s),parseInt(a)}},window.sbi_init=function(){window.sbi=new t,window.sbi.createPage(window.sbi.createFeeds,{whenFeedsCreated:window.sbi.afterFeedsCreated})}}(jQuery),jQuery(document).ready(function(i){void 0!==window.sb_instagram_js_options.resized_url&&-1===window.sb_instagram_js_options.resized_url.indexOf(location.protocol)&&("http:"===location.protocol?window.sb_instagram_js_options.resized_url=window.sb_instagram_js_options.resized_url.replace("http:","https:"):window.sb_instagram_js_options.resized_url=window.sb_instagram_js_options.resized_url.replace("https:","http:")),sbi_init()}));
languages/instagram-feed-nl_NL.mo ADDED
Binary file
templates/feed.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Feeds for Instagram Main Template
4
+ * Creates the wrapping HTML and adds settings as attributes
5
+ *
6
+ * @version 2.0 Custom Feeds for Instagram Free by Smash Balloon
7
+ *
8
+ */
9
+ // Don't load directly
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ die( '-1' );
12
+ }
13
+ $feed_styles = SB_Instagram_Display_Elements::get_feed_style( $settings ); // already escaped
14
+ $sb_images_style = SB_Instagram_Display_Elements::get_sbi_images_style( $settings ); // already escaped
15
+ $image_resolution_setting = $settings['imageres'];
16
+ $cols_setting = $settings['cols'];
17
+ $num_setting = $settings['num'];
18
+ $icon_type = $settings['font_method'];
19
+
20
+ if ( $settings['showheader'] && ! empty( $posts ) && $settings['headeroutside'] ) {
21
+ include sbi_get_feed_template_part( 'header', $settings );
22
+ }
23
+ ?>
24
+
25
+ <div id="sb_instagram" class="sbi sbi_col_<?php echo esc_attr( $cols_setting ); ?> <?php echo esc_attr( $additional_classes ); ?>"<?php echo $feed_styles; ?> data-feedid="<?php echo esc_attr( $feed_id ); ?>" data-res="<?php echo esc_attr( $image_resolution_setting ); ?>" data-cols="<?php echo esc_attr( $cols_setting ); ?>" data-num="<?php echo esc_attr( $num_setting ); ?>" data-shortcode-atts="<?php echo esc_attr( $shortcode_atts ); ?>" <?php echo $other_atts; ?>>
26
+ <?php
27
+ if ( $settings['showheader'] && ! empty( $posts ) && !$settings['headeroutside'] ) {
28
+ include sbi_get_feed_template_part( 'header', $settings );
29
+ }
30
+ ?>
31
+
32
+ <div id="sbi_images" <?php echo $sb_images_style; ?>>
33
+ <?php
34
+ if ( ! in_array( 'ajaxPostLoad', $flags, true ) ) {
35
+ $this->posts_loop( $posts, $settings );
36
+ }
37
+ ?>
38
+ </div>
39
+
40
+ <?php if ( ! empty( $posts ) ) { include sbi_get_feed_template_part( 'footer', $settings ); } ?>
41
+
42
+ <?php do_action( 'sbi_before_feed_end', $this, $feed_id ); ?>
43
+
44
+ </div>
templates/footer.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Feeds for Instagram Footer Template
4
+ * Adds pagination and html for errors and resized images
5
+ *
6
+ * @version 2.0 Custom Feeds for Instagram Free by Smash Balloon
7
+ *
8
+ */
9
+
10
+ // Don't load directly
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ die( '-1' );
13
+ }
14
+
15
+ $follow_btn_style = SB_Instagram_Display_Elements::get_follow_styles( $settings ); // style="background: rgb();color: rgb();" already escaped
16
+ $follow_btn_classes = strpos( $follow_btn_style, 'background' ) !== false ? ' sbi_custom' : '';
17
+ $show_follow_button = ( $settings['showfollow'] == 'on' || $settings['showfollow'] == 'true' || $settings['showfollow'] == true ) && $settings['showfollow'] !== 'false';
18
+ $follow_button_text = __( $settings['followtext'], 'instagram-feed' );
19
+
20
+ $load_btn_style = SB_Instagram_Display_Elements::get_load_button_styles( $settings ); // style="background: rgb();color: rgb();" already escaped
21
+ $load_btn_classes = strpos( $load_btn_style, 'background' ) !== false ? ' sbi_custom' : '';
22
+ $load_button_text = __( $settings['buttontext'], 'instagram-feed' );
23
+ ?>
24
+ <div id="sbi_load">
25
+
26
+ <?php if ( $use_pagination ) : ?>
27
+ <a class="sbi_load_btn" href="javascript:void(0);" <?php echo $load_btn_style; ?>>
28
+ <span class="sbi_btn_text"><?php echo esc_html( $load_button_text ); ?></span>
29
+ <span class="sbi_loader sbi_hidden" style="background-color: rgb(255, 255, 255);"></span>
30
+ </a>
31
+ <?php endif; ?>
32
+
33
+ <?php if ( $first_username && $show_follow_button ) : ?>
34
+ <span class="sbi_follow_btn<?php echo esc_attr( $follow_btn_classes ); ?>">
35
+ <a href="<?php echo esc_url( 'https://www.instagram.com/' . $first_username ); ?>" <?php echo $follow_btn_style; ?> target="_blank" rel="noopener">
36
+ <?php
37
+ echo SB_Instagram_Display_Elements::get_icon( 'instagram', $icon_type );
38
+ echo esc_html( $follow_button_text );
39
+ ?>
40
+ </a>
41
+ </span>
42
+ <?php endif; ?>
43
+
44
+ </div>
templates/header.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Feeds for Instagram Header Template
4
+ * Adds account information and an avatar to the top of the feed
5
+ *
6
+ * @version 2.0 Custom Feeds for Instagram Free by Smash Balloon
7
+ *
8
+ */
9
+
10
+ // Don't load directly
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ die( '-1' );
13
+ }
14
+ $header_padding = (int)$settings['imagepadding'] > 0 ? 'padding: '.(int)$settings['imagepadding'] . $settings['imagepaddingunit'] . ';' : '';
15
+ $header_margin = (int) $settings['imagepadding'] < 10 ? ' margin-bottom: 10px;' : '';
16
+
17
+ $username = SB_Instagram_Parse::get_username( $header_data );
18
+ $avatar = SB_Instagram_Parse::get_avatar( $header_data, $settings );
19
+ $name = SB_Instagram_Parse::get_name( $header_data );
20
+ $header_text_color_style = SB_Instagram_Display_Elements::get_header_text_color_styles( $settings ); // style="color: #517fa4;" already escaped
21
+
22
+ ?>
23
+ <div class="sb_instagram_header" style="<?php echo $header_padding . $header_margin; ?>padding-bottom: 0;">
24
+ <a href="https://www.instagram.com/<?php echo urlencode( $username ); ?>" target="_blank" rel="noopener" title="@<?php echo esc_attr( $username ); ?>" class="sbi_header_link">
25
+ <div class="sbi_header_text">
26
+ <h3 class="sbi_no_bio" <?php echo $header_text_color_style; ?>><?php echo esc_html( $username ); ?></h3>
27
+ </div>
28
+ <div class="sbi_header_img" data-avatar-url="<?php echo esc_attr( SB_Instagram_Parse::get_avatar( $header_data ) ); ?>">
29
+ <div class="sbi_header_img_hover"><?php echo SB_Instagram_Display_Elements::get_icon( 'newlogo', $icon_type ); ?></div>
30
+ <img src="<?php echo esc_url( $avatar ); ?>" alt="<?php echo esc_attr( $name ); ?>" width="50" height="50">
31
+ </div>
32
+ </a>
33
+ </div>
templates/item.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom Feeds for Instagram Item Template
4
+ * Adds an image, link, and other data for each post in the feed
5
+ *
6
+ * @version 2.0 Custom Feeds for Instagram Free by Smash Balloon
7
+ *
8
+ */
9
+
10
+ // Don't load directly
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ die( '-1' );
13
+ }
14
+ $classes = SB_Instagram_Display_Elements::get_item_classes( $settings, $offset );
15
+ $post_id = SB_Instagram_Parse::get_post_id( $post );
16
+ $timestamp = SB_Instagram_Parse::get_timestamp( $post );
17
+ $media_type = SB_Instagram_Parse::get_media_type( $post );
18
+ $permalink = SB_Instagram_Parse::get_permalink( $post );
19
+ $maybe_carousel_icon = $media_type === 'carousel' ? SB_Instagram_Display_Elements::get_icon( 'carousel', $icon_type ) : '';
20
+ $maybe_video_icon = $media_type === 'video' ? SB_Instagram_Display_Elements::get_icon( 'video', $icon_type ) : '';
21
+ $media_url = SB_Instagram_Display_Elements::get_optimum_media_url( $post, $settings );
22
+ $media_full_res = SB_Instagram_Parse::get_media_url( $post );
23
+ $sbi_photo_style_element = SB_Instagram_Display_Elements::get_sbi_photo_style_element( $post, $settings ); // has already been escaped
24
+ $media_all_sizes_json = SB_Instagram_Parse::get_media_src_set( $post );
25
+ $img_alt = SB_Instagram_Parse::get_caption( $post, __( 'Image for post', 'instagram-feed' ) . ' ' . $post_id );
26
+
27
+ ?>
28
+ <div class="sbi_item sbi_type_<?php echo esc_attr( $media_type ); ?><?php echo esc_attr( $classes ); ?>" id="sbi_<?php echo esc_html( $post_id ); ?>" data-date="<?php echo esc_html( $timestamp ); ?>">
29
+ <div class="sbi_photo_wrap">
30
+ <a class="sbi_photo" href="<?php echo esc_url( $permalink ); ?>" target="_blank" rel="noopener" data-full-res="<?php echo esc_url( $media_full_res ); ?>" data-img-src-set="<?php echo esc_attr( wp_json_encode( $media_all_sizes_json ) ); ?>"<?php echo $sbi_photo_style_element; ?>>
31
+ <span class="sbi-screenreader"><?php echo sprintf( __( 'Instagram post %s', 'instagram-feed' ), $post_id ); ?></span>
32
+ <?php echo $maybe_carousel_icon; ?>
33
+ <?php echo $maybe_video_icon; ?>
34
+ <img src="<?php echo esc_url( $media_url ); ?>" alt="<?php echo esc_attr( $img_alt ); ?>" width="200" height="200">
35
+ </a>
36
+ </div>
37
+ </div>