rtMedia for WordPress, BuddyPress and bbPress - Version 3.10

Version Description

Requires BuddyPress 1.7 or higher, if using BuddyPress. Added update BuddyPress activity privacy feature, added BuddyPress activity for media likes and comments feature.

=

Download this release

Release Info

Developer rtcamp
Plugin Icon 128x128 rtMedia for WordPress, BuddyPress and bbPress
Version 3.10
Comparing to
See all releases

Code changes from version 3.9.5 to 3.10

Files changed (93) hide show
  1. app/admin/RTMediaFormHandler.php +23 -1
  2. app/assets/js/rtMedia.js +34 -1
  3. app/assets/js/rtmedia.min.js +1 -1
  4. app/helper/RTMediaSettings.php +3 -1
  5. app/main/controllers/activity/RTMediaBuddyPressActivity.php +211 -0
  6. app/main/controllers/media/RTMediaMedia.php +1 -1
  7. app/main/controllers/privacy/RTMediaPrivacy.php +147 -24
  8. app/main/controllers/template/rt-template-functions.php +1 -1
  9. app/main/controllers/upload/RTMediaUploadView.php +1 -1
  10. index.php +34 -1
  11. languages/buddypress-media.mo +0 -0
  12. languages/buddypress-media.po +2983 -1588
  13. lib/freemius/LICENSE.txt +340 -0
  14. lib/freemius/assets/css/admin/account.css +1 -0
  15. lib/freemius/assets/css/admin/add-ons.css +2 -0
  16. lib/freemius/assets/css/admin/common.css +1 -0
  17. lib/freemius/assets/css/admin/connect.css +1 -0
  18. lib/freemius/assets/css/admin/deactivation-feedback.css +1 -0
  19. lib/freemius/assets/css/common.css +1 -0
  20. lib/freemius/assets/img/icon.png +0 -0
  21. lib/freemius/assets/img/plugin-icon.png +0 -0
  22. lib/freemius/assets/js/jquery.ba-postmessage.js +222 -0
  23. lib/freemius/assets/js/jquery.ba-postmessage.min.js +9 -0
  24. lib/freemius/assets/js/nojquery.ba-postmessage.js +140 -0
  25. lib/freemius/assets/js/nojquery.ba-postmessage.min.js +12 -0
  26. lib/freemius/assets/js/postmessage.js +110 -0
  27. lib/freemius/assets/scss/_colors.scss +58 -0
  28. lib/freemius/assets/scss/_functions.scss +0 -0
  29. lib/freemius/assets/scss/_load.scss +4 -0
  30. lib/freemius/assets/scss/_mixins.scss +224 -0
  31. lib/freemius/assets/scss/_start.scss +4 -0
  32. lib/freemius/assets/scss/_vars.scss +5 -0
  33. lib/freemius/assets/scss/admin/account.scss +122 -0
  34. lib/freemius/assets/scss/admin/add-ons.scss +319 -0
  35. lib/freemius/assets/scss/admin/common.scss +109 -0
  36. lib/freemius/assets/scss/admin/connect.scss +405 -0
  37. lib/freemius/assets/scss/admin/deactivation-feedback.scss +120 -0
  38. lib/freemius/config.php +161 -0
  39. lib/freemius/includes/class-freemius-abstract.php +382 -0
  40. lib/freemius/includes/class-freemius.php +7698 -0
  41. lib/freemius/includes/class-fs-api.php +354 -0
  42. lib/freemius/includes/class-fs-logger.php +168 -0
  43. lib/freemius/includes/class-fs-plugin-updater.php +253 -0
  44. lib/freemius/includes/class-fs-security.php +61 -0
  45. lib/freemius/includes/entities/class-fs-entity.php +149 -0
  46. lib/freemius/includes/entities/class-fs-plugin-info.php +34 -0
  47. lib/freemius/includes/entities/class-fs-plugin-license.php +160 -0
  48. lib/freemius/includes/entities/class-fs-plugin-plan.php +71 -0
  49. lib/freemius/includes/entities/class-fs-plugin-tag.php +24 -0
  50. lib/freemius/includes/entities/class-fs-plugin.php +90 -0
  51. lib/freemius/includes/entities/class-fs-scope-entity.php +29 -0
  52. lib/freemius/includes/entities/class-fs-site.php +119 -0
  53. lib/freemius/includes/entities/class-fs-subscription.php +117 -0
  54. lib/freemius/includes/entities/class-fs-user.php +62 -0
  55. lib/freemius/includes/fs-core-functions.php +461 -0
  56. lib/freemius/includes/fs-plugin-functions.php +411 -0
  57. lib/freemius/includes/i18n.php +247 -0
  58. lib/freemius/includes/managers/class-fs-admin-menu-manager.php +544 -0
  59. lib/freemius/includes/managers/class-fs-admin-notice-manager.php +303 -0
  60. lib/freemius/includes/managers/class-fs-key-value-storage.php +291 -0
  61. lib/freemius/includes/managers/class-fs-license-manager.php +101 -0
  62. lib/freemius/includes/managers/class-fs-option-manager.php +297 -0
  63. lib/freemius/includes/managers/class-fs-plan-manager.php +147 -0
  64. lib/freemius/includes/managers/class-fs-plugin-manager.php +154 -0
  65. lib/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php +2 -0
  66. lib/freemius/includes/sdk/Exceptions/EmptyArgumentException.php +2 -0
  67. lib/freemius/includes/sdk/Exceptions/Exception.php +75 -0
  68. lib/freemius/includes/sdk/Exceptions/InvalidArgumentException.php +2 -0
  69. lib/freemius/includes/sdk/Exceptions/OAuthException.php +8 -0
  70. lib/freemius/includes/sdk/Freemius.php +403 -0
  71. lib/freemius/includes/sdk/FreemiusBase.php +217 -0
  72. lib/freemius/includes/sdk/LICENSE.txt +340 -0
  73. lib/freemius/start.php +95 -0
  74. lib/freemius/templates/account.php +442 -0
  75. lib/freemius/templates/add-ons.php +113 -0
  76. lib/freemius/templates/admin-notice.php +34 -0
  77. lib/freemius/templates/all-admin-notice.php +31 -0
  78. lib/freemius/templates/checkout.php +242 -0
  79. lib/freemius/templates/connect.php +175 -0
  80. lib/freemius/templates/contact.php +72 -0
  81. lib/freemius/templates/deactivation-feedback-modal.php +196 -0
  82. lib/freemius/templates/debug.php +103 -0
  83. lib/freemius/templates/email.php +42 -0
  84. lib/freemius/templates/firewall-issues-js.php +49 -0
  85. lib/freemius/templates/pending-activation.php +146 -0
  86. lib/freemius/templates/plugin-icon.php +58 -0
  87. lib/freemius/templates/plugin-info/description.php +63 -0
  88. lib/freemius/templates/plugin-info/features.php +81 -0
  89. lib/freemius/templates/plugin-info/screenshots.php +19 -0
  90. lib/freemius/templates/powered-by.php +37 -0
  91. lib/freemius/templates/pricing.php +96 -0
  92. lib/freemius/templates/sticky-admin-notice-js.php +36 -0
  93. readme.txt +7 -3
app/admin/RTMediaFormHandler.php CHANGED
@@ -1006,7 +1006,7 @@ class RTMediaFormHandler {
1006
  ),
1007
  'group' => 10,
1008
  ),
1009
- 'rtmedia-enable-notification' => array(
1010
  'title' => __( 'Enable media notification', 'buddypress-media' ),
1011
  'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
1012
  'args' => array(
@@ -1017,6 +1017,28 @@ class RTMediaFormHandler {
1017
  ),
1018
  'group' => 10,
1019
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1020
  'general_enableAlbums' => array(
1021
  'title' => __( 'Organize media into albums', 'buddypress-media' ),
1022
  'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
1006
  ),
1007
  'group' => 10,
1008
  ),
1009
+ 'rtmedia-enable-notification' => array(
1010
  'title' => __( 'Enable media notification', 'buddypress-media' ),
1011
  'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
1012
  'args' => array(
1017
  ),
1018
  'group' => 10,
1019
  ),
1020
+ 'rtmedia-enable-like-activity' => array(
1021
+ 'title' => __( 'Create activity for media likes', 'buddypress-media' ),
1022
+ 'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
1023
+ 'args' => array(
1024
+ 'key' => 'buddypress_mediaLikeActivity',
1025
+ 'value' => $options[ 'buddypress_mediaLikeActivity' ],
1026
+ 'desc' => __( 'Enabling this setting will create BuddyPress activity for media likes.', 'buddypress-media' ),
1027
+
1028
+ ),
1029
+ 'group' => 10,
1030
+ ),
1031
+ 'rtmedia-enable-comment-activity' => array(
1032
+ 'title' => __( 'Create activity for media comments', 'buddypress-media' ),
1033
+ 'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
1034
+ 'args' => array(
1035
+ 'key' => 'buddypress_mediaCommentActivity',
1036
+ 'value' => $options[ 'buddypress_mediaCommentActivity' ],
1037
+ 'desc' => __( 'Enabling this setting will create BuddyPress activity for media comments.', 'buddypress-media' ),
1038
+
1039
+ ),
1040
+ 'group' => 10,
1041
+ ),
1042
  'general_enableAlbums' => array(
1043
  'title' => __( 'Organize media into albums', 'buddypress-media' ),
1044
  'callback' => array( 'RTMediaFormHandler', 'checkbox' ),
app/assets/js/rtMedia.js CHANGED
@@ -336,7 +336,7 @@ jQuery( 'document' ).ready( function ( $ ) {
336
  jQuery( '.rtmedia-container' ).on( 'click', '.rtmedia-delete-selected', function ( e ) {
337
  if ( jQuery( '.rtmedia-list :checkbox:checked' ).length > 0 ) {
338
  if ( confirm( rtmedia_selected_media_delete_confirmation ) ) {
339
- jQuery( this ).closest( 'form' ).attr( 'action', '../../../' + rtmedia_media_slug + '/delete' ).submit();
340
  }
341
  } else {
342
  rtmedia_gallery_action_alert_message( rtmedia_no_media_selected, 'warning' );
@@ -354,6 +354,39 @@ jQuery( 'document' ).ready( function ( $ ) {
354
 
355
  } );
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  function rtmedia_media_view_counts() {
358
  //var view_count_action = jQuery('#rtmedia-media-view-form').attr("action");
359
  if ( jQuery( '#rtmedia-media-view-form' ).length > 0 ) {
336
  jQuery( '.rtmedia-container' ).on( 'click', '.rtmedia-delete-selected', function ( e ) {
337
  if ( jQuery( '.rtmedia-list :checkbox:checked' ).length > 0 ) {
338
  if ( confirm( rtmedia_selected_media_delete_confirmation ) ) {
339
+ jQuery( this ).closest( 'form' ).attr( 'action', '../../../' + rtmedia_media_slug + '/delete' ).submit();
340
  }
341
  } else {
342
  rtmedia_gallery_action_alert_message( rtmedia_no_media_selected, 'warning' );
354
 
355
  } );
356
 
357
+ jQuery( '#buddypress' ).on( 'change', '.rtm-activity-privacy-opt', function(){
358
+
359
+ var activity_id = jQuery( this ).attr( 'id');
360
+ activity_id = activity_id.split( '-' );
361
+ activity_id = activity_id[ activity_id.length - 1 ];
362
+
363
+ var that = this;
364
+
365
+ data = {
366
+ activity_id : activity_id,
367
+ privacy : jQuery( this ).val(),
368
+ nonce : jQuery( '#rtmedia_activity_privacy_nonce' ).val(),
369
+ action : 'rtm_change_activity_privacy'
370
+ };
371
+
372
+ jQuery.post( ajaxurl, data, function( res ){
373
+ var message = '';
374
+ var css_class = '';
375
+ if( res == "true" ){
376
+ message = "Privacy updated successfully.";
377
+ css_class = 'success';
378
+ } else {
379
+ message = "Couldn't change privacy, please try again.";
380
+ css_class = 'fail';
381
+ }
382
+
383
+ jQuery( that ).after( '<p class="rtm-ac-privacy-updated '+ css_class +'">'+ message +'</p>' );
384
+ setTimeout( function(){
385
+ jQuery( that ).siblings( '.rtm-ac-privacy-updated').remove();
386
+ }, 2000 );
387
+ } );
388
+ } );
389
+
390
  function rtmedia_media_view_counts() {
391
  //var view_count_action = jQuery('#rtmedia-media-view-form').attr("action");
392
  if ( jQuery( '#rtmedia-media-view-form' ).length > 0 ) {
app/assets/js/rtmedia.min.js CHANGED
@@ -3,4 +3,4 @@
3
  * @package rtMedia
4
  */
5
  function apply_rtMagnificPopup(a){jQuery("document").ready(function(b){var c="";c="undefined"==typeof rtmedia_load_more?"Loading media":rtmedia_load_more,"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&(b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").length>0&&b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").addClass("no-popup"),rtMagnificPopup=jQuery(a).magnificPopup({delegate:"a:not(.no-popup, .mejs-time-slider, .mejs-volume-slider, .mejs-horizontal-volume-slider)",type:"ajax",tLoading:c+" #%curr%...",mainClass:"mfp-img-mobile",preload:[1,3],closeOnBgClick:!0,gallery:{enabled:!0,navigateByImgClick:!0,arrowMarkup:"",preload:[0,1]},image:{tError:'<a href="%url%">The image #%curr%</a> could not be loaded.',titleSrc:function(a){return a.el.attr("title")+"<small>by Marsel Van Oosten</small>"}},callbacks:{ajaxContentAdded:function(){a=jQuery.magnificPopup.instance,1===jQuery(a.items).size()&&jQuery(".mfp-arrow").remove();var a=jQuery.magnificPopup.instance,c=a.currItem.el,d=c.parent();if(d.is("li")||(d=d.parent()),d.is(":nth-last-child(2)")||d.is(":last-child")){d.next();"block"==jQuery("#rtMedia-galary-next").css("display")&&jQuery("#rtMedia-galary-next").click()}var e=a.items.length;if(a.index==e-1&&!d.is(":last-child"))return void c.click();var f={};"undefined"!=typeof _wpmejsSettings&&(f.pluginPath=_wpmejsSettings.pluginPath),b(".mfp-content .wp-audio-shortcode,.mfp-content .wp-video-shortcode,.mfp-content .bp_media_content video").mediaelementplayer({defaultVideoWidth:480,defaultVideoHeight:270,success:function(a,b){a.play()}}),b(".mfp-content .mejs-audio .mejs-controls").css("position","relative"),rtMediaHook.call("rtmedia_js_popup_after_content_added",[])},close:function(a){rtmedia_init_action_dropdown()},BeforeChange:function(a){}}}))})}function rtmedia_init_action_dropdown(){var a,b;jQuery(".click-nav > span, .click-nav > div").toggleClass("no-js js"),jQuery(".click-nav .js ul").hide(),jQuery(".click-nav .clicker").click(function(c){a=jQuery("#rtm-media-options .click-nav .clicker").next("ul"),b=jQuery(this).next("ul"),jQuery.each(a,function(a,c){jQuery(c).html()!=b.html()&&jQuery(c).hide()}),jQuery(b).toggle(),c.stopPropagation()})}function bp_media_create_element(a){return!1}function rtmedia_version_compare(a,b){if(typeof a+typeof b!="stringstring")return!1;for(var c=a.split("."),d=b.split("."),e=0,f=Math.max(c.length,d.length);f>e;e++){if(c[e]&&!d[e]&&parseInt(c[e])>0||parseInt(c[e])>parseInt(d[e]))return!0;if(d[e]&&!c[e]&&parseInt(d[e])>0||parseInt(c[e])<parseInt(d[e]))return!1}return!0}function rtm_is_element_exist(a){return jQuery(a).length>0?!0:!1}function rtm_masonry_reload(a){setTimeout(function(){a.masonry("reload")},250)}function rtmediaGetParameterByName(a){a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var b=new RegExp("[\\?&]"+a+"=([^&#]*)"),c=b.exec(location.search);return null==c?"":decodeURIComponent(c[1].replace(/\+/g," "))}function rtmedia_single_media_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning"),jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","0.2"),jQuery(".rtmedia-single-media .rtmedia-media").after("<div class='rtmedia-message-container'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","1"),jQuery(".rtmedia-message-container").remove()},3e3),jQuery(".rtmedia-message-container").click(function(){jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","1"),jQuery(".rtmedia-message-container").remove()})}function rtmedia_gallery_action_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning");var d='<div class="rtmedia-gallery-alert-container"> </div>';jQuery("body").append(d),jQuery(".rtmedia-gallery-alert-container").append("<div class='rtmedia-gallery-message-box'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-gallery-alert-container").remove()},3e3),jQuery(".rtmedia-gallery-message-box").click(function(){jQuery(".rtmedia-gallery-alert-container").remove()})}!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h="Close",i="BeforeClose",j="AfterClose",k="BeforeAppend",l="MarkupParse",m="Open",n="Change",o="mfp",p="."+o,q="mfp-ready",r="mfp-removing",s="mfp-prevent-close",t=function(){},u=!!window.jQuery,v=a(window),w=function(a,c){b.ev.on(o+a+p,c)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(c,d){b.ev.triggerHandler(o+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},z=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(b=new t,b.init(),a.magnificPopup.instance=b)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};t.prototype={constructor:t,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=B(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(c.isObj===!1){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=x("bg").on("click"+p,function(){b.close()}),b.wrap=x("wrap").attr("tabindex",-1).on("click"+p,function(a){b._checkIfClose(a.target)&&b.close()}),b.container=x("container",b.wrap)),b.contentContainer=x("content"),b.st.preloader&&(b.preloader=x("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var j=i[e];j=j.charAt(0).toUpperCase()+j.slice(1),b["init"+j].call(b)}y("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(w(l,function(a,b,c,d){c.close_replaceWith=z(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(z())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}):b.wrap.css({top:v.scrollTop(),position:"absolute"}),(b.st.fixedBgPos===!1||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup"+p,function(a){27===a.keyCode&&b.close()}),v.on("resize"+p,function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var k=b.wH=v.height(),n={};if(b.fixedContentPos&&b._hasScrollBar(k)){var o=b._getScrollbarSize();o&&(n.marginRight=o)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):n.overflow="hidden");var r=b.st.mainClass;return b.isIE7&&(r+=" mfp-ie7"),r&&b._addClassToMFP(r),b.updateItemHTML(),y("BuildControls"),a("html").css(n),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP(q),b._setFocus()):b.bgOverlay.addClass(q),d.on("focusin"+p,b._onFocusIn)},16),b.isOpen=!0,b.updateSize(k),y(m),c},close:function(){b.isOpen&&(y(i),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP(r),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){y(h);var c=r+" "+q+" ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup"+p+" focusin"+p),b.ev.off(p),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&b.currTemplate[b.currItem.type]!==!0||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,y(j)},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||v.height();b.fixedContentPos||b.wrap.css("height",b.wH),y("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(y("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=b.st[d]?b.st[d].markup:!1;y("FirstMarkupParse",f),f?b.currTemplate[d]=a(f):b.currTemplate[d]=!0}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,y(n,c),e=c.type,b.container.prepend(b.contentContainer),y("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&b.currTemplate[c]===!0?b.content.find(".mfp-close").length||b.content.append(z()):b.content=a:b.content="",y(k),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,y("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){var f=void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick;if(f||2!==c.which&&!c.ctrlKey&&!c.metaKey){var g=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(g)if(a.isFunction(g)){if(!g.call(b))return!0}else if(v.width()<g)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};y("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass(s)){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||v.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){return c.target===b.wrap[0]||a.contains(b.wrap[0],c.target)?void 0:(b._setFocus(),!1)},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(l,[b,c,d]),a.each(c,function(a,c){if(void 0===c||c===!1)return!0;if(e=a.split("_"),e.length>1){var d=b.find(p+"-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(p+"-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:t.prototype,modules:[],open:function(b,c){return A(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&times;</button>',tClose:"Close (Esc)",tLoading:"Loading..."}},a.fn.magnificPopup=function(c){A();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=u?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),u?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var C,D,E,F="inline",G=function(){E&&(D.after(E.addClass(C)).detach(),E=null)};a.magnificPopup.registerModule(F,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push(F),w(h+"."+F,function(){G()})},getInline:function(c,d){if(G(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(D||(C=e.hiddenClass,D=x(C),C="mfp-"+C),E=f.after(D).detach().removeClass(C)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var H,I="ajax",J=function(){H&&a(document.body).removeClass(H)},K=function(){J(),b.req&&b.req.abort()};a.magnificPopup.registerModule(I,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push(I),H=b.st.ajax.cursor,w(h+"."+I,K),w("BeforeChange."+I,K)},getAjax:function(c){H&&a(document.body).addClass(H),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};y("ParseAjax",g),b.appendContent(a(g.data),I),c.finished=!0,J(),b._setFocus(),setTimeout(function(){b.wrap.addClass(q)},16),b.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var L,M=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),w(m+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),w(h+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),v.off("resize"+p)}),w("Resize"+d,b.resizeImage),b.isLowIE&&w("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){L&&clearInterval(L),L=setInterval(function(){return d.naturalWidth>0?void b._onImageHasSize(a):(c>200&&clearInterval(L),c++,void(3===c?e(10):40===c?e(50):100===c&&e(500)))},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,y("ImageLoadComplete")):(e++,200>e?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:M(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(L&&clearInterval(L),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var N,O=function(){return void 0===N&&(N=void 0!==document.createElement("p").style.MozTransform),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,j=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},k=function(){b.content.css("visibility","visible")};w("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),a=b._getItemToZoom(),!a)return void k();f=j(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){k(),setTimeout(function(){f.remove(),a=f=null,y("ZoomAnimationEnded")},16)},g)},16)}}),w(i+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(a=b._getItemToZoom(),!a)return;f=j(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),w(h+d,function(){b._allowZoom()&&(k(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return b.currItem.hasSize?b.currItem.img:!1},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(u?d.innerHeight():d[0].offsetHeight)-g-f};return O()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var P="iframe",Q="//about:blank",R=function(a){if(b.currTemplate[P]){var c=b.currTemplate[P].find("iframe");c.length&&(a||(c[0].src=Q),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(x("b",e[0],!1,!0),x("a",e[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){v.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g,h=a(this);if(c){var i,j,k,l,m,n;h.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,v.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)&&(l=!0,d())}).on("touchend"+f,function(a){d(),l||n>1||(g=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){g=!1},b),e())})})}h.on("click"+f,function(){g||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&v.off("touchmove"+f+" touchend"+f)}}(),A()}),"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick();var e="false"===c.$elem.attr("data-hash")?!1:!0;if(e===!0){var f=b.location.hash;f&&c.$elem.find("li").find("a[href="+f+"]").trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find("a[href="+a+"]").trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li"),e=d.find("a");e.on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");a(f).removeClass("hide");var g="false"===c.$elem.attr("data-hash")?!1:!0;if(g===!0){var h=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(h)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){var c=this,d=c.$elem.find("li"),e=d.find("a");e.each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document);var rtMagnificPopup,rtm_masonry_container,rtMediaHook={hooks:[],is_break:!1,register:function(a,b){"undefined"==typeof rtMediaHook.hooks[a]&&(rtMediaHook.hooks[a]=[]),rtMediaHook.hooks[a].push(b)},call:function(a,b){if("undefined"!=typeof rtMediaHook.hooks[a])for(i=0;i<rtMediaHook.hooks[a].length;++i)if(1!=rtMediaHook.hooks[a][i](b))return rtMediaHook.is_break=!0,!1;return!0}};jQuery("document").ready(function(a){function b(){if(jQuery("#rtmedia-media-view-form").length>0){var a=jQuery("#rtmedia-media-view-form").attr("action");jQuery.post(a,{},function(a){})}}function c(){var a=jQuery.magnificPopup.instance;jQuery(".mfp-arrow-right").on("click",function(b){a.next()}),jQuery(".mfp-arrow-left").on("click",function(b){a.prev()}),jQuery(".mfp-content .rtmedia-media").swipe({swipeLeft:function(b,c,d,e,f){a.next()},swipeRight:function(b,c,d,e,f){a.prev()},threshold:0})}function d(){jQuery(document).on("focusin","#comment_content",function(){jQuery(document).unbind("keydown")}),jQuery(document).on("focusout","#comment_content",function(){var a=jQuery.magnificPopup.instance;jQuery(document).on("keydown",function(b){37===b.keyCode?a.prev():39===b.keyCode&&a.next()})})}function e(){jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()})}a(".rtm-tabs").rtTab(),jQuery(".rtmedia-modal-link").length>0&&a(".rtmedia-modal-link").magnificPopup({type:"inline",midClick:!0,closeBtnInside:!0}),a("#rt_media_comment_form").submit(function(b){return""==a.trim(a("#comment_content").val())?(0==jQuery("#rtmedia-single-media-container").length?rtmedia_gallery_action_alert_message(rtmedia_empty_comment_msg,"warning"):rtmedia_single_media_alert_message(rtmedia_empty_comment_msg,"warning"),!1):!0}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&apply_rtMagnificPopup(".rtmedia-list-media, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||"undefined"==typeof b.data||"undefined"==typeof b.data.action)return!0}catch(d){return!0}if("activity_get_older_updates"==b.data.action){var e=b.success;a.success=function(a){e(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}else if("get_single_activity_content"==b.data.action){var e=b.success;a.success=function(a){e(a),setTimeout(function(){apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update:first-child .wp-audio-shortcode, ul.activity-list li.rtmedia_update:first-child .wp-video-shortcode").mediaelementplayer({defaultVideoWidth:480,defaultVideoHeight:270})},900)}}}),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||"undefined"==typeof b.data||"undefined"==typeof b.data.action)return!0}catch(d){return!0}if("activity_get_older_updates"==b.data.action){var e=b.success;a.success=function(a){e(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}}),jQuery(".rtmedia-container").on("click",".select-all",function(a){jQuery(this).toggleClass("unselect-all").toggleClass("select-all"),jQuery(this).attr("title",rtmedia_unselect_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!0)}),jQuery(".rtmedia-list-item").addClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".unselect-all",function(a){jQuery(this).toggleClass("select-all").toggleClass("unselect-all"),jQuery(this).attr("title",rtmedia_select_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!1)}),jQuery(".rtmedia-list-item").removeClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".rtmedia-move",function(a){jQuery(".rtmedia-delete-container").slideUp(),jQuery(".rtmedia-move-container").slideToggle()}),jQuery("#rtmedia-create-album-modal").on("click","#rtmedia_create_new_album",function(b){if($albumname=jQuery.trim(jQuery("#rtmedia_album_name").val()),$context=jQuery.trim(jQuery("#rtmedia_album_context").val()),$context_id=jQuery.trim(jQuery("#rtmedia_album_context_id").val()),$privacy=jQuery.trim(jQuery("#rtmedia_select_album_privacy").val()),$create_album_nonce=jQuery.trim(jQuery("#rtmedia_create_album_nonce").val()),""!=$albumname){var c={action:"rtmedia_create_album",
6
- name:$albumname,context:$context,context_id:$context_id,create_album_nonce:$create_album_nonce};""!==$privacy&&(c.privacy=$privacy),a("#rtmedia_create_new_album").attr("disabled","disabled");var d=a("#rtmedia_create_new_album").html();a("#rtmedia_create_new_album").prepend("<img src='"+rMedia_loading_file+"' />"),jQuery.post(rtmedia_ajax_url,c,function(b){if(b=jQuery.parseJSON(b),"undefined"!=typeof b.album){b=jQuery.trim(b.album);var c=!0;jQuery(".rtmedia-user-album-list").each(function(){if(jQuery(this).children("optgroup").each(function(){return jQuery(this).attr("value")===$context?(c=!1,void jQuery(this).append('<option value="'+b+'">'+$albumname+"</option>")):void 0}),c){var a=$context.charAt(0).toUpperCase()+$context.slice(1),d='<optgroup value="'+$context+'" label="'+a+' Albums"><option value="'+b+'">'+$albumname+"</option></optgroup>";jQuery(this).append(d)}}),jQuery('select.rtmedia-user-album-list option[value="'+b+'"]').prop("selected",!0),jQuery(".rtmedia-create-new-album-container").slideToggle(),jQuery("#rtmedia_album_name").val(""),jQuery("#rtmedia-create-album-modal").append("<div class='rtmedia-success rtmedia-create-album-alert'><b>"+$albumname+"</b>"+rtmedia_album_created_msg+"</div>"),setTimeout(function(){jQuery(".rtmedia-create-album-alert").remove()},4e3),setTimeout(function(){galleryObj.reloadView(),jQuery(".close-reveal-modal").click()},2e3)}else"undefined"!=typeof b.error?rtmedia_gallery_action_alert_message(b.error,"warning"):rtmedia_gallery_action_alert_message(rtmedia_something_wrong_msg,"warning");a("#rtmedia_create_new_album").removeAttr("disabled"),a("#rtmedia_create_new_album").html(d)})}else rtmedia_gallery_action_alert_message(rtmedia_empty_album_name_msg,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_delete_confirmation)&&jQuery(this).closest("form").attr("action","../../../"+rtmedia_media_slug+"/delete").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-move-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_move_confirmation)&&jQuery(this).closest("form").attr("action","").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),b(),rtMediaHook.register("rtmedia_js_popup_after_content_added",function(){b(),e(),mfp=jQuery.magnificPopup.instance,jQuery(mfp.items).size()>1&&c(),d();var f=a(window).height();jQuery(".rtm-lightbox-container .mejs-video").css({height:.8*f,"max-height":.8*f,"over-flow":"hidden"}),jQuery(".mfp-content .rtmedia-media").css({"max-height":.87*f,"over-flow":"hidden"}),rtmedia_init_action_dropdown(),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").shorten({showChars:130});var g=a(".rtm-gallery-title"),h="";h=a.isEmptyObject(g)?a("#subnav.item-list-tabs li.selected ").html():g.html(),""!=h&&a(".rtm-ltb-gallery-title .ltb-title").html(h);var i=a("#subnav.item-list-tabs li.selected span").html();return a("li.total").html(i),!0});var f=jQuery("#drag-drop-area"),g=jQuery("#whats-new");f.html();jQuery("#rtmedia-upload-container").after("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&jQuery("#whats-new-textarea").append("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),jQuery(document).on("dragover",function(a){jQuery("#rtm-media-gallery-uploader").show(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&g.addClass("rtm-drag-drop-active"),f.addClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").show()}).on("dragleave",function(a){a.preventDefault(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(g.removeClass("rtm-drag-drop-active"),g.removeAttr("style")),f.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}).on("drop",function(a){a.preventDefault(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(g.removeClass("rtm-drag-drop-active"),g.removeAttr("style")),f.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-album",function(a){a.preventDefault(),confirm(rtmedia_album_delete_confirmation)&&jQuery(this).closest("form").submit()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()}),rtmedia_init_action_dropdown(),a(document).click(function(){a(".click-nav ul").is(":visible")&&a(".click-nav ul",this).hide()}),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").length>0&&a(".rtm-more").shorten({showChars:200}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&(rtm_masonry_container=jQuery(".rtmedia-container .rtmedia-list"),rtm_masonry_container.masonry({itemSelector:".rtmedia-list-item"}),setInterval(function(){jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(rtm_masonry_container)},1e3),jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())})),jQuery(".rtm-uploader-tabs").length>0&&jQuery(".rtm-uploader-tabs li").click(function(a){jQuery(this).hasClass("active")||(jQuery(this).siblings().removeClass("active"),jQuery(this).parents(".rtm-uploader-tabs").siblings().hide(),class_name=jQuery(this).attr("class"),jQuery(this).parents(".rtm-uploader-tabs").siblings('[data-id="'+class_name+'"]').show(),jQuery(this).addClass("active"),"rtm-upload-tab"!=class_name?jQuery("div.moxie-shim").children("input[type=file]").hide():jQuery("div.moxie-shim").children("input[type=file]").show())}),jQuery(".rtmedia-container").on("click",".rtm-delete-media",function(a){a.preventDefault();var b="Are you sure you want to delete this media?";if("undefined"!=typeof rtmedia_media_delete_confirmation&&(b=rtmedia_media_delete_confirmation),confirm(b)){var c=jQuery(this).closest("li"),d=jQuery("#rtmedia_media_delete_nonce").val(),e={action:"delete_uploaded_media",nonce:d,media_id:c.attr("id")};jQuery.ajax({url:ajaxurl,type:"post",data:e,success:function(a){"1"==a?(rtmedia_gallery_action_alert_message("file deleted successfully.","success"),c.remove(),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)):rtmedia_gallery_action_alert_message(rtmedia_file_not_deleted,"warning")}})}})}),function(a){a.fn.shorten=function(b){var c={showChars:100,ellipsesText:"...",moreText:"more",lessText:"less"};return b&&a.extend(c,b),a(document).off("click",".morelink"),a(document).on({click:function(){var b=a(this);return b.hasClass("less")?(b.removeClass("less"),b.html(c.moreText)):(b.addClass("less"),b.html(c.lessText)),b.parent().prev().toggle(),b.prev().toggle(),!1}},".morelink"),this.each(function(){var b=a(this);if(!b.hasClass("shortened")){b.addClass("shortened");var d=b.html();if(d.length>c.showChars){var e=d.substr(0,c.showChars),f=d.substr(c.showChars,d.length-c.showChars),g=e+'<span class="moreellipses">'+c.ellipsesText+' </span><span class="morecontent"><span>'+f+'</span> <a href="#" class="morelink">'+c.moreText+"</a></span>";b.html(g),a(".morecontent span").hide()}}})}}(jQuery),window.onload=function(){"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)};
3
  * @package rtMedia
4
  */
5
  function apply_rtMagnificPopup(a){jQuery("document").ready(function(b){var c="";c="undefined"==typeof rtmedia_load_more?"Loading media":rtmedia_load_more,"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&(b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").length>0&&b(".activity-item .rtmedia-activity-container .rtmedia-list-item > a").siblings("p").children("a").addClass("no-popup"),rtMagnificPopup=jQuery(a).magnificPopup({delegate:"a:not(.no-popup, .mejs-time-slider, .mejs-volume-slider, .mejs-horizontal-volume-slider)",type:"ajax",tLoading:c+" #%curr%...",mainClass:"mfp-img-mobile",preload:[1,3],closeOnBgClick:!0,gallery:{enabled:!0,navigateByImgClick:!0,arrowMarkup:"",preload:[0,1]},image:{tError:'<a href="%url%">The image #%curr%</a> could not be loaded.',titleSrc:function(a){return a.el.attr("title")+"<small>by Marsel Van Oosten</small>"}},callbacks:{ajaxContentAdded:function(){a=jQuery.magnificPopup.instance,1===jQuery(a.items).size()&&jQuery(".mfp-arrow").remove();var a=jQuery.magnificPopup.instance,c=a.currItem.el,d=c.parent();if(d.is("li")||(d=d.parent()),d.is(":nth-last-child(2)")||d.is(":last-child")){d.next();"block"==jQuery("#rtMedia-galary-next").css("display")&&jQuery("#rtMedia-galary-next").click()}var e=a.items.length;if(a.index==e-1&&!d.is(":last-child"))return void c.click();var f={};"undefined"!=typeof _wpmejsSettings&&(f.pluginPath=_wpmejsSettings.pluginPath),b(".mfp-content .wp-audio-shortcode,.mfp-content .wp-video-shortcode,.mfp-content .bp_media_content video").mediaelementplayer({defaultVideoWidth:480,defaultVideoHeight:270,success:function(a,b){a.play()}}),b(".mfp-content .mejs-audio .mejs-controls").css("position","relative"),rtMediaHook.call("rtmedia_js_popup_after_content_added",[])},close:function(a){rtmedia_init_action_dropdown()},BeforeChange:function(a){}}}))})}function rtmedia_init_action_dropdown(){var a,b;jQuery(".click-nav > span, .click-nav > div").toggleClass("no-js js"),jQuery(".click-nav .js ul").hide(),jQuery(".click-nav .clicker").click(function(c){a=jQuery("#rtm-media-options .click-nav .clicker").next("ul"),b=jQuery(this).next("ul"),jQuery.each(a,function(a,c){jQuery(c).html()!=b.html()&&jQuery(c).hide()}),jQuery(b).toggle(),c.stopPropagation()})}function bp_media_create_element(a){return!1}function rtmedia_version_compare(a,b){if(typeof a+typeof b!="stringstring")return!1;for(var c=a.split("."),d=b.split("."),e=0,f=Math.max(c.length,d.length);f>e;e++){if(c[e]&&!d[e]&&parseInt(c[e])>0||parseInt(c[e])>parseInt(d[e]))return!0;if(d[e]&&!c[e]&&parseInt(d[e])>0||parseInt(c[e])<parseInt(d[e]))return!1}return!0}function rtm_is_element_exist(a){return jQuery(a).length>0?!0:!1}function rtm_masonry_reload(a){setTimeout(function(){a.masonry("reload")},250)}function rtmediaGetParameterByName(a){a=a.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var b=new RegExp("[\\?&]"+a+"=([^&#]*)"),c=b.exec(location.search);return null==c?"":decodeURIComponent(c[1].replace(/\+/g," "))}function rtmedia_single_media_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning"),jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","0.2"),jQuery(".rtmedia-single-media .rtmedia-media").after("<div class='rtmedia-message-container'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","1"),jQuery(".rtmedia-message-container").remove()},3e3),jQuery(".rtmedia-message-container").click(function(){jQuery(".rtmedia-single-media .rtmedia-media").css("opacity","1"),jQuery(".rtmedia-message-container").remove()})}function rtmedia_gallery_action_alert_message(a,b){var c="rtmedia-success";"warning"==b&&(c="rtmedia-warning");var d='<div class="rtmedia-gallery-alert-container"> </div>';jQuery("body").append(d),jQuery(".rtmedia-gallery-alert-container").append("<div class='rtmedia-gallery-message-box'><span class='"+c+"'>"+a+" </span></div>"),setTimeout(function(){jQuery(".rtmedia-gallery-alert-container").remove()},3e3),jQuery(".rtmedia-gallery-message-box").click(function(){jQuery(".rtmedia-gallery-alert-container").remove()})}!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h="Close",i="BeforeClose",j="AfterClose",k="BeforeAppend",l="MarkupParse",m="Open",n="Change",o="mfp",p="."+o,q="mfp-ready",r="mfp-removing",s="mfp-prevent-close",t=function(){},u=!!window.jQuery,v=a(window),w=function(a,c){b.ev.on(o+a+p,c)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(c,d){b.ev.triggerHandler(o+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},z=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(b=new t,b.init(),a.magnificPopup.instance=b)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};t.prototype={constructor:t,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=B(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(c.isObj===!1){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=x("bg").on("click"+p,function(){b.close()}),b.wrap=x("wrap").attr("tabindex",-1).on("click"+p,function(a){b._checkIfClose(a.target)&&b.close()}),b.container=x("container",b.wrap)),b.contentContainer=x("content"),b.st.preloader&&(b.preloader=x("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var j=i[e];j=j.charAt(0).toUpperCase()+j.slice(1),b["init"+j].call(b)}y("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(w(l,function(a,b,c,d){c.close_replaceWith=z(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(z())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}):b.wrap.css({top:v.scrollTop(),position:"absolute"}),(b.st.fixedBgPos===!1||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup"+p,function(a){27===a.keyCode&&b.close()}),v.on("resize"+p,function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var k=b.wH=v.height(),n={};if(b.fixedContentPos&&b._hasScrollBar(k)){var o=b._getScrollbarSize();o&&(n.marginRight=o)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):n.overflow="hidden");var r=b.st.mainClass;return b.isIE7&&(r+=" mfp-ie7"),r&&b._addClassToMFP(r),b.updateItemHTML(),y("BuildControls"),a("html").css(n),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP(q),b._setFocus()):b.bgOverlay.addClass(q),d.on("focusin"+p,b._onFocusIn)},16),b.isOpen=!0,b.updateSize(k),y(m),c},close:function(){b.isOpen&&(y(i),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP(r),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){y(h);var c=r+" "+q+" ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup"+p+" focusin"+p),b.ev.off(p),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&b.currTemplate[b.currItem.type]!==!0||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,y(j)},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||v.height();b.fixedContentPos||b.wrap.css("height",b.wH),y("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(y("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=b.st[d]?b.st[d].markup:!1;y("FirstMarkupParse",f),f?b.currTemplate[d]=a(f):b.currTemplate[d]=!0}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,y(n,c),e=c.type,b.container.prepend(b.contentContainer),y("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&b.currTemplate[c]===!0?b.content.find(".mfp-close").length||b.content.append(z()):b.content=a:b.content="",y(k),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,y("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){var f=void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick;if(f||2!==c.which&&!c.ctrlKey&&!c.metaKey){var g=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(g)if(a.isFunction(g)){if(!g.call(b))return!0}else if(v.width()<g)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};y("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass(s)){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||v.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){return c.target===b.wrap[0]||a.contains(b.wrap[0],c.target)?void 0:(b._setFocus(),!1)},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(l,[b,c,d]),a.each(c,function(a,c){if(void 0===c||c===!1)return!0;if(e=a.split("_"),e.length>1){var d=b.find(p+"-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(p+"-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:t.prototype,modules:[],open:function(b,c){return A(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&times;</button>',tClose:"Close (Esc)",tLoading:"Loading..."}},a.fn.magnificPopup=function(c){A();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=u?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),u?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var C,D,E,F="inline",G=function(){E&&(D.after(E.addClass(C)).detach(),E=null)};a.magnificPopup.registerModule(F,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push(F),w(h+"."+F,function(){G()})},getInline:function(c,d){if(G(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(D||(C=e.hiddenClass,D=x(C),C="mfp-"+C),E=f.after(D).detach().removeClass(C)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var H,I="ajax",J=function(){H&&a(document.body).removeClass(H)},K=function(){J(),b.req&&b.req.abort()};a.magnificPopup.registerModule(I,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push(I),H=b.st.ajax.cursor,w(h+"."+I,K),w("BeforeChange."+I,K)},getAjax:function(c){H&&a(document.body).addClass(H),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};y("ParseAjax",g),b.appendContent(a(g.data),I),c.finished=!0,J(),b._setFocus(),setTimeout(function(){b.wrap.addClass(q)},16),b.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var L,M=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),w(m+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),w(h+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),v.off("resize"+p)}),w("Resize"+d,b.resizeImage),b.isLowIE&&w("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){L&&clearInterval(L),L=setInterval(function(){return d.naturalWidth>0?void b._onImageHasSize(a):(c>200&&clearInterval(L),c++,void(3===c?e(10):40===c?e(50):100===c&&e(500)))},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,y("ImageLoadComplete")):(e++,200>e?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:M(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(L&&clearInterval(L),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var N,O=function(){return void 0===N&&(N=void 0!==document.createElement("p").style.MozTransform),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,j=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},k=function(){b.content.css("visibility","visible")};w("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),a=b._getItemToZoom(),!a)return void k();f=j(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){k(),setTimeout(function(){f.remove(),a=f=null,y("ZoomAnimationEnded")},16)},g)},16)}}),w(i+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(a=b._getItemToZoom(),!a)return;f=j(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),w(h+d,function(){b._allowZoom()&&(k(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return b.currItem.hasSize?b.currItem.img:!1},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(u?d.innerHeight():d[0].offsetHeight)-g-f};return O()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var P="iframe",Q="//about:blank",R=function(a){if(b.currTemplate[P]){var c=b.currTemplate[P].find("iframe");c.length&&(a||(c[0].src=Q),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(x("b",e[0],!1,!0),x("a",e[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){v.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g,h=a(this);if(c){var i,j,k,l,m,n;h.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,v.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)&&(l=!0,d())}).on("touchend"+f,function(a){d(),l||n>1||(g=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){g=!1},b),e())})})}h.on("click"+f,function(){g||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&v.off("touchmove"+f+" touchend"+f)}}(),A()}),"function"!=typeof Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b}),function(a,b,c,d){var e={init:function(b,c){var d=this;d.elem=c,d.$elem=a(c),d.options=a.extend({},a.fn.rtTab.options,b),d.rtTabs()},rtTabs:function(){var c=this,d=c.options.activeTab;c.$elem.find("li:nth-child("+d+")").addClass("active"),c.rtTabContent(activeTabContent="yes"),c.rtClick();var e="false"===c.$elem.attr("data-hash")?!1:!0;if(e===!0){var f=b.location.hash;f&&c.$elem.find("li").find("a[href="+f+"]").trigger("click"),a(b).on("hashchange",function(){var a=b.location.hash;c.$elem.find("li").find("a[href="+a+"]").trigger("click")})}},rtClick:function(){var c=this,d=c.$elem.find("li"),e=d.find("a");e.on("click",function(e){e.preventDefault(),d.removeClass("active"),c.rtTabContent(),a(this).parent().addClass("active");var f=a(this).attr("href");a(f).removeClass("hide");var g="false"===c.$elem.attr("data-hash")?!1:!0;if(g===!0){var h=a(b).scrollTop();location.hash=a(this).attr("href"),a(b).scrollTop(h)}"function"==typeof c.options.onComplete&&c.options.onComplete.apply(c.elem,arguments)})},rtTabContent:function(b){var c=this,d=c.$elem.find("li"),e=d.find("a");e.each(function(){var c=a(this),d=c.attr("href");"yes"===b?c.parent().hasClass("active")||a(d).addClass("hide"):a(d).addClass("hide")})}};a.fn.rtTab=function(b){return this.each(function(){var c=Object.create(e);c.init(b,this),a.data(this,"rtTab",c)})},a.fn.rtTab.options={activeTab:1,onComplete:null}}(jQuery,window,document);var rtMagnificPopup,rtm_masonry_container,rtMediaHook={hooks:[],is_break:!1,register:function(a,b){"undefined"==typeof rtMediaHook.hooks[a]&&(rtMediaHook.hooks[a]=[]),rtMediaHook.hooks[a].push(b)},call:function(a,b){if("undefined"!=typeof rtMediaHook.hooks[a])for(i=0;i<rtMediaHook.hooks[a].length;++i)if(1!=rtMediaHook.hooks[a][i](b))return rtMediaHook.is_break=!0,!1;return!0}};jQuery("document").ready(function(a){function b(){if(jQuery("#rtmedia-media-view-form").length>0){var a=jQuery("#rtmedia-media-view-form").attr("action");jQuery.post(a,{},function(a){})}}function c(){var a=jQuery.magnificPopup.instance;jQuery(".mfp-arrow-right").on("click",function(b){a.next()}),jQuery(".mfp-arrow-left").on("click",function(b){a.prev()}),jQuery(".mfp-content .rtmedia-media").swipe({swipeLeft:function(b,c,d,e,f){a.next()},swipeRight:function(b,c,d,e,f){a.prev()},threshold:0})}function d(){jQuery(document).on("focusin","#comment_content",function(){jQuery(document).unbind("keydown")}),jQuery(document).on("focusout","#comment_content",function(){var a=jQuery.magnificPopup.instance;jQuery(document).on("keydown",function(b){37===b.keyCode?a.prev():39===b.keyCode&&a.next()})})}function e(){jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()})}a(".rtm-tabs").rtTab(),jQuery(".rtmedia-modal-link").length>0&&a(".rtmedia-modal-link").magnificPopup({type:"inline",midClick:!0,closeBtnInside:!0}),a("#rt_media_comment_form").submit(function(b){return""==a.trim(a("#comment_content").val())?(0==jQuery("#rtmedia-single-media-container").length?rtmedia_gallery_action_alert_message(rtmedia_empty_comment_msg,"warning"):rtmedia_single_media_alert_message(rtmedia_empty_comment_msg,"warning"),!1):!0}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),a("li.rtmedia-list-item p a").each(function(b){a(this).addClass("no-popup")}),"undefined"!=typeof rtmedia_lightbox_enabled&&"1"==rtmedia_lightbox_enabled&&apply_rtMagnificPopup(".rtmedia-list-media, .rtmedia-activity-container ul.rtmedia-list, #bp-media-list,.bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content, .rtm-bbp-container, ul.rtm-comment-container"),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||"undefined"==typeof b.data||"undefined"==typeof b.data.action)return!0}catch(d){return!0}if("activity_get_older_updates"==b.data.action){var e=b.success;a.success=function(a){e(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}else if("get_single_activity_content"==b.data.action){var e=b.success;a.success=function(a){e(a),setTimeout(function(){apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),jQuery("ul.activity-list li.rtmedia_update:first-child .wp-audio-shortcode, ul.activity-list li.rtmedia_update:first-child .wp-video-shortcode").mediaelementplayer({defaultVideoWidth:480,defaultVideoHeight:270})},900)}}}),jQuery.ajaxPrefilter(function(a,b,c){try{if(null==b.data||"undefined"==typeof b.data||"undefined"==typeof b.data.action)return!0}catch(d){return!0}if("activity_get_older_updates"==b.data.action){var e=b.success;a.success=function(a){e(a),apply_rtMagnificPopup(".rtmedia-activity-container ul.rtmedia-list, #bp-media-list, .bp-media-sc-list, li.media.album_updated ul,ul.bp-media-list-media, li.activity-item div.activity-content div.activity-inner div.bp_media_content"),rtMediaHook.call("rtmedia_js_after_activity_added",[])}}}),jQuery(".rtmedia-container").on("click",".select-all",function(a){jQuery(this).toggleClass("unselect-all").toggleClass("select-all"),jQuery(this).attr("title",rtmedia_unselect_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!0)}),jQuery(".rtmedia-list-item").addClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".unselect-all",function(a){jQuery(this).toggleClass("select-all").toggleClass("unselect-all"),jQuery(this).attr("title",rtmedia_select_all_visible),jQuery(".rtmedia-list input").each(function(){jQuery(this).prop("checked",!1)}),jQuery(".rtmedia-list-item").removeClass("bulk-selected")}),jQuery(".rtmedia-container").on("click",".rtmedia-move",function(a){jQuery(".rtmedia-delete-container").slideUp(),jQuery(".rtmedia-move-container").slideToggle()}),jQuery("#rtmedia-create-album-modal").on("click","#rtmedia_create_new_album",function(b){if($albumname=jQuery.trim(jQuery("#rtmedia_album_name").val()),$context=jQuery.trim(jQuery("#rtmedia_album_context").val()),$context_id=jQuery.trim(jQuery("#rtmedia_album_context_id").val()),$privacy=jQuery.trim(jQuery("#rtmedia_select_album_privacy").val()),$create_album_nonce=jQuery.trim(jQuery("#rtmedia_create_album_nonce").val()),""!=$albumname){var c={action:"rtmedia_create_album",
6
+ name:$albumname,context:$context,context_id:$context_id,create_album_nonce:$create_album_nonce};""!==$privacy&&(c.privacy=$privacy),a("#rtmedia_create_new_album").attr("disabled","disabled");var d=a("#rtmedia_create_new_album").html();a("#rtmedia_create_new_album").prepend("<img src='"+rMedia_loading_file+"' />"),jQuery.post(rtmedia_ajax_url,c,function(b){if(b=jQuery.parseJSON(b),"undefined"!=typeof b.album){b=jQuery.trim(b.album);var c=!0;jQuery(".rtmedia-user-album-list").each(function(){if(jQuery(this).children("optgroup").each(function(){return jQuery(this).attr("value")===$context?(c=!1,void jQuery(this).append('<option value="'+b+'">'+$albumname+"</option>")):void 0}),c){var a=$context.charAt(0).toUpperCase()+$context.slice(1),d='<optgroup value="'+$context+'" label="'+a+' Albums"><option value="'+b+'">'+$albumname+"</option></optgroup>";jQuery(this).append(d)}}),jQuery('select.rtmedia-user-album-list option[value="'+b+'"]').prop("selected",!0),jQuery(".rtmedia-create-new-album-container").slideToggle(),jQuery("#rtmedia_album_name").val(""),jQuery("#rtmedia-create-album-modal").append("<div class='rtmedia-success rtmedia-create-album-alert'><b>"+$albumname+"</b>"+rtmedia_album_created_msg+"</div>"),setTimeout(function(){jQuery(".rtmedia-create-album-alert").remove()},4e3),setTimeout(function(){galleryObj.reloadView(),jQuery(".close-reveal-modal").click()},2e3)}else"undefined"!=typeof b.error?rtmedia_gallery_action_alert_message(b.error,"warning"):rtmedia_gallery_action_alert_message(rtmedia_something_wrong_msg,"warning");a("#rtmedia_create_new_album").removeAttr("disabled"),a("#rtmedia_create_new_album").html(d)})}else rtmedia_gallery_action_alert_message(rtmedia_empty_album_name_msg,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_delete_confirmation)&&jQuery(this).closest("form").attr("action","../../../"+rtmedia_media_slug+"/delete").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery(".rtmedia-container").on("click",".rtmedia-move-selected",function(a){jQuery(".rtmedia-list :checkbox:checked").length>0?confirm(rtmedia_selected_media_move_confirmation)&&jQuery(this).closest("form").attr("action","").submit():rtmedia_gallery_action_alert_message(rtmedia_no_media_selected,"warning")}),jQuery("#buddypress").on("change",".rtm-activity-privacy-opt",function(){var a=jQuery(this).attr("id");a=a.split("-"),a=a[a.length-1];var b=this;data={activity_id:a,privacy:jQuery(this).val(),nonce:jQuery("#rtmedia_activity_privacy_nonce").val(),action:"rtm_change_activity_privacy"},jQuery.post(ajaxurl,data,function(a){var c="",d="";"true"==a?(c="Privacy updated successfully.",d="success"):(c="Couldn't change privacy, please try again.",d="fail"),jQuery(b).after('<p class="rtm-ac-privacy-updated '+d+'">'+c+"</p>"),setTimeout(function(){jQuery(b).siblings(".rtm-ac-privacy-updated").remove()},2e3)})}),b(),rtMediaHook.register("rtmedia_js_popup_after_content_added",function(){b(),e(),mfp=jQuery.magnificPopup.instance,jQuery(mfp.items).size()>1&&c(),d();var f=a(window).height();jQuery(".rtm-lightbox-container .mejs-video").css({height:.8*f,"max-height":.8*f,"over-flow":"hidden"}),jQuery(".mfp-content .rtmedia-media").css({"max-height":.87*f,"over-flow":"hidden"}),rtmedia_init_action_dropdown(),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").shorten({showChars:130});var g=a(".rtm-gallery-title"),h="";h=a.isEmptyObject(g)?a("#subnav.item-list-tabs li.selected ").html():g.html(),""!=h&&a(".rtm-ltb-gallery-title .ltb-title").html(h);var i=a("#subnav.item-list-tabs li.selected span").html();return a("li.total").html(i),!0});var f=jQuery("#drag-drop-area"),g=jQuery("#whats-new");f.html();jQuery("#rtmedia-upload-container").after("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&jQuery("#whats-new-textarea").append("<div id='rtm-drop-files-title'>"+rtmedia_drop_media_msg+"</div>"),jQuery(document).on("dragover",function(a){jQuery("#rtm-media-gallery-uploader").show(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&g.addClass("rtm-drag-drop-active"),f.addClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").show()}).on("dragleave",function(a){a.preventDefault(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(g.removeClass("rtm-drag-drop-active"),g.removeAttr("style")),f.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}).on("drop",function(a){a.preventDefault(),"undefined"!=typeof rtmedia_bp_enable_activity&&"1"==rtmedia_bp_enable_activity&&(g.removeClass("rtm-drag-drop-active"),g.removeAttr("style")),f.removeClass("rtm-drag-drop-active"),jQuery("#rtm-drop-files-title").hide()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-album",function(a){a.preventDefault(),confirm(rtmedia_album_delete_confirmation)&&jQuery(this).closest("form").submit()}),jQuery(".rtmedia-container").on("click",".rtmedia-delete-media",function(a){a.preventDefault(),confirm(rtmedia_media_delete_confirmation)&&jQuery(this).closest("form").submit()}),rtmedia_init_action_dropdown(),a(document).click(function(){a(".click-nav ul").is(":visible")&&a(".click-nav ul",this).hide()}),jQuery(".rtmedia-comment-link").on("click",function(a){a.preventDefault(),jQuery("#comment_content").focus()}),jQuery(".rtm-more").length>0&&a(".rtm-more").shorten({showChars:200}),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&(rtm_masonry_container=jQuery(".rtmedia-container .rtmedia-list"),rtm_masonry_container.masonry({itemSelector:".rtmedia-list-item"}),setInterval(function(){jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())}),rtm_masonry_reload(rtm_masonry_container)},1e3),jQuery.each(jQuery(".rtmedia-list.masonry .rtmedia-item-title"),function(a,b){jQuery(b).width(jQuery(b).siblings(".rtmedia-item-thumbnail").children("img").width())})),jQuery(".rtm-uploader-tabs").length>0&&jQuery(".rtm-uploader-tabs li").click(function(a){jQuery(this).hasClass("active")||(jQuery(this).siblings().removeClass("active"),jQuery(this).parents(".rtm-uploader-tabs").siblings().hide(),class_name=jQuery(this).attr("class"),jQuery(this).parents(".rtm-uploader-tabs").siblings('[data-id="'+class_name+'"]').show(),jQuery(this).addClass("active"),"rtm-upload-tab"!=class_name?jQuery("div.moxie-shim").children("input[type=file]").hide():jQuery("div.moxie-shim").children("input[type=file]").show())}),jQuery(".rtmedia-container").on("click",".rtm-delete-media",function(a){a.preventDefault();var b="Are you sure you want to delete this media?";if("undefined"!=typeof rtmedia_media_delete_confirmation&&(b=rtmedia_media_delete_confirmation),confirm(b)){var c=jQuery(this).closest("li"),d=jQuery("#rtmedia_media_delete_nonce").val(),e={action:"delete_uploaded_media",nonce:d,media_id:c.attr("id")};jQuery.ajax({url:ajaxurl,type:"post",data:e,success:function(a){"1"==a?(rtmedia_gallery_action_alert_message("file deleted successfully.","success"),c.remove(),"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)):rtmedia_gallery_action_alert_message(rtmedia_file_not_deleted,"warning")}})}})}),function(a){a.fn.shorten=function(b){var c={showChars:100,ellipsesText:"...",moreText:"more",lessText:"less"};return b&&a.extend(c,b),a(document).off("click",".morelink"),a(document).on({click:function(){var b=a(this);return b.hasClass("less")?(b.removeClass("less"),b.html(c.moreText)):(b.addClass("less"),b.html(c.lessText)),b.parent().prev().toggle(),b.prev().toggle(),!1}},".morelink"),this.each(function(){var b=a(this);if(!b.hasClass("shortened")){b.addClass("shortened");var d=b.html();if(d.length>c.showChars){var e=d.substr(0,c.showChars),f=d.substr(c.showChars,d.length-c.showChars),g=e+'<span class="moreellipses">'+c.ellipsesText+' </span><span class="morecontent"><span>'+f+'</span> <a href="#" class="morelink">'+c.moreText+"</a></span>";b.html(g),a(".morecontent span").hide()}}})}}(jQuery),window.onload=function(){"undefined"!=typeof rtmedia_masonry_layout&&"true"==rtmedia_masonry_layout&&0==jQuery(".rtmedia-container .rtmedia-list.rtm-no-masonry").length&&rtm_masonry_reload(rtm_masonry_container)};
app/helper/RTMediaSettings.php CHANGED
@@ -84,7 +84,9 @@ if ( ! class_exists( 'RTMediaSettings' ) ){
84
  $defaults['buddypress_enableOnActivity'] = 1;
85
  $defaults['buddypress_enableOnProfile'] = 1;
86
  $defaults['buddypress_limitOnActivity'] = 0;
87
- $defaults['buddypress_enableNotification'] = 0;
 
 
88
  $defaults['styles_custom'] = '';
89
  $defaults['styles_enabled'] = 1;
90
 
84
  $defaults['buddypress_enableOnActivity'] = 1;
85
  $defaults['buddypress_enableOnProfile'] = 1;
86
  $defaults['buddypress_limitOnActivity'] = 0;
87
+ $defaults['buddypress_enableNotification'] = 0;
88
+ $defaults['buddypress_mediaLikeActivity'] = 0;
89
+ $defaults['buddypress_mediaCommentActivity'] = 0;
90
  $defaults['styles_custom'] = '';
91
  $defaults['styles_enabled'] = 1;
92
 
app/main/controllers/activity/RTMediaBuddyPressActivity.php CHANGED
@@ -31,6 +31,17 @@ class RTMediaBuddyPressActivity {
31
 
32
  // Filter bp_activity_prefetch_object_data for translatable activity actions
33
  add_filter( 'bp_activity_prefetch_object_data', array( $this, 'bp_prefetch_activity_object_data' ), 10, 1 );
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
  function bp_activity_deleted_activities( $activity_ids_deleted ){
@@ -417,4 +428,204 @@ class RTMediaBuddyPressActivity {
417
  return $activities;
418
  }
419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
31
 
32
  // Filter bp_activity_prefetch_object_data for translatable activity actions
33
  add_filter( 'bp_activity_prefetch_object_data', array( $this, 'bp_prefetch_activity_object_data' ), 10, 1 );
34
+
35
+ // BuddyPress activity for media like action
36
+ if ( isset( $rtmedia->options['buddypress_mediaLikeActivity'] ) && 0 != $rtmedia->options['buddypress_mediaLikeActivity'] ){
37
+ add_action( 'rtmedia_after_like_media', array( $this, 'activity_after_media_like' ) );
38
+ }
39
+
40
+ // BuddyPress activity for media comment action
41
+ if ( isset( $rtmedia->options['buddypress_mediaCommentActivity'] ) && 0 != $rtmedia->options['buddypress_mediaCommentActivity'] ){
42
+ add_action( 'rtmedia_after_add_comment', array( $this, 'activity_after_media_comment' ) );
43
+ add_action( 'rtmedia_before_remove_comment', array( $this, 'remove_activity_after_media_comment_delete' ) );
44
+ }
45
  }
46
 
47
  function bp_activity_deleted_activities( $activity_ids_deleted ){
428
  return $activities;
429
  }
430
 
431
+ /**
432
+ * Create BP activity when user like and delete associated activity when user remove like.
433
+ *
434
+ * @param $obj RTMediaLike
435
+ */
436
+ function activity_after_media_like( $obj ){
437
+ global $rtmedia_points_media_id;
438
+ if( is_a( $obj, 'RTMediaLike' ) && isset( $obj->action_query->id ) ){
439
+ $media_id = $obj->action_query->id;
440
+ } elseif( ! empty( $rtmedia_points_media_id ) ){
441
+ $media_id = $rtmedia_points_media_id;
442
+ } else {
443
+ $media_id = false;
444
+ }
445
+
446
+ $media_obj = $obj->media;
447
+
448
+ // Proceed only if we have media to process.
449
+ if( $media_id !== false && ( $media_obj->context == 'profile' || $media_obj->context == 'group' ) ){
450
+
451
+ $user_id = $obj->interactor;
452
+
453
+ // If $obj->increase is true than request is to like the media.
454
+ if( $obj->increase ){
455
+
456
+ // Create activity on media like
457
+ $user = get_userdata( $user_id );
458
+ $username = '<a href="' . get_rtmedia_user_link( $user_id ) . '">' . $user->display_name . '</a>';
459
+
460
+ $media_author = $obj->owner;
461
+
462
+ $primary_link = get_rtmedia_permalink( $media_id );
463
+
464
+ $media_const = 'RTMEDIA_' . strtoupper( $obj->media->media_type ) . '_LABEL';
465
+ $media_str = '<a href="'. $primary_link .'">' . constant( $media_const ) . '</a>';
466
+
467
+ if( $media_obj->context == 'group' ){
468
+ $group_data = groups_get_group( array( 'group_id' => $media_obj->context_id ) );
469
+ $group_name = '<a href="' . bp_get_group_permalink( $group_data ) . '">' . $group_data->name . '</a>';
470
+ $action = sprintf( __( '%1$s liked a %2$s in the group %3$s', 'buddypress-media' ), $username, $media_str, $group_name );
471
+ } else {
472
+ if( $user_id == $media_author ){
473
+ $action = sprintf( __( '%1$s liked their %2$s', 'buddypress-media' ), $username, $media_str );
474
+ } else {
475
+ $media_author_data = get_userdata( $media_author );
476
+ $media_author_name = '<a href="' . get_rtmedia_user_link( $media_author ) . '">' . $media_author_data->display_name . '</a>';
477
+ $action = sprintf( __( '%1$s liked %2$s\'s %3$s', 'buddypress-media' ), $username, $media_author_name, $media_str );
478
+ }
479
+ }
480
+
481
+ $action = apply_filters( 'rtm_bp_like_activity_action', $action, $media_id, $user_id );
482
+ $primary_link = get_rtmedia_permalink( $media_id );
483
+
484
+ // generate activity arguments.
485
+ $activity_args = array(
486
+ 'user_id' => $user_id,
487
+ 'action' => $action,
488
+ 'type' => 'rtmedia_like_activity',
489
+ 'primary_link' => $primary_link,
490
+ 'item_id' => $media_id,
491
+ );
492
+
493
+ // set activity component
494
+ if( $media_obj->context == 'group' || $media_obj->context == 'profile' ) {
495
+ $activity_args[ 'component' ] = $media_obj->context;
496
+ if( $media_obj->context == 'group' ) {
497
+ $activity_args[ 'component' ] = "groups";
498
+ $activity_args[ 'item_id' ] = $media_obj->context_id;
499
+ }
500
+ }
501
+
502
+ // add BP activity
503
+ $activity_id = bp_activity_add( $activity_args );
504
+
505
+ // Store activity id into user meta for reference
506
+ update_user_meta( $user_id, 'rtm-bp-media-like-activity-' . $media_id, $activity_id );
507
+ } else {
508
+
509
+ $meta_key = 'rtm-bp-media-like-activity-' . $media_id;
510
+ // Delete activity when user remove his like.
511
+ $activity_id = get_user_meta( $user_id, $meta_key, true );
512
+
513
+ if( ! empty( $activity_id ) ){
514
+ if( bp_activity_delete( array( 'id' => $activity_id ) ) ){
515
+ delete_user_meta( $user_id, $meta_key );
516
+ }
517
+ }
518
+ }
519
+ }
520
+ }
521
+
522
+ /**
523
+ * Create BuddyPress activity when user comment on media
524
+ *
525
+ * @param $params array
526
+ */
527
+ function activity_after_media_comment( $params ){
528
+
529
+ if( isset( $params['comment_post_ID'] ) ){
530
+
531
+ // get media details
532
+ $media_model = new RTMediaModel();
533
+ $media_obj = $media_model->get( array( 'media_id' => $params['comment_post_ID'] ) );
534
+ $media_obj = $media_obj[0];
535
+
536
+ // only proceed if corresponding media is exist.
537
+ if( ! empty( $media_obj ) && ( $media_obj->context == 'profile' || $media_obj->context == 'group' ) ){
538
+
539
+ $media_id = $media_obj->id;
540
+
541
+ $user_id = $params['user_id'];
542
+ $user = get_userdata( $user_id );
543
+ $username = '<a href="' . get_rtmedia_user_link( $user_id ) . '">' . $user->display_name . '</a>';
544
+
545
+ $primary_link = get_rtmedia_permalink( $media_id );
546
+
547
+ $media_const = 'RTMEDIA_' . strtoupper( $media_obj->media_type ) . '_LABEL';
548
+ $media_str = '<a href="'. $primary_link .'">' . constant( $media_const ) . '</a>';
549
+
550
+ $media_author = $media_obj->media_author;
551
+
552
+ if( $media_obj->context == 'group' ){
553
+ $group_data = groups_get_group( array( 'group_id' => $media_obj->context_id ) );
554
+ $group_name = '<a href="' . bp_get_group_permalink( $group_data ) . '">' . $group_data->name . '</a>';
555
+ $action = sprintf( __( '%1$s commented on a %2$s in the group %3$s', 'buddypress-media' ), $username, $media_str, $group_name );
556
+ } else {
557
+ if( $user_id == $media_author ){
558
+ $action = sprintf( __( '%1$s commented on their %2$s', 'buddypress-media' ), $username, $media_str );
559
+ } else {
560
+ $media_author_data = get_userdata( $media_author );
561
+ $media_author_name = '<a href="' . get_rtmedia_user_link( $media_author ) . '">' . $media_author_data->display_name . '</a>';
562
+ $action = sprintf( __( '%1$s commented on %2$s\'s %3$s', 'buddypress-media' ), $username, $media_author_name, $media_str );
563
+ }
564
+ }
565
+
566
+ $comment_content = $params['comment_content'];
567
+ $wp_comment_id = $params['comment_id'];
568
+
569
+ // prepare activity arguments
570
+ $activity_args = array(
571
+ 'user_id' => $user_id,
572
+ 'action' => $action,
573
+ 'content' => $comment_content,
574
+ 'type' => 'rtmedia_comment_activity',
575
+ 'primary_link' => $primary_link,
576
+ 'item_id' => $media_id,
577
+ 'secondary_item_id' => $wp_comment_id
578
+ );
579
+
580
+ // set activity component
581
+ if( $media_obj->context == 'group' || $media_obj->context == 'profile' ) {
582
+ $activity_args[ 'component' ] = $media_obj->context;
583
+ if( $media_obj->context == 'group' ) {
584
+ $activity_args[ 'component' ] = "groups";
585
+ $activity_args[ 'item_id' ] = $media_obj->context_id;
586
+ }
587
+ }
588
+
589
+ // create BuddyPress activity
590
+ $activity_id = bp_activity_add( $activity_args );
591
+
592
+ // Store activity id into user meta for reference
593
+ update_user_meta( $user_id, 'rtm-bp-media-comment-activity-' . $media_id . '-' . $wp_comment_id, $activity_id );
594
+ }
595
+ }
596
+ }
597
+
598
+ /**
599
+ * Remove activity when comment on media is deleted
600
+ *
601
+ * @param $comment_id
602
+ */
603
+ function remove_activity_after_media_comment_delete( $comment_id ){
604
+ if( !empty( $comment_id ) ) {
605
+
606
+ // get comment details from comment id
607
+ $comment = get_comment( $comment_id );
608
+ $user_id = $comment->user_id;
609
+
610
+ if( isset( $comment->comment_post_ID ) && isset( $comment->user_id ) ){
611
+ $model = new RTMediaModel();
612
+ $media_obj = $model->get( array( 'media_id' => $comment->comment_post_ID ) );
613
+ $media_obj = $media_obj[0];
614
+
615
+ if( ! empty( $media_obj ) ){
616
+ $meta_key = 'rtm-bp-media-comment-activity-' . $media_obj->id . '-' . $comment_id;
617
+
618
+ // Delete activity when user remove his comment.
619
+ $activity_id = get_user_meta( $user_id, $meta_key, true );
620
+
621
+ if( ! empty( $activity_id ) ){
622
+ if( bp_activity_delete( array( 'id' => $activity_id ) ) ){
623
+ delete_user_meta( $user_id, $meta_key );
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+ }
630
+
631
  }
app/main/controllers/media/RTMediaMedia.php CHANGED
@@ -601,7 +601,7 @@ class RTMediaMedia {
601
  $activity_args[ "hide_sitewide" ] = true;
602
  }
603
 
604
- if( $media->context == 'group' || 'profile' ) {
605
  $activity_args[ 'component' ] = $media->context;
606
  if( $media->context == 'group' ) {
607
  $activity_args[ 'component' ] = "groups";
601
  $activity_args[ "hide_sitewide" ] = true;
602
  }
603
 
604
+ if( $media->context == 'group' || $media->context == 'profile' ) {
605
  $activity_args[ 'component' ] = $media->context;
606
  if( $media->context == 'group' ) {
607
  $activity_args[ 'component' ] = "groups";
app/main/controllers/privacy/RTMediaPrivacy.php CHANGED
@@ -15,8 +15,9 @@ class RTMediaPrivacy {
15
  *
16
  * @var object default application wide privacy levels
17
  */
18
- public
19
- $default_privacy;
 
20
 
21
  function __construct( $flag = true ) {
22
  if ( is_rtmedia_privacy_enable() && $flag ) {
@@ -25,14 +26,87 @@ class RTMediaPrivacy {
25
  add_action( 'bp_init', array( $this, 'add_nav' ) );
26
  add_action( 'bp_template_content', array( $this, 'content' ) );
27
  add_filter( 'bp_activity_get_user_join_filter', array( $this, 'activity_privacy' ), 10, 6 );
 
 
 
 
28
  add_filter( 'bp_use_legacy_activity_query', array( $this, 'enable_buddypress_privacy' ), 10, 3 );
29
  add_filter( 'bp_activity_has_more_items', array( $this, 'enable_buddypress_load_more' ), 10, 1 );
30
  add_action( 'bp_actions', array( $this,'rt_privacy_settings_action' ) );
 
 
 
 
 
 
 
 
 
 
31
  }
32
  add_action( 'friends_friendship_accepted', array( 'RTMediaFriends', 'refresh_friends_cache' ) );
33
  add_action( 'friends_friendship_deleted', array( 'RTMediaFriends', 'refresh_friends_cache' ) );
34
  }
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  function enable_buddypress_load_more( $has_more_items ) {
37
  global $activities_template;
38
  return true;
@@ -66,7 +140,7 @@ class RTMediaPrivacy {
66
  }
67
  }
68
 
69
- function select_privacy_ui( $echo = true, $select_id = false ) {
70
  global $rtmedia;
71
 
72
  if ( ! is_rtmedia_privacy_enable() )
@@ -76,12 +150,13 @@ class RTMediaPrivacy {
76
  return false;
77
 
78
  global $rtmedia_media;
79
- $default = 0;
80
- if ( isset( $rtmedia_media->privacy ) )
 
 
81
  $default = $rtmedia_media->privacy;
82
- else {
83
  $default = get_user_meta( get_current_user_id(), 'rtmedia-default-privacy', true );
84
-
85
  if ( ( $default === false ) || $default === '' ) {
86
  $default = get_rtmedia_default_privacy();
87
  }
@@ -89,12 +164,22 @@ class RTMediaPrivacy {
89
 
90
 
91
  $form = new rtForm();
 
 
 
 
 
 
 
 
 
 
92
  $attributes = array(
93
  'name' => 'privacy',
94
- 'class' => array( 'privacy' )
95
  );
96
- if ( $select_id && $select_id != "" ) {
97
- $attributes[ 'id' ] = $select_id;
98
  }
99
  global $rtmedia;
100
  $privacy_levels = $rtmedia->privacy_settings[ 'levels' ];
@@ -325,36 +410,36 @@ class RTMediaPrivacy {
325
  $user = 0;
326
  }
327
 
328
- $activity_upgrade_done = rtmedia_get_site_option( 'rtmedia_activity_done_upgrade' );
329
-
330
  // admin has upgraded rtmedia activity so we can use rt_rtm_activity table for rtmedia related activity filters
331
- if ( $activity_upgrade_done ) {
332
  $rtmedia_activity_model = new RTMediaActivityModel();
333
- $where .= " (ra.privacy is NULL OR ra.privacy <= 0) ";
334
  if ( $user ) {
335
- $where .= "OR ((ra.privacy=20)";
336
- $where .= " OR (a.user_id={$user} AND ra.privacy >= 40)";
337
  if ( class_exists( 'BuddyPress' ) ) {
338
  if ( bp_is_active( 'friends' ) ) {
339
  $friendship = new RTMediaFriends();
340
  $friends = $friendship->get_friends_cache( $user );
341
  if ( isset( $friends ) && ! empty( $friends ) != "" ) {
342
- $where .= " OR (ra.privacy=40 AND a.user_id IN ('" . implode( "','", $friends ) . "'))";
343
  }
344
  }
345
  }
346
  $where .= ')';
347
  }
348
- if ( function_exists( "bp_core_get_table_prefix" ) ) {
349
- $bp_prefix = bp_core_get_table_prefix();
350
- } else {
351
- $bp_prefix = "";
352
- }
353
  if ( strpos( $select_sql, "SELECT DISTINCT" ) === false ) {
354
  $select_sql = str_replace( "SELECT", "SELECT DISTINCT", $select_sql );
355
  }
356
- $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID LEFT JOIN {$rtmedia_model->table_name} m ON ( a.id = m.activity_id AND m.blog_id = '" . get_current_blog_id() . "' ) LEFT JOIN {$rtmedia_activity_model->table_name} ra ON ( a.id = ra.activity_id and ra.blog_id = '" . get_current_blog_id() . "' ) ";
357
- $where_sql = $where_sql . " AND (NOT EXISTS (SELECT m.activity_id FROM {$bp_prefix}bp_activity_meta m WHERE m.meta_key='rtmedia_privacy' AND m.activity_id=a.id) OR ( {$where} ) )";
 
 
 
 
 
 
358
  $newsql = "{$select_sql} {$from_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}";
359
  } else {
360
  $where .= " (m.max_privacy is NULL OR m.max_privacy <= 0) ";
@@ -388,4 +473,42 @@ class RTMediaPrivacy {
388
  return $newsql;
389
  }
390
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  }
15
  *
16
  * @var object default application wide privacy levels
17
  */
18
+ public $default_privacy;
19
+
20
+ public $rtm_activity_table_alias = 'ra';
21
 
22
  function __construct( $flag = true ) {
23
  if ( is_rtmedia_privacy_enable() && $flag ) {
26
  add_action( 'bp_init', array( $this, 'add_nav' ) );
27
  add_action( 'bp_template_content', array( $this, 'content' ) );
28
  add_filter( 'bp_activity_get_user_join_filter', array( $this, 'activity_privacy' ), 10, 6 );
29
+
30
+ // Filter bp_activity_get_user_join_filter to get activity privacy field in loop
31
+ add_filter( 'bp_activity_get_user_join_filter', array( $this, 'activity_privacy_sql_field' ), 10, 6 );
32
+
33
  add_filter( 'bp_use_legacy_activity_query', array( $this, 'enable_buddypress_privacy' ), 10, 3 );
34
  add_filter( 'bp_activity_has_more_items', array( $this, 'enable_buddypress_load_more' ), 10, 1 );
35
  add_action( 'bp_actions', array( $this,'rt_privacy_settings_action' ) );
36
+
37
+ // show change privacy option in activity meta.
38
+ add_action( 'bp_activity_entry_meta', array( $this, 'update_activity_privacy_option' ) );
39
+
40
+ // Add nonce field to change activity privacy option
41
+ add_action( 'template_notices', array( $this, 'add_activity_privacy_nonce' ) );
42
+
43
+ // save update privacy value
44
+ add_action( 'wp_ajax_rtm_change_activity_privacy', array( $this, 'rtm_change_activity_privacy' ) );
45
+
46
  }
47
  add_action( 'friends_friendship_accepted', array( 'RTMediaFriends', 'refresh_friends_cache' ) );
48
  add_action( 'friends_friendship_deleted', array( 'RTMediaFriends', 'refresh_friends_cache' ) );
49
  }
50
 
51
+ /**
52
+ * Hooked to `bp_activity_entry_meta`
53
+ *
54
+ * Show privacy dropdown inside activity loop along with activity meta buttons.
55
+ */
56
+ function update_activity_privacy_option(){
57
+ if( function_exists( 'bp_activity_user_can_delete' ) && bp_activity_user_can_delete()
58
+ && is_rtmedia_privacy_enable() && is_rtmedia_privacy_user_overide()
59
+ && apply_filters( 'rtm_load_bp_activity_privacy_update_ui', true )
60
+ ){
61
+ global $activities_template;
62
+
63
+ $selected = 0;
64
+ if( isset( $activities_template->activity->privacy ) ){
65
+ $selected = intval( $activities_template->activity->privacy );
66
+ }
67
+
68
+ //todo strict standard error
69
+ self::select_privacy_ui( true, 'rtm-ac-privacy-' . $activities_template->activity->id , array( 'rtm-activity-privacy-opt' ), $selected );
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Add nonce field for activity privacy change action verification
75
+ */
76
+ function add_activity_privacy_nonce(){
77
+ wp_nonce_field( 'rtmedia_activity_privacy_nonce', 'rtmedia_activity_privacy_nonce' );
78
+ }
79
+
80
+ function rtm_change_activity_privacy(){
81
+ $data = $_POST;
82
+
83
+ if( wp_verify_nonce( $data[ 'nonce' ], 'rtmedia_activity_privacy_nonce' ) ){
84
+ $rtm_activity_model = new RTMediaActivityModel();
85
+ $is_ac_privacy_exist = $rtm_activity_model->check( $data[ 'activity_id' ] );
86
+
87
+ if( ! $is_ac_privacy_exist ){
88
+ // Very first privacy entry for this activity
89
+ $status = $rtm_activity_model->insert( array(
90
+ 'privacy' => intval( $data['privacy'] ),
91
+ 'activity_id' => intval( $data[ 'activity_id' ] ),
92
+ 'user_id' => get_current_user_id(),
93
+ ) );
94
+ } else {
95
+ // Just update the existing value
96
+ $status = $rtm_activity_model->update( array( 'privacy' => intval( $data['privacy'] ) ), array( 'activity_id' => intval( $data['activity_id'] ) ) );
97
+ }
98
+
99
+ if( $status === false ){
100
+ $status = 'false';
101
+ } else {
102
+ $status = 'true';
103
+ }
104
+
105
+ echo $status;
106
+ wp_die();
107
+ }
108
+ }
109
+
110
  function enable_buddypress_load_more( $has_more_items ) {
111
  global $activities_template;
112
  return true;
140
  }
141
  }
142
 
143
+ function select_privacy_ui( $echo = true, $element_id = false, $element_class = array(), $selected = false ) {
144
  global $rtmedia;
145
 
146
  if ( ! is_rtmedia_privacy_enable() )
150
  return false;
151
 
152
  global $rtmedia_media;
153
+
154
+ if( $selected !== false ){
155
+ $default = $selected;
156
+ } elseif ( isset( $rtmedia_media->privacy ) ){
157
  $default = $rtmedia_media->privacy;
158
+ } else {
159
  $default = get_user_meta( get_current_user_id(), 'rtmedia-default-privacy', true );
 
160
  if ( ( $default === false ) || $default === '' ) {
161
  $default = get_rtmedia_default_privacy();
162
  }
164
 
165
 
166
  $form = new rtForm();
167
+
168
+ $attributes_class = array( 'privacy' );
169
+
170
+ if( !empty( $element_class ) ){
171
+ if( ! is_array( $element_class ) ){
172
+ $attributes_class = array_merge( $attributes_class, (array) $element_class );
173
+ } else {
174
+ $attributes_class = array_merge( $attributes_class, $element_class );
175
+ }
176
+ }
177
  $attributes = array(
178
  'name' => 'privacy',
179
+ 'class' => $attributes_class
180
  );
181
+ if ( $element_id && $element_id != "" ) {
182
+ $attributes[ 'id' ] = $element_id;
183
  }
184
  global $rtmedia;
185
  $privacy_levels = $rtmedia->privacy_settings[ 'levels' ];
410
  $user = 0;
411
  }
412
 
 
 
413
  // admin has upgraded rtmedia activity so we can use rt_rtm_activity table for rtmedia related activity filters
414
+ if ( $this->can_use_rtm_ac_privacy() ) {
415
  $rtmedia_activity_model = new RTMediaActivityModel();
416
+ $where .= " ({$this->rtm_activity_table_alias}.privacy is NULL OR {$this->rtm_activity_table_alias}.privacy <= 0) ";
417
  if ( $user ) {
418
+ $where .= "OR (({$this->rtm_activity_table_alias}.privacy=20)";
419
+ $where .= " OR (a.user_id={$user} AND {$this->rtm_activity_table_alias}.privacy >= 40)";
420
  if ( class_exists( 'BuddyPress' ) ) {
421
  if ( bp_is_active( 'friends' ) ) {
422
  $friendship = new RTMediaFriends();
423
  $friends = $friendship->get_friends_cache( $user );
424
  if ( isset( $friends ) && ! empty( $friends ) != "" ) {
425
+ $where .= " OR ({$this->rtm_activity_table_alias}.privacy=40 AND a.user_id IN ('" . implode( "','", $friends ) . "'))";
426
  }
427
  }
428
  }
429
  $where .= ')';
430
  }
431
+
 
 
 
 
432
  if ( strpos( $select_sql, "SELECT DISTINCT" ) === false ) {
433
  $select_sql = str_replace( "SELECT", "SELECT DISTINCT", $select_sql );
434
  }
435
+
436
+ $select_sql .= " ,{$this->rtm_activity_table_alias}.privacy ";
437
+
438
+ $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID LEFT JOIN {$rtmedia_activity_model->table_name} {$this->rtm_activity_table_alias} ON ( a.id = {$this->rtm_activity_table_alias}.activity_id and ra.blog_id = '" . get_current_blog_id() . "' ) ";
439
+
440
+ // removed NOT EXISTS check for `rtmedia_privacy` activty meta value.
441
+ // check git history for more details ;)
442
+ $where_sql = $where_sql . " AND {$where}";
443
  $newsql = "{$select_sql} {$from_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}";
444
  } else {
445
  $where .= " (m.max_privacy is NULL OR m.max_privacy <= 0) ";
473
  return $newsql;
474
  }
475
 
476
+ /**
477
+ * Hooked to `bp_activity_get_user_join_filter` filter. Get activity privacy field inside loop.
478
+ *
479
+ * Use only if current user has admin capability because for non admin users privacy field will be added in
480
+ * privacy filter query itself.
481
+ *
482
+ * @param $sql
483
+ * @param $select_sql
484
+ * @param $from_sql
485
+ * @param $where_sql
486
+ * @param $sort
487
+ * @param string $pag_sql
488
+ *
489
+ * @return string
490
+ */
491
+ function activity_privacy_sql_field( $sql, $select_sql, $from_sql, $where_sql, $sort, $pag_sql = '' ){
492
+ global $wpdb, $bp;
493
+
494
+ if( $this->can_use_rtm_ac_privacy() && is_rt_admin() ){
495
+ $rtmedia_activity_model = new RTMediaActivityModel();
496
+ if( strpos( $sql, $rtmedia_activity_model->table_name ) === false ){
497
+ $select_sql .= " ,{$this->rtm_activity_table_alias}.privacy ";
498
+ $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID LEFT JOIN {$rtmedia_activity_model->table_name} {$this->rtm_activity_table_alias} ON ( a.id = {$this->rtm_activity_table_alias}.activity_id and ra.blog_id = '" . get_current_blog_id() . "' ) ";
499
+ $sql = "{$select_sql} {$from_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}";
500
+ }
501
+ }
502
+ return $sql;
503
+ }
504
+
505
+ /**
506
+ * Check if activity privacy migration is done or not.
507
+ *
508
+ * @return bool|mixed|void
509
+ */
510
+ function can_use_rtm_ac_privacy(){
511
+ return rtmedia_get_site_option( 'rtmedia_activity_done_upgrade' );
512
+ }
513
+
514
  }
app/main/controllers/template/rt-template-functions.php CHANGED
@@ -1951,7 +1951,7 @@ function rtmedia_edit_media_privacy_ui() {
1951
  //if context is group i.e editing a group media, dont show the privacy dropdown
1952
  return false;
1953
  }
1954
- $privacymodel = new RTMediaPrivacy();
1955
  $privacy = $privacymodel->select_privacy_ui( $echo = false );
1956
  if ( $privacy ) {
1957
  return "<div class='rtmedia-edit-privacy rtm-field-wrap'><label for='privacy'>" . __( 'Privacy : ', 'buddypress-media' ) . "</label>" . $privacy . "</div>";
1951
  //if context is group i.e editing a group media, dont show the privacy dropdown
1952
  return false;
1953
  }
1954
+ $privacymodel = new RTMediaPrivacy( false );
1955
  $privacy = $privacymodel->select_privacy_ui( $echo = false );
1956
  if ( $privacy ) {
1957
  return "<div class='rtmedia-edit-privacy rtm-field-wrap'><label for='privacy'>" . __( 'Privacy : ', 'buddypress-media' ) . "</label>" . $privacy . "</div>";
app/main/controllers/upload/RTMediaUploadView.php CHANGED
@@ -64,7 +64,7 @@ class RTMediaUploadView {
64
  // if the context is group, then set the media privacy to public
65
  $privacy = "<input type='hidden' name='privacy' value='0'/>";
66
  } else {
67
- $up_privacy = new RTMediaPrivacy();
68
  $up_privacy = $up_privacy->select_privacy_ui( false, 'rtSelectPrivacy' );
69
  if ( $up_privacy ) {
70
  $privacy = "<span> <label for='privacy'> <i class='dashicons dashicons-visibility rtmicon'></i> " . __( 'Privacy: ', 'buddypress-media' ) . "</label>" . $up_privacy . "</span>";
64
  // if the context is group, then set the media privacy to public
65
  $privacy = "<input type='hidden' name='privacy' value='0'/>";
66
  } else {
67
+ $up_privacy = new RTMediaPrivacy( false );
68
  $up_privacy = $up_privacy->select_privacy_ui( false, 'rtSelectPrivacy' );
69
  if ( $up_privacy ) {
70
  $privacy = "<span> <label for='privacy'> <i class='dashicons dashicons-visibility rtmicon'></i> " . __( 'Privacy: ', 'buddypress-media' ) . "</label>" . $up_privacy . "</span>";
index.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: rtMedia for WordPress, BuddyPress and bbPress
5
  Plugin URI: http://rtcamp.com/rtmedia/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
6
  Description: This plugin adds missing media rich features like photos, videos and audio uploading to BuddyPress which are essential if you are building social network, seriously!
7
- Version: 3.9.5
8
  Author: rtCamp
9
  Text Domain: buddypress-media
10
  Author URI: http://rtcamp.com/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
@@ -117,6 +117,39 @@ spl_autoload_register( 'rtmedia_autoloader' );
117
  global $rtmedia;
118
  $rtmedia = new RTMedia();
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
  /*
122
  * Look Ma! Very few includes! Next File: /app/main/RTMedia.php
4
  Plugin Name: rtMedia for WordPress, BuddyPress and bbPress
5
  Plugin URI: http://rtcamp.com/rtmedia/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
6
  Description: This plugin adds missing media rich features like photos, videos and audio uploading to BuddyPress which are essential if you are building social network, seriously!
7
+ Version: 3.10
8
  Author: rtCamp
9
  Text Domain: buddypress-media
10
  Author URI: http://rtcamp.com/?utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media
117
  global $rtmedia;
118
  $rtmedia = new RTMedia();
119
 
120
+ /**
121
+ * Integrated Freemius into rtMedia.
122
+ *
123
+ * @return Freemius
124
+ */
125
+ function rtmedia_fs() {
126
+ global $bm_fs;
127
+
128
+ if ( ! isset( $bm_fs ) ) {
129
+ // Include Freemius SDK.
130
+ require_once RTMEDIA_PATH . 'lib/freemius/start.php';
131
+
132
+ $bm_fs = fs_dynamic_init( array(
133
+ 'id' => '122',
134
+ 'slug' => 'buddypress-media',
135
+ 'public_key' => 'pk_3b5465cdde21c8ba24cd731b149a8',
136
+ 'is_premium' => false,
137
+ 'has_addons' => false,
138
+ 'has_paid_plans' => false,
139
+ 'menu' => array(
140
+ 'slug' => 'rtmedia-settings',
141
+ 'account' => false,
142
+ 'contact' => false,
143
+ 'support' => false,
144
+ ),
145
+ ) );
146
+ }
147
+
148
+ return $bm_fs;
149
+ }
150
+
151
+ // Init Freemius.
152
+ rtmedia_fs();
153
 
154
  /*
155
  * Look Ma! Very few includes! Next File: /app/main/RTMedia.php
languages/buddypress-media.mo CHANGED
Binary file
languages/buddypress-media.po CHANGED
@@ -2,2588 +2,2981 @@
2
  # This file is distributed under the same license as the rtMedia for WordPress, BuddyPress and bbPress package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: rtMedia for WordPress, BuddyPress and bbPress 3.9.3\n"
6
  "Report-Msgid-Bugs-To: http://community.rtcamp.com/c/rtmedia/\n"
7
- "POT-Creation-Date: 2015-12-04 10:36:47+00:00\n"
8
- "MIME-Version: 1.0\n"
9
- "Content-Type: text/plain; charset=utf-8\n"
10
- "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: rtMedia <rtmedia@rtcamp.com>\n"
13
  "Language-Team: rtMedia <rtmedia@rtcamp.com>\n"
14
- "X-Generator: grunt-wp-i18n 0.5.3\n"
15
- "X-Poedit-KeywordsList: "
16
- "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
17
- "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
18
  "Language: en\n"
 
 
 
 
 
 
 
19
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
- "X-Poedit-Country: United States\n"
21
  "X-Poedit-SourceCharset: UTF-8\n"
22
  "X-Poedit-Basepath: ../\n"
23
- "X-Poedit-SearchPath-0: .\n"
24
- "X-Poedit-Bookmarks: \n"
25
  "X-Textdomain-Support: yes\n"
 
26
 
27
- #: app/admin/RTMediaAdmin.php:127
28
- msgid "View &#8220;%s&#8221;"
29
  msgstr ""
30
 
31
- #: app/admin/RTMediaAdmin.php:127
32
- msgid "View"
33
  msgstr ""
34
 
35
- #: app/admin/RTMediaAdmin.php:369
36
- msgid " You must"
 
37
  msgstr ""
38
 
39
- #: app/admin/RTMediaAdmin.php:369
40
- msgid "update permalink structure"
41
  msgstr ""
42
 
43
- #: app/admin/RTMediaAdmin.php:369
44
- msgid "to something other than the default for it to work."
 
 
 
 
 
45
  msgstr ""
46
 
47
- #: app/admin/RTMediaAdmin.php:395
48
- msgid "rtMedia:"
 
 
 
49
  msgstr ""
50
 
51
- #: app/admin/RTMediaAdmin.php:395
52
- msgid "Please update all premium add-ons that you have purchased from rtCamp from"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  msgstr ""
54
 
55
- #: app/admin/RTMediaAdmin.php:395
56
- msgid "your account"
57
  msgstr ""
58
 
59
- #: app/admin/RTMediaAdmin.php:395
60
- msgid "Dismiss"
 
61
  msgstr ""
62
 
63
- #: app/admin/RTMediaAdmin.php:508
64
- msgid "rtMedia Pro is released"
65
  msgstr ""
66
 
67
- #: app/admin/RTMediaAdmin.php:529
68
- msgid "Media Stats"
 
 
 
69
  msgstr ""
70
 
71
- #: app/admin/RTMediaAdmin.php:556
72
- msgid "Usage Stats"
73
  msgstr ""
74
 
75
- #: app/admin/RTMediaAdmin.php:565
76
- msgid "Total "
77
  msgstr ""
78
 
79
- #: app/admin/RTMediaAdmin.php:573
80
- msgid "With Media"
 
81
  msgstr ""
82
 
83
- #: app/admin/RTMediaAdmin.php:581
84
- msgid "Comments "
85
  msgstr ""
86
 
87
- #: app/admin/RTMediaAdmin.php:589 app/main/controllers/media/RTMediaLike.php:19
88
- msgid "Likes"
89
  msgstr ""
90
 
91
- #: app/admin/RTMediaAdmin.php:600
92
- msgid "rtMedia Links:"
 
93
  msgstr ""
94
 
95
- #: app/admin/RTMediaAdmin.php:601
96
- msgid "Homepage"
97
  msgstr ""
98
 
99
- #: app/admin/RTMediaAdmin.php:602
100
- msgid "Free Support"
 
101
  msgstr ""
102
 
103
- #: app/admin/RTMediaAdmin.php:603
104
- msgid "Premium Addons"
105
  msgstr ""
106
 
107
- #: app/admin/RTMediaAdmin.php:619
108
- msgid "Right Now in rtMedia"
 
 
109
  msgstr ""
110
 
111
- #: app/admin/RTMediaAdmin.php:673 app/admin/RTMediaAdmin.php:882
112
- msgid "Regenerate Thumbnail"
113
  msgstr ""
114
 
115
- #: app/admin/RTMediaAdmin.php:714 app/admin/RTMediaAdmin.php:1368
116
- #: app/admin/RTMediaAdmin.php:1369
117
- msgid "rtMedia"
118
  msgstr ""
119
 
120
- #: app/admin/RTMediaAdmin.php:721 app/admin/RTMediaAdmin.php:724
121
- #: app/admin/RTMediaAdmin.php:870 app/admin/RTMediaAdmin.php:1398
122
- msgid "Settings"
123
  msgstr ""
124
 
125
- #: app/admin/RTMediaAdmin.php:732 app/admin/RTMediaAdmin.php:735
126
- #: app/admin/RTMediaAdmin.php:871 app/admin/RTMediaAdmin.php:1402
127
- msgid "Addons"
128
  msgstr ""
129
 
130
- #: app/admin/RTMediaAdmin.php:743 app/admin/RTMediaAdmin.php:746
131
- #: app/admin/RTMediaAdmin.php:872 app/admin/RTMediaAdmin.php:1414
132
- #: app/helper/RTMediaSettings.php:208 app/helper/RTMediaSupport.php:51
133
- #: app/helper/RTMediaSupport.php:52
134
- msgid "Support"
135
  msgstr ""
136
 
137
- #: app/admin/RTMediaAdmin.php:754 app/admin/RTMediaAdmin.php:757
138
- #: app/admin/RTMediaAdmin.php:873 app/admin/RTMediaAdmin.php:1406
139
- msgid "Themes"
140
  msgstr ""
141
 
142
- #: app/admin/RTMediaAdmin.php:765 app/admin/RTMediaAdmin.php:768
143
- #: app/admin/RTMediaAdmin.php:874 app/admin/RTMediaAdmin.php:1410
144
- msgid "Hire Us"
 
145
  msgstr ""
146
 
147
- #: app/admin/RTMediaAdmin.php:777 app/admin/RTMediaAdmin.php:780
148
- #: app/admin/RTMediaAdmin.php:876 app/admin/RTMediaAdmin.php:1422
149
- msgid "Licenses"
 
150
  msgstr ""
151
 
152
- #: app/admin/RTMediaAdmin.php:831
153
- msgid "ON"
 
154
  msgstr ""
155
 
156
- #: app/admin/RTMediaAdmin.php:832
157
- msgid "OFF"
 
 
158
  msgstr ""
159
 
160
- #: app/admin/RTMediaAdmin.php:838
161
- msgid "Please do not refresh this page."
162
  msgstr ""
163
 
164
- #: app/admin/RTMediaAdmin.php:839
165
- msgid ""
166
- "Something went wrong. Please <a href "
167
- "onclick=\"location.reload();\">refresh</a> page."
168
  msgstr ""
169
 
170
- #: app/admin/RTMediaAdmin.php:840
171
- msgid "This will subscribe you to the free plan."
 
172
  msgstr ""
173
 
174
- #: app/admin/RTMediaAdmin.php:841
175
- msgid "Are you sure you want to disable the encoding service?"
 
176
  msgstr ""
177
 
178
- #: app/admin/RTMediaAdmin.php:842
179
- msgid "Are you sure you want to enable the encoding service?"
180
  msgstr ""
181
 
182
- #: app/admin/RTMediaAdmin.php:882
183
- msgid "Regen. Thumbnail "
184
  msgstr ""
185
 
186
- #: app/admin/RTMediaAdmin.php:900 app/admin/RTMediaAdmin.php:1879
187
- msgid "Regenerate Video Thumbnails"
 
188
  msgstr ""
189
 
190
- #: app/admin/RTMediaAdmin.php:918
191
- msgid "Regenerate Pending Thumbnails"
 
 
192
  msgstr ""
193
 
194
- #: app/admin/RTMediaAdmin.php:928
195
- msgid "Total Videos"
 
196
  msgstr ""
197
 
198
- #: app/admin/RTMediaAdmin.php:931
199
- msgid "Sent of regenerate thumbails"
 
 
200
  msgstr ""
201
 
202
- #: app/admin/RTMediaAdmin.php:933
203
- msgid "Fail to regenerate thumbails"
 
204
  msgstr ""
205
 
206
- #: app/admin/RTMediaAdmin.php:972
207
- msgid "Regenerate Video Thumbnails Done"
 
208
  msgstr ""
209
 
210
- #: app/admin/RTMediaAdmin.php:1016
211
- msgid ""
212
- "You have %s videos without thumbnails. Click <a href='%s'> here </a> to "
213
- "generate thumbnails. <a href='#' "
214
- "onclick='rtmedia_hide_video_thumb_notice()' style='float:right'>Hide</a>"
215
  msgstr ""
216
 
217
- #: app/admin/RTMediaAdmin.php:1094
218
- msgid "not a video ..."
 
 
219
  msgstr ""
220
 
221
- #: app/admin/RTMediaAdmin.php:1259
222
- msgid "Empowering The Web With WordPress"
 
223
  msgstr ""
224
 
225
- #: app/admin/RTMediaAdmin.php:1279
226
- msgid "Settings saved successfully!"
227
  msgstr ""
228
 
229
- #: app/admin/RTMediaAdmin.php:1282 app/admin/RTMediaAdmin.php:1305
230
- msgid "Save Settings"
231
  msgstr ""
232
 
233
- #: app/admin/RTMediaAdmin.php:1504 app/admin/RTMediaAdmin.php:1505
234
- msgid "Display"
 
 
235
  msgstr ""
236
 
237
- #: app/admin/RTMediaAdmin.php:1513
238
- msgid "rtMedia BuddyPress"
 
 
239
  msgstr ""
240
 
241
- #: app/admin/RTMediaAdmin.php:1514
242
- msgid "BuddyPress"
243
  msgstr ""
244
 
245
- #: app/admin/RTMediaAdmin.php:1522
246
- msgid "rtMedia Types"
247
  msgstr ""
248
 
249
- #: app/admin/RTMediaAdmin.php:1523
250
- msgid "Types"
 
251
  msgstr ""
252
 
253
- #: app/admin/RTMediaAdmin.php:1530
254
- msgid "rtMedia Sizes"
 
255
  msgstr ""
256
 
257
- #: app/admin/RTMediaAdmin.php:1531
258
- msgid "Media Sizes"
259
  msgstr ""
260
 
261
- #: app/admin/RTMediaAdmin.php:1538
262
- msgid "rtMedia Privacy"
263
  msgstr ""
264
 
265
- #: app/admin/RTMediaAdmin.php:1539
266
- #: app/main/controllers/privacy/RTMediaPrivacy.php:310
267
- msgid "Privacy"
268
  msgstr ""
269
 
270
- #: app/admin/RTMediaAdmin.php:1545
271
- msgid "rtMedia Custom CSS"
272
  msgstr ""
273
 
274
- #: app/admin/RTMediaAdmin.php:1546
275
- msgid "Custom CSS"
276
  msgstr ""
277
 
278
- #: app/admin/RTMediaAdmin.php:1555 app/admin/RTMediaAdmin.php:1556
279
- msgid "Other Settings"
 
280
  msgstr ""
281
 
282
- #: app/admin/RTMediaAdmin.php:1651
283
- msgid "I use @rtMediaWP http://rt.cx/rtmedia on %s"
284
  msgstr ""
285
 
286
- #: app/admin/RTMediaAdmin.php:1653
287
- msgid "Post to Twitter Now"
288
  msgstr ""
289
 
290
- #: app/admin/RTMediaAdmin.php:1653
291
- msgid "Post to Twitter"
292
  msgstr ""
293
 
294
- #: app/admin/RTMediaAdmin.php:1654
295
- msgid "Share on Facebook Now"
 
296
  msgstr ""
297
 
298
- #: app/admin/RTMediaAdmin.php:1654
299
- msgid "Share on Facebook"
300
  msgstr ""
301
 
302
- #: app/admin/RTMediaAdmin.php:1655
303
- msgid "Rate rtMedia on Wordpress.org"
304
  msgstr ""
305
 
306
- #: app/admin/RTMediaAdmin.php:1655
307
- msgid "Rate on Wordpress.org"
308
  msgstr ""
309
 
310
- #: app/admin/RTMediaAdmin.php:1656
311
- msgid "Subscribe to our Feeds"
312
  msgstr ""
313
 
314
- #: app/admin/RTMediaAdmin.php:1659
315
- msgid "Spread the Word"
 
316
  msgstr ""
317
 
318
- #: app/admin/RTMediaAdmin.php:1665 app/admin/RTMediaAdmin.php:1672
319
- msgid "Subscribe"
320
  msgstr ""
321
 
322
- #: app/admin/RTMediaAdmin.php:1694
323
- msgid "Thank you for your time."
 
324
  msgstr ""
325
 
326
- #: app/admin/RTMediaAdmin.php:1706
327
- msgid "Premium Add-ons"
328
  msgstr ""
329
 
330
- #: app/admin/RTMediaAdmin.php:1722
331
- msgid ""
332
- "You have images enabled on rtMedia but your network allowed filetypes do "
333
- "not permit uploading of %s. Click <a href=\"%s\">here</a> to change your "
334
- "settings manually."
335
  msgstr ""
336
 
337
- #: app/admin/RTMediaAdmin.php:1723 app/admin/RTMediaAdmin.php:1734
338
- #: app/admin/RTMediaAdmin.php:1743
339
- msgid "Recommended"
340
  msgstr ""
341
 
342
- #: app/admin/RTMediaAdmin.php:1723 app/admin/RTMediaAdmin.php:1734
343
- #: app/admin/RTMediaAdmin.php:1743
344
- msgid "Update Network Settings Automatically"
345
  msgstr ""
346
 
347
- #: app/admin/RTMediaAdmin.php:1733
348
- msgid ""
349
- "You have video enabled on BuddyPress Media but your network allowed "
350
- "filetypes do not permit uploading of mp4. Click <a href=\"%s\">here</a> to "
351
- "change your settings manually."
352
  msgstr ""
353
 
354
- #: app/admin/RTMediaAdmin.php:1742
355
- msgid ""
356
- "You have audio enabled on BuddyPress Media but your network allowed "
357
- "filetypes do not permit uploading of mp3. Click <a href=\"%s\">here</a> to "
358
- "change your settings manually."
359
  msgstr ""
360
 
361
- #: app/admin/RTMediaAdmin.php:1757
362
- msgid "Network settings updated successfully."
 
363
  msgstr ""
364
 
365
- #: app/admin/RTMediaAdmin.php:1863
366
- msgid "Video is sent to generate thumbnails."
367
  msgstr ""
368
 
369
- #: app/admin/RTMediaAdmin.php:1865
370
- msgid "Video cannot be sent to generate thumbnails."
 
 
371
  msgstr ""
372
 
373
- #: app/admin/RTMediaAdmin.php:1944
374
- msgid ""
375
- "Please update rtMedia template files if you have overridden the default "
376
- "rtMedia templates in your theme. If not, you can ignore and hide this "
377
- "notice."
378
  msgstr ""
379
 
380
- #: app/admin/RTMediaAdmin.php:1944
381
- #: app/importers/RTMediaMediaSizeImporter.php:66
382
- #: app/importers/RTMediaMigration.php:64
383
- msgid "Hide"
384
  msgstr ""
385
 
386
- #: app/admin/RTMediaFormHandler.php:65 app/admin/RTMediaFormHandler.php:107
387
- #: app/admin/RTMediaFormHandler.php:202 app/admin/RTMediaFormHandler.php:237
388
- msgid "Please provide a \"value\" in the argument."
 
 
389
  msgstr ""
390
 
391
- #: app/admin/RTMediaFormHandler.php:150
392
- msgid "Need to specify atleast two radios, else use a checkbox instead"
 
 
 
 
 
393
  msgstr ""
394
 
395
- #: app/admin/RTMediaFormHandler.php:285 templates/media/album-gallery.php:56
396
- #: templates/media/media-gallery.php:65
397
- msgid "Load More"
 
398
  msgstr ""
399
 
400
- #: app/admin/RTMediaFormHandler.php:286
401
- msgid "Pagination"
 
 
 
402
  msgstr ""
403
 
404
- #: app/admin/RTMediaFormHandler.php:298
405
- msgid "Allow user to comment on uploaded media"
 
 
 
406
  msgstr ""
407
 
408
- #: app/admin/RTMediaFormHandler.php:303
 
409
  msgid ""
410
- "This will display the comment form and comment listing on single media "
411
- "pages as well as inside lightbox (if lightbox is enabled)."
412
  msgstr ""
413
 
414
- #: app/admin/RTMediaFormHandler.php:308
415
- msgid "Use lightbox to display media"
416
  msgstr ""
417
 
418
- #: app/admin/RTMediaFormHandler.php:313
419
- msgid "View single media in facebook style lightbox."
 
420
  msgstr ""
421
 
422
- #: app/admin/RTMediaFormHandler.php:318
423
- msgid "Number of media per page"
424
  msgstr ""
425
 
426
- #: app/admin/RTMediaFormHandler.php:324
427
- msgid "Number of media items you want to show per page on front end."
428
  msgstr ""
429
 
430
- #: app/admin/RTMediaFormHandler.php:330
431
- msgid "Media display pagination option"
432
  msgstr ""
433
 
434
- #: app/admin/RTMediaFormHandler.php:336
435
- msgid "Choose whether you want the load more button or pagination buttons."
 
436
  msgstr ""
437
 
438
- #: app/admin/RTMediaFormHandler.php:341
439
- msgid "Enable"
440
  msgstr ""
441
 
442
- #: app/admin/RTMediaFormHandler.php:341
443
- msgid "Cascading grid layout"
444
  msgstr ""
445
 
446
- #: app/admin/RTMediaFormHandler.php:346
447
- msgid "If you enable masonry view, it is advisable to"
448
  msgstr ""
449
 
450
- #: app/admin/RTMediaFormHandler.php:346
451
- msgid "for masonry view."
452
  msgstr ""
453
 
454
- #: app/admin/RTMediaFormHandler.php:350
455
- msgid "You might need to"
456
  msgstr ""
457
 
458
- #: app/admin/RTMediaFormHandler.php:350
459
- msgid "change thumbnail size"
460
  msgstr ""
461
 
462
- #: app/admin/RTMediaFormHandler.php:350
463
- msgid "and uncheck the crop box for thumbnails."
 
 
 
464
  msgstr ""
465
 
466
- #: app/admin/RTMediaFormHandler.php:350
467
- msgid ""
468
- "To set gallery for fixed width, set image height to 0 and width as per your "
469
- "requirement and vice-versa."
470
  msgstr ""
471
 
472
- #: app/admin/RTMediaFormHandler.php:353
473
- msgid "Enable Direct Upload"
474
  msgstr ""
475
 
476
- #: app/admin/RTMediaFormHandler.php:358
477
- msgid "Uploading media directly as soon as it gets selected."
478
  msgstr ""
479
 
480
- #: app/admin/RTMediaFormHandler.php:384
481
- msgid "Single Media View"
482
  msgstr ""
483
 
484
- #: app/admin/RTMediaFormHandler.php:385
485
- msgid "List Media View"
486
  msgstr ""
487
 
488
- #: app/admin/RTMediaFormHandler.php:386
489
- msgid "Masonry View"
490
  msgstr ""
491
 
492
- #: app/admin/RTMediaFormHandler.php:387
493
- msgid "Direct Upload"
494
  msgstr ""
495
 
496
- #: app/admin/RTMediaFormHandler.php:405
497
- msgid "Allow usage data tracking"
498
  msgstr ""
499
 
500
- #: app/admin/RTMediaFormHandler.php:410
501
- msgid ""
502
- "To make rtMedia better compatible with your sites, you can help the rtMedia "
503
- "team learn what themes and plugins you are using. No private information "
504
- "about your setup will be sent during tracking."
505
  msgstr ""
506
 
507
- #: app/admin/RTMediaFormHandler.php:414
508
- msgid "Admin bar menu integration"
509
  msgstr ""
510
 
511
- #: app/admin/RTMediaFormHandler.php:419
512
- msgid ""
513
- "Add rtMedia menu to WordPress admin bar for easy access to settings and "
514
- "moderation page (if enabled)."
515
  msgstr ""
516
 
517
- #: app/admin/RTMediaFormHandler.php:424
518
- msgid "Add a link to rtMedia in footer"
519
  msgstr ""
520
 
521
- #: app/admin/RTMediaFormHandler.php:429
522
- msgid "Help us promote rtMedia."
523
  msgstr ""
524
 
525
- #: app/admin/RTMediaFormHandler.php:434
526
- msgid "Also add my affiliate-id to rtMedia footer link"
 
 
527
  msgstr ""
528
 
529
- #: app/admin/RTMediaFormHandler.php:439
 
 
 
 
 
 
 
530
  msgid ""
531
- "Add your affiliate-id along with footer link and get rewarded by our "
532
- "affiliation program."
533
  msgstr ""
534
 
535
- #: app/admin/RTMediaFormHandler.php:443
536
- msgid "Signup for"
 
 
 
 
537
  msgstr ""
538
 
539
- #: app/admin/RTMediaFormHandler.php:443
540
- msgid "affiliate program"
541
  msgstr ""
542
 
543
- #: app/admin/RTMediaFormHandler.php:443 app/admin/RTMediaFormHandler.php:454
544
- #: app/helper/RTMediaSupport.php:363
545
- msgid "here"
546
  msgstr ""
547
 
548
- #: app/admin/RTMediaFormHandler.php:446
549
- msgid "Enable JSON API"
550
  msgstr ""
551
 
552
- #: app/admin/RTMediaFormHandler.php:451
553
- msgid ""
554
- "This will allow handling API requests for rtMedia sent through any mobile "
555
- "app."
556
  msgstr ""
557
 
558
- #: app/admin/RTMediaFormHandler.php:454
559
- msgid "You can refer to the API document from"
560
  msgstr ""
561
 
562
- #: app/admin/RTMediaFormHandler.php:477
563
- msgid "Admin Settings"
564
  msgstr ""
565
 
566
- #: app/admin/RTMediaFormHandler.php:478
567
- msgid "API Settings"
568
  msgstr ""
569
 
570
- #: app/admin/RTMediaFormHandler.php:479
571
- msgid "Miscellaneous"
572
  msgstr ""
573
 
574
- #: app/admin/RTMediaFormHandler.php:480
575
- msgid "Footer Link"
576
  msgstr ""
577
 
578
- #: app/admin/RTMediaFormHandler.php:560
579
- msgid "Media Types Settings"
 
580
  msgstr ""
581
 
582
- #: app/admin/RTMediaFormHandler.php:568 app/helper/RTMediaSettings.php:324
583
- msgid "Media Type"
 
584
  msgstr ""
585
 
586
- #: app/admin/RTMediaFormHandler.php:573
587
- msgid "Allow Upload"
 
588
  msgstr ""
589
 
590
- #: app/admin/RTMediaFormHandler.php:575
591
- msgid "Allows you to upload a particular media type on your post."
592
  msgstr ""
593
 
594
- #: app/admin/RTMediaFormHandler.php:583
595
- msgid "Set Featured"
596
  msgstr ""
597
 
598
- #: app/admin/RTMediaFormHandler.php:585
599
- msgid "Place a specific media as a featured content on the post."
 
600
  msgstr ""
601
 
602
- #: app/admin/RTMediaFormHandler.php:627
603
- msgid "File Extensions"
 
604
  msgstr ""
605
 
606
- #: app/admin/RTMediaFormHandler.php:715
607
- msgid "Media Size Settings"
608
  msgstr ""
609
 
610
- #: app/admin/RTMediaFormHandler.php:720
611
- msgid "Category"
612
  msgstr ""
613
 
614
- #: app/admin/RTMediaFormHandler.php:721
615
- msgid "Entity"
 
616
  msgstr ""
617
 
618
- #: app/admin/RTMediaFormHandler.php:722
619
- msgid "Width"
 
620
  msgstr ""
621
 
622
- #: app/admin/RTMediaFormHandler.php:723
623
- msgid "Height"
 
624
  msgstr ""
625
 
626
- #: app/admin/RTMediaFormHandler.php:724
627
- msgid "Crop"
 
 
 
628
  msgstr ""
629
 
630
- #: app/admin/RTMediaFormHandler.php:777
631
- msgid "Number of thumbnails to generate on video upload"
 
632
  msgstr ""
633
 
634
- #: app/admin/RTMediaFormHandler.php:783
635
- msgid ""
636
- " If you choose more than 1 thumbnail, your users will be able to change the "
637
- "thumbnail by going to video 'edit' section. Maximum value is 10."
 
638
  msgstr ""
639
 
640
- #: app/admin/RTMediaFormHandler.php:791
641
- msgid "Encoding Settings"
642
  msgstr ""
643
 
644
- #: app/admin/RTMediaFormHandler.php:798
645
- msgid "JPEG/JPG image quality (1-100)"
 
646
  msgstr ""
647
 
648
- #: app/admin/RTMediaFormHandler.php:804
649
- msgid "Enter JPEG/JPG Image Quality. Minimum value is 1. 100 is original quality."
 
650
  msgstr ""
651
 
652
- #: app/admin/RTMediaFormHandler.php:812
653
- msgid "Image Quality"
654
  msgstr ""
655
 
656
- #: app/admin/RTMediaFormHandler.php:834
657
- msgid "Custom CSS settings"
658
  msgstr ""
659
 
660
- #: app/admin/RTMediaFormHandler.php:853
661
- msgid "rtMedia default styles"
 
 
662
  msgstr ""
663
 
664
- #: app/admin/RTMediaFormHandler.php:859
 
665
  msgid ""
666
- "Load default rtMedia styles. You need to write your own style for rtMedia "
667
- "if you disable it."
668
  msgstr ""
669
 
670
- #: app/admin/RTMediaFormHandler.php:864
671
- msgid "Paste your CSS code"
 
 
672
  msgstr ""
673
 
674
- #: app/admin/RTMediaFormHandler.php:870
675
- msgid "Custom rtMedia CSS container"
676
  msgstr ""
677
 
678
- #: app/admin/RTMediaFormHandler.php:893
679
- msgid "Enable privacy"
 
680
  msgstr ""
681
 
682
- #: app/admin/RTMediaFormHandler.php:899
683
- msgid "Enable privacy in rtMedia"
684
  msgstr ""
685
 
686
- #: app/admin/RTMediaFormHandler.php:904
687
- msgid "Default privacy"
 
 
 
688
  msgstr ""
689
 
690
- #: app/admin/RTMediaFormHandler.php:910
691
- msgid "Set default privacy for media"
 
 
 
692
  msgstr ""
693
 
694
- #: app/admin/RTMediaFormHandler.php:916
695
- msgid "Allow users to set privacy for their content"
696
  msgstr ""
697
 
698
- #: app/admin/RTMediaFormHandler.php:921
699
- msgid ""
700
- "If you choose this, users will be able to change privacy of their own "
701
- "uploads."
702
  msgstr ""
703
 
704
- #: app/admin/RTMediaFormHandler.php:925
705
- msgid "For group uploads, BuddyPress groups privacy is used."
 
706
  msgstr ""
707
 
708
- #: app/admin/RTMediaFormHandler.php:967
709
- msgid "Enable media in profile"
 
710
  msgstr ""
711
 
712
- #: app/admin/RTMediaFormHandler.php:972
713
- msgid "Enable Media on BuddyPress Profile"
 
714
  msgstr ""
715
 
716
- #: app/admin/RTMediaFormHandler.php:977
717
- msgid "Enable media in group"
718
  msgstr ""
719
 
720
- #: app/admin/RTMediaFormHandler.php:982
721
- msgid "Enable Media on BuddyPress Groups"
 
 
722
  msgstr ""
723
 
724
- #: app/admin/RTMediaFormHandler.php:987
725
- msgid "Allow upload from activity stream"
 
726
  msgstr ""
727
 
728
- #: app/admin/RTMediaFormHandler.php:992
729
- msgid "Allow upload using status update box present on activity stream page"
730
  msgstr ""
731
 
732
- #: app/admin/RTMediaFormHandler.php:998
733
- msgid "Number of media items to show in activity stream"
734
  msgstr ""
735
 
736
- #: app/admin/RTMediaFormHandler.php:1003
 
 
 
 
 
737
  msgid ""
738
- "With bulk uploads activity, the stream may get flooded. You can control the "
739
- "maximum number of media items or files per activity. This limit will not "
740
- "affect the actual number of uploads. This is only for display. <em>0</em> "
741
- "means unlimited."
742
  msgstr ""
743
 
744
- #: app/admin/RTMediaFormHandler.php:1010
745
- msgid "Enable media notification"
746
  msgstr ""
747
 
748
- #: app/admin/RTMediaFormHandler.php:1015
749
- msgid ""
750
- "This will enable notifications to media authors for media likes and "
751
- "comments."
752
  msgstr ""
753
 
754
- #: app/admin/RTMediaFormHandler.php:1021
755
- msgid "Organize media into albums"
756
  msgstr ""
757
 
758
- #: app/admin/RTMediaFormHandler.php:1027
759
- msgid ""
760
- "This will add 'album' tab to BuddyPress profile and group depending on the "
761
- "^above^ settings."
762
  msgstr ""
763
 
764
- #: app/helper/RTMediaAddon.php:79 app/helper/RTMediaAddon.php:80
765
- msgid "Plugins"
766
  msgstr ""
767
 
768
- #: app/helper/RTMediaAddon.php:87 app/helper/RTMediaAddon.php:88
769
- msgid "Audio/Video Encoding"
770
  msgstr ""
771
 
772
- #: app/helper/RTMediaAddon.php:111
773
- msgid "SEO"
774
  msgstr ""
775
 
776
- #: app/helper/RTMediaAddon.php:114
777
  msgid ""
778
- "Generate an XML sitemap for all the public media files uploaded via rtMedia "
779
- "plugin. These sitemaps can be useful to index search engine to improve "
780
- "website SEO."
781
  msgstr ""
782
 
783
- #: app/helper/RTMediaAddon.php:121
784
- msgid "Moderation"
 
 
 
785
  msgstr ""
786
 
787
- #: app/helper/RTMediaAddon.php:124
788
  msgid ""
789
- "Report media if they find offensive. Set number of reports to automatically "
790
- "take down media from site."
791
  msgstr ""
792
 
793
- #: app/helper/RTMediaAddon.php:132
794
- msgid "Custom Attributes"
 
 
795
  msgstr ""
796
 
797
- #: app/helper/RTMediaAddon.php:135
798
- msgid ""
799
- "Categories media based on attributes. Site owner need to create attributes. "
800
- "When user upload a media, can select in which attribute that media can add."
801
  msgstr ""
802
 
803
- #: app/helper/RTMediaAddon.php:143
804
- msgid "Docs and Other files"
 
 
805
  msgstr ""
806
 
807
- #: app/helper/RTMediaAddon.php:146
808
- msgid ""
809
- "Allow users to upload documents and other file type using rtMedia upload "
810
- "box. This addon support all the file extensions which WordPress allows."
811
  msgstr ""
812
 
813
- #: app/helper/RTMediaAddon.php:154
814
- msgid "Default Albums"
 
 
815
  msgstr ""
816
 
817
- #: app/helper/RTMediaAddon.php:157
 
818
  msgid ""
819
- "This plugin allows the creation of multiple default albums for rtMedia "
820
- "uploads. One of these albums can be set as the default global album."
821
  msgstr ""
822
 
823
- #: app/helper/RTMediaAddon.php:165
824
- msgid "Podcast (RSS and Atom feeds)"
 
825
  msgstr ""
826
 
827
- #: app/helper/RTMediaAddon.php:168
828
  msgid ""
829
- "Read rtMedia uploads from iTunes as well as any RSS feed-reader/podcasting "
830
- "software."
831
  msgstr ""
832
 
833
- #: app/helper/RTMediaAddon.php:176
834
- msgid "Playlists"
 
835
  msgstr ""
836
 
837
- #: app/helper/RTMediaAddon.php:179
 
838
  msgid ""
839
- "Audio can be grouped into playlists. Once the user upload any audio file, "
840
- "can create a playlist or use existing one to manage audio files."
 
841
  msgstr ""
842
 
843
- #: app/helper/RTMediaAddon.php:187
844
- msgid "Favorites"
 
845
  msgstr ""
846
 
847
- #: app/helper/RTMediaAddon.php:190
 
 
 
 
848
  msgid ""
849
- "Users can create their list of favorite media in which they can add media "
850
- "previously uploaded by any user."
851
  msgstr ""
852
 
853
- #: app/helper/RTMediaAddon.php:198
854
- msgid "Restrictions"
855
  msgstr ""
856
 
857
- #: app/helper/RTMediaAddon.php:201
 
858
  msgid ""
859
- "Site admin can set an upload limit on the basis of time span, file size "
860
- "(MB) and number of files user can upload."
861
  msgstr ""
862
 
863
- #: app/helper/RTMediaAddon.php:209
864
- msgid "bbPress Attachments"
865
  msgstr ""
866
 
867
- #: app/helper/RTMediaAddon.php:212
868
- msgid "Attach media files to bbPress forum topics and replies."
 
 
 
869
  msgstr ""
870
 
871
- #: app/helper/RTMediaAddon.php:220
872
- msgid "WordPress Sitewide Gallery"
 
873
  msgstr ""
874
 
875
- #: app/helper/RTMediaAddon.php:223
 
 
 
 
 
 
876
  msgid ""
877
- "Site admin can create and upload media into WordPress album. Create album "
878
- "without being dependent on BuddyPress."
879
  msgstr ""
880
 
881
- #: app/helper/RTMediaAddon.php:231
882
- msgid "WordPress Comment Attachments"
883
  msgstr ""
884
 
885
- #: app/helper/RTMediaAddon.php:234
 
886
  msgid ""
887
- "Allow users to upload a media file in WordPress comment attachment box. It "
888
- "will display a thumbnail of attached file."
889
  msgstr ""
890
 
891
- #: app/helper/RTMediaAddon.php:242
892
- msgid "Social Sharing"
893
  msgstr ""
894
 
895
- #: app/helper/RTMediaAddon.php:245
 
896
  msgid ""
897
- "Share uploaded media on social network sites like Facebook, twitter, "
898
- "linkedin, Google +. This addon integrate with rtSocial plugin."
899
  msgstr ""
900
 
901
- #: app/helper/RTMediaAddon.php:253
902
- msgid "Sidebar Widgets"
903
  msgstr ""
904
 
905
- #: app/helper/RTMediaAddon.php:256
906
  msgid ""
907
- "This addon provide widgets to upload media and display gallery for rtMedia "
908
- "plugin."
 
909
  msgstr ""
910
 
911
- #: app/helper/RTMediaAddon.php:264
912
- msgid "5 Star Ratings"
 
 
913
  msgstr ""
914
 
915
- #: app/helper/RTMediaAddon.php:267
 
 
 
 
 
916
  msgid ""
917
- "Display 5 star rating for all the uploaded media. User can rate the media "
918
- "files from 1 to 5 star."
919
  msgstr ""
920
 
921
- #: app/helper/RTMediaAddon.php:275
922
- msgid "Edit Mp3 Info (ID3 Tags)"
923
  msgstr ""
924
 
925
- #: app/helper/RTMediaAddon.php:278
926
- msgid "Allow user to edit MP3 FIle Audio tags (ID 3 tags)."
927
  msgstr ""
928
 
929
- #: app/helper/RTMediaAddon.php:286
930
- msgid "Media Sorting"
931
  msgstr ""
932
 
933
- #: app/helper/RTMediaAddon.php:289
934
  msgid ""
935
- "Sort uploaded media based on file size, ascending/descending title, upload "
936
- "date of media."
937
  msgstr ""
938
 
939
- #: app/helper/RTMediaAddon.php:297
940
- msgid "Bulk Edit"
 
 
 
 
941
  msgstr ""
942
 
943
- #: app/helper/RTMediaAddon.php:300
 
 
944
  msgid ""
945
- "Bulk edit option will allow user to quickly select media files and do "
946
- "required actions like move files from one album to another, change "
947
- "attributes, change privacy, delete files."
948
  msgstr ""
949
 
950
- #: app/helper/RTMediaAddon.php:308
951
- msgid "BuddyPress Profile Picture"
 
 
952
  msgstr ""
953
 
954
- #: app/helper/RTMediaAddon.php:311
955
- msgid "User can easily set his/her profile picture from media uploaded via rtMedia."
 
 
 
 
956
  msgstr ""
957
 
958
- #: app/helper/RTMediaAddon.php:319
959
- msgid "Album Cover Art"
 
 
 
960
  msgstr ""
961
 
962
- #: app/helper/RTMediaAddon.php:322
963
- msgid "User can easily set any of the image of the album as album cover photo"
 
964
  msgstr ""
965
 
966
- #: app/helper/RTMediaAddon.php:330
967
- msgid "Direct Download Link"
968
  msgstr ""
969
 
970
- #: app/helper/RTMediaAddon.php:333
971
- msgid ""
972
- "User can download media from website. Site owner can restrict which media "
973
- "type can be allowed to download."
974
  msgstr ""
975
 
976
- #: app/helper/RTMediaAddon.php:341
977
- msgid "Upload by URL"
 
 
978
  msgstr ""
979
 
980
- #: app/helper/RTMediaAddon.php:344
981
- msgid ""
982
- "Users do not need to download media files from a URL and then upload it "
983
- "with rtMedia. Just provide the absolute URL for the media and it will "
984
- "upload on site."
985
  msgstr ""
986
 
987
- #: app/helper/RTMediaAddon.php:352
988
- msgid "Media Likes"
 
989
  msgstr ""
990
 
991
- #: app/helper/RTMediaAddon.php:355
992
- msgid ""
993
- "This add-on let you know who liked the media. User can also see which media "
994
- "they liked under their profile."
995
  msgstr ""
996
 
997
- #: app/helper/RTMediaAddon.php:363
998
- msgid "Activity URL Preview"
 
999
  msgstr ""
1000
 
1001
- #: app/helper/RTMediaAddon.php:366
1002
- msgid ""
1003
- "This addon provides a preview of the URL that is shared in BuddyPress "
1004
- "activity. Just enter the URL you want to share on your site and see a "
1005
- "preview of it before it is shared."
1006
  msgstr ""
1007
 
1008
- #: app/helper/RTMediaAddon.php:374
1009
- msgid "View Counter"
 
1010
  msgstr ""
1011
 
1012
- #: app/helper/RTMediaAddon.php:377
1013
- msgid ""
1014
- "Enable view count for all the uploaded media. Whenever user open that media "
1015
- "file in lightbox or in single media view, that view count will be "
1016
- "calculated and display next to media file."
1017
  msgstr ""
1018
 
1019
- #: app/helper/RTMediaAddon.php:385
1020
- msgid "Shortcode Generator"
 
1021
  msgstr ""
1022
 
1023
- #: app/helper/RTMediaAddon.php:388
1024
- msgid ""
1025
- "This add-on will add shortcode generator button in WordPress post and page "
1026
- "editor for all the rtMedia shortcodes."
1027
  msgstr ""
1028
 
1029
- #: app/helper/RTMediaAddon.php:396
1030
- msgid "Album Privacy"
1031
  msgstr ""
1032
 
1033
- #: app/helper/RTMediaAddon.php:399
1034
- msgid ""
1035
- "Set album privacy when user create an album or change album privacy when "
1036
- "editing existing albums. The privacy levels are Public, Logged in user, "
1037
- "Friends and Private."
1038
  msgstr ""
1039
 
1040
- #: app/helper/RTMediaAddon.php:407
1041
- msgid "BuddyPress Group Media Control"
1042
  msgstr ""
1043
 
1044
- #: app/helper/RTMediaAddon.php:410
1045
- msgid "This add-on allows group owner to manage media upload feature group wise."
1046
  msgstr ""
1047
 
1048
- #: app/helper/RTMediaAddon.php:418
1049
- msgid "Set Custom Thumbnail for Audio/Video"
 
1050
  msgstr ""
1051
 
1052
- #: app/helper/RTMediaAddon.php:421
1053
- msgid ""
1054
- "Allow media owner to change the thumbnail of uploaded audio/video files. "
1055
- "The File Upload box will be provided to change media thumbnail."
1056
  msgstr ""
1057
 
1058
- #: app/helper/RTMediaAddon.php:429
1059
- msgid "myCRED"
 
1060
  msgstr ""
1061
 
1062
- #: app/helper/RTMediaAddon.php:432
1063
- msgid ""
1064
- "This plugin integrates rtMedia and myCRED plugin, users can be can award "
1065
- "virtual points for various rtMedia activities, like media upload, likes, "
1066
- "deleted etc."
1067
  msgstr ""
1068
 
1069
- #: app/helper/RTMediaAddon.php:440
1070
- msgid "Upload terms"
1071
  msgstr ""
1072
 
1073
- #: app/helper/RTMediaAddon.php:443
1074
- msgid ""
1075
- "User must have to check the terms and conditions checkbox before uploading "
1076
- "the media."
1077
- msgstr ""
 
1078
 
1079
- #: app/helper/RTMediaAddon.php:451
1080
- msgid "CubePoints"
1081
  msgstr ""
1082
 
1083
- #: app/helper/RTMediaAddon.php:454
1084
- msgid ""
1085
- "If you are using CubePoints plugin on your website than rtMedia CubePoint "
1086
- "add-on can be integrate with that plugin to setup point management system "
1087
- "for rtMedia related activities."
1088
  msgstr ""
1089
 
1090
- #: app/helper/RTMediaAddon.php:462
1091
- msgid "Social Sync"
 
1092
  msgstr ""
1093
 
1094
- #: app/helper/RTMediaAddon.php:465
1095
- msgid "rtMedia Social Sync allows you to import media from your Facebook account."
1096
  msgstr ""
1097
 
1098
- #: app/helper/RTMediaAddon.php:473
1099
- msgid "Photo Watermark"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  msgstr ""
1101
 
1102
- #: app/helper/RTMediaAddon.php:476
1103
- msgid ""
1104
- "rtMedia Photo Watermark let you add watermark on your images uploaded using "
1105
- "rtMedia."
1106
  msgstr ""
1107
 
1108
- #: app/helper/RTMediaAddon.php:484
1109
- msgid "Photo Tagging"
1110
  msgstr ""
1111
 
1112
- #: app/helper/RTMediaAddon.php:487
1113
  msgid ""
1114
- "rtMedia Photo Tagging enable users to tag their friends on photos uploaded "
1115
- "using rtMedia."
1116
  msgstr ""
1117
 
1118
- #: app/helper/RTMediaAddon.php:495
1119
- msgid "Photo Filters"
 
1120
  msgstr ""
1121
 
1122
- #: app/helper/RTMediaAddon.php:498
1123
- msgid ""
1124
- "rtMedia Photo Filters adds Instagram like filters to images uploaded with "
1125
- "rtMedia."
1126
  msgstr ""
1127
 
1128
- #: app/helper/RTMediaAddon.php:506
1129
- msgid "Kaltura Add-on"
 
1130
  msgstr ""
1131
 
1132
- #: app/helper/RTMediaAddon.php:509
1133
- msgid ""
1134
- "Add support for more video formats using Kaltura video solution. It works "
1135
- "with Kaltura.com, self-hosted Kaltura-CE and Kaltura-on-premise."
1136
  msgstr ""
1137
 
1138
- #: app/helper/RTMediaAddon.php:517
1139
- msgid "FFMPEG Add-on"
1140
  msgstr ""
1141
 
1142
- #: app/helper/RTMediaAddon.php:520
1143
- msgid ""
1144
- "Add supports for more audio & video formats using open-source media-node. "
1145
- "Media node comes with automated setup script for Ubuntu/Debian."
1146
  msgstr ""
1147
 
1148
- #: app/helper/RTMediaAddon.php:528
1149
- msgid "Membership Add-on"
1150
  msgstr ""
1151
 
1152
- #: app/helper/RTMediaAddon.php:531
 
1153
  msgid ""
1154
- "rtMedia Membership add-on provides membership functionality in your site in "
1155
- "terms of media upload."
1156
- msgstr ""
1157
-
1158
- #: app/helper/RTMediaAddon.php:571
1159
- msgid "Coming Soon !!"
1160
  msgstr ""
1161
 
1162
- #: app/helper/RTMediaAddon.php:604
1163
- msgid "Purchased"
 
 
1164
  msgstr ""
1165
 
1166
- #: app/helper/RTMediaAddon.php:606 app/helper/RTMediaThemes.php:155
1167
- #: app/helper/RTMediaThemes.php:183 app/helper/RTMediaThemes.php:280
1168
- #: app/helper/RTMediaThemes.php:308 app/importers/BPMediaAlbumimporter.php:178
1169
- msgid "Buy Now"
1170
  msgstr ""
1171
 
1172
- #: app/helper/RTMediaAddon.php:635 app/helper/RTMediaThemes.php:154
1173
- #: app/helper/RTMediaThemes.php:182 app/helper/RTMediaThemes.php:279
1174
- #: app/helper/RTMediaThemes.php:307 app/importers/BPMediaAlbumimporter.php:179
1175
- msgid "Live Demo"
1176
  msgstr ""
1177
 
1178
- #: app/helper/RTMediaAdminWidget.php:32
1179
- msgid "Argument missing. id is required."
1180
  msgstr ""
1181
 
1182
- #: app/helper/RTMediaCommentNotification.php:60
1183
- msgid "commented on your"
1184
  msgstr ""
1185
 
1186
- #: app/helper/RTMediaCommentNotification.php:62
1187
- msgid "new comments on your"
1188
  msgstr ""
1189
 
1190
- #: app/helper/RTMediaFeed.php:52
1191
- msgid "No items"
1192
  msgstr ""
1193
 
1194
- #: app/helper/RTMediaFeed.php:58
1195
- msgid "Posted "
 
1196
  msgstr ""
1197
 
1198
- #: app/helper/RTMediaLicense.php:56
1199
- msgid "Activated"
1200
  msgstr ""
1201
 
1202
- #: app/helper/RTMediaLicense.php:59
1203
- msgid "Deactivated"
 
1204
  msgstr ""
1205
 
1206
- #: app/helper/RTMediaLicense.php:68
1207
- msgid "Status: "
 
1208
  msgstr ""
1209
 
1210
- #: app/helper/RTMediaLicense.php:77
1211
- msgid "License Key"
 
1212
  msgstr ""
1213
 
1214
- #: app/helper/RTMediaLicense.php:88
1215
- msgid "Activate / Deactivate License"
1216
  msgstr ""
1217
 
1218
- #: app/helper/RTMediaLicense.php:96
1219
- msgid "Deactivate License"
1220
  msgstr ""
1221
 
1222
- #: app/helper/RTMediaLicense.php:99
1223
- msgid "Activate License"
1224
  msgstr ""
1225
 
1226
- #: app/helper/RTMediaLikeNotification.php:91
1227
- msgid "liked your"
 
 
1228
  msgstr ""
1229
 
1230
- #: app/helper/RTMediaLikeNotification.php:93
1231
- msgid "and one more friend liked your"
1232
  msgstr ""
1233
 
1234
- #: app/helper/RTMediaLikeNotification.php:96
1235
- msgid "and"
1236
  msgstr ""
1237
 
1238
- #: app/helper/RTMediaLikeNotification.php:96
1239
- msgid "other friends liked your"
1240
  msgstr ""
1241
 
1242
- #: app/helper/RTMediaSettings.php:206
1243
- msgid "BuddyPress Media Addons for Photos"
 
 
1244
  msgstr ""
1245
 
1246
- #: app/helper/RTMediaSettings.php:210
1247
- msgid "rtMedia Themes"
1248
  msgstr ""
1249
 
1250
- #: app/helper/RTMediaSettings.php:283
1251
  msgid ""
1252
- "Currently your network allows uploading of the following file types. You "
1253
- "can change the settings <a href=\"%s\">here</a>.<br /><code>%s</code></span>"
1254
  msgstr ""
1255
 
1256
- #: app/helper/RTMediaSettings.php:301 app/helper/RTMediaSettings.php:303
1257
- msgid "Recounting of media files done successfully"
 
 
1258
  msgstr ""
1259
 
1260
- #: app/helper/RTMediaSettings.php:303
1261
- msgid "Recount Success"
 
 
1262
  msgstr ""
1263
 
1264
- #: app/helper/RTMediaSettings.php:307 app/helper/RTMediaSettings.php:309
1265
- msgid "Recounting Failed"
 
 
1266
  msgstr ""
1267
 
1268
- #: app/helper/RTMediaSettings.php:309
1269
- msgid "Recount Fail"
 
1270
  msgstr ""
1271
 
1272
- #: app/helper/RTMediaSettings.php:322 app/helper/RTMediaSettings.php:324
1273
- msgid "Atleast one Media Type Must be selected"
1274
  msgstr ""
1275
 
1276
- #: app/helper/RTMediaSettings.php:333 app/helper/RTMediaSettings.php:335
1277
- msgid "\"Number of media\" count value should be numeric and greater than 0."
1278
  msgstr ""
1279
 
1280
- #: app/helper/RTMediaSettings.php:335
1281
- msgid "Default Count"
 
1282
  msgstr ""
1283
 
1284
- #: app/helper/RTMediaSettings.php:340
1285
- msgid "Settings saved."
 
 
1286
  msgstr ""
1287
 
1288
- #: app/helper/RTMediaSettings.php:364
1289
- msgid ""
1290
- "If you make changes to width, height or crop settings, you must use \"<a "
1291
- "href=\"%s\">Regenerate Thumbnail Plugin</a>\" to regenerate old images.\""
1292
  msgstr ""
1293
 
1294
- #: app/helper/RTMediaSettings.php:385
1295
- msgid "BuddyPress Media 2.6 requires a database upgrade. "
1296
  msgstr ""
1297
 
1298
- #: app/helper/RTMediaSettings.php:385
1299
- msgid "Update Database"
1300
  msgstr ""
1301
 
1302
- #: app/helper/RTMediaSettings.php:402
1303
- msgid ""
1304
- "If your site has some issues due to BuddyPress Media and you want one on "
1305
- "one support then you can create a support topic on the <a target=\"_blank\" "
1306
- "href=\"http://community.rtcamp.com/c/rtmedia?utm_source=dashboard&utm_"
1307
- "medium=plugin&utm_campaign=rtmedia\">rtCamp Support Forum</a>."
1308
  msgstr ""
1309
 
1310
- #: app/helper/RTMediaSettings.php:403
1311
- msgid ""
1312
- "If you have any suggestions, enhancements or bug reports, then you can open "
1313
- "a new issue on <a target=\"_blank\" "
1314
- "href=\"https://github.com/rtCamp/rtmedia/issues/new\">GitHub</a>."
1315
  msgstr ""
1316
 
1317
- #: app/helper/RTMediaSupport.php:58 app/helper/RTMediaSupport.php:59
1318
- #: app/helper/RTMediaSupport.php:305 app/helper/RTMediaSupport.php:560
1319
- msgid "Debug Info"
1320
  msgstr ""
1321
 
1322
- #: app/helper/RTMediaSupport.php:66 app/helper/RTMediaSupport.php:67
1323
- #: app/importers/RTMediaMigration.php:83
1324
- msgid "Migration"
1325
  msgstr ""
1326
 
1327
- #: app/helper/RTMediaSupport.php:128
1328
- msgid "Service"
1329
  msgstr ""
1330
 
1331
- #: app/helper/RTMediaSupport.php:135
1332
- msgid "Premium Support"
1333
  msgstr ""
1334
 
1335
- #: app/helper/RTMediaSupport.php:141
1336
- msgid "Bug Report"
1337
  msgstr ""
1338
 
1339
- #: app/helper/RTMediaSupport.php:147
1340
- msgid "New Feature"
 
 
 
 
1341
  msgstr ""
1342
 
1343
- #: app/helper/RTMediaSupport.php:149
1344
- msgid "Submit"
1345
  msgstr ""
1346
 
1347
- #: app/helper/RTMediaSupport.php:195
1348
- msgid "by"
 
 
 
 
1349
  msgstr ""
1350
 
1351
- #: app/helper/RTMediaSupport.php:195
1352
- msgid "version"
 
1353
  msgstr ""
1354
 
1355
- #: app/helper/RTMediaSupport.php:357
1356
- msgid "There is no media found to migrate."
1357
  msgstr ""
1358
 
1359
- #: app/helper/RTMediaSupport.php:363
1360
- #: app/main/controllers/media/RTMediaLoginPopup.php:52
1361
- msgid "Click"
 
1362
  msgstr ""
1363
 
1364
- #: app/helper/RTMediaSupport.php:363
1365
- msgid "here to migrate media from rtMedia 2.x to rtMedia 3.0+."
1366
  msgstr ""
1367
 
1368
- #: app/helper/RTMediaSupport.php:392
1369
- msgid "Submit a Bug Report"
1370
  msgstr ""
1371
 
1372
- #: app/helper/RTMediaSupport.php:395
1373
- msgid "Submit a New Feature Request"
1374
  msgstr ""
1375
 
1376
- #: app/helper/RTMediaSupport.php:398
1377
- msgid "Submit Support Request"
1378
  msgstr ""
1379
 
1380
- #: app/helper/RTMediaSupport.php:405
1381
- msgid ""
1382
- "If your site has some issues due to rtMedia and you want support, feel free "
1383
- "to create a support topic on <a target=\"_blank\" "
1384
- "href=\"http://community.rtcamp.com/c/rtmedia/?utm_source=dashboard&utm_"
1385
- "medium=plugin&utm_campaign=buddypress-media\">Community Forum</a>."
1386
  msgstr ""
1387
 
1388
- #: app/helper/RTMediaSupport.php:406
1389
- msgid ""
1390
- "If you have any suggestions, enhancements or bug reports, you can open a "
1391
- "new issue on <a target=\"_blank\" "
1392
- "href=\"https://github.com/rtCamp/rtMedia/issues/new\">GitHub</a>."
1393
  msgstr ""
1394
 
1395
- #: app/helper/RTMediaSupport.php:415
1396
- msgid "Name"
1397
  msgstr ""
1398
 
1399
- #: app/helper/RTMediaSupport.php:420
1400
- msgid "Use actual user name which used during purchased."
1401
  msgstr ""
1402
 
1403
- #: app/helper/RTMediaSupport.php:426
1404
- msgid "Email"
1405
  msgstr ""
1406
 
1407
- #: app/helper/RTMediaSupport.php:431
1408
- msgid "Use email id which used during purchased"
1409
  msgstr ""
1410
 
1411
- #: app/helper/RTMediaSupport.php:437
1412
- msgid "Website"
1413
  msgstr ""
1414
 
1415
- #: app/helper/RTMediaSupport.php:442
1416
- msgid "Subject"
1417
  msgstr ""
1418
 
1419
- #: app/helper/RTMediaSupport.php:447 templates/media/album-single-edit.php:16
1420
- #: templates/media/media-single-edit.php:16
1421
- msgid "Details"
1422
  msgstr ""
1423
 
1424
- #: app/helper/RTMediaSupport.php:490
1425
- msgid "rtMedia Premium Support Request from"
1426
  msgstr ""
1427
 
1428
- #: app/helper/RTMediaSupport.php:493
1429
- msgid "rtMedia New Feature Request from"
1430
  msgstr ""
1431
 
1432
- #: app/helper/RTMediaSupport.php:496
1433
- msgid "rtMedia Bug Report from"
1434
  msgstr ""
1435
 
1436
- #: app/helper/RTMediaSupport.php:499
1437
- msgid "rtMedia Contact from"
1438
  msgstr ""
1439
 
1440
- #: app/helper/RTMediaSupport.php:577
1441
- msgid "Thank you for your Feedback/Suggestion."
1442
  msgstr ""
1443
 
1444
- #: app/helper/RTMediaSupport.php:579
1445
- msgid "Thank you for posting your support request."
1446
  msgstr ""
1447
 
1448
- #: app/helper/RTMediaSupport.php:580
1449
- msgid "We will get back to you shortly."
 
1450
  msgstr ""
1451
 
1452
- #: app/helper/RTMediaSupport.php:585
1453
- msgid "Your server failed to send an email."
1454
  msgstr ""
1455
 
1456
- #: app/helper/RTMediaSupport.php:586
1457
- msgid "Kindly contact your server support to fix this."
 
1458
  msgstr ""
1459
 
1460
- #: app/helper/RTMediaSupport.php:587
1461
- msgid ""
1462
- "You can alternatively create a support request <a "
1463
- "href=\"https://rtcamp.com/premium-support/\" target=\"_blank\">here</a>"
1464
  msgstr ""
1465
 
1466
- #: app/helper/RTMediaThemes.php:60 app/helper/RTMediaThemes.php:61
1467
- msgid "Themes By rtCamp"
1468
  msgstr ""
1469
 
1470
- #: app/helper/RTMediaThemes.php:67 app/helper/RTMediaThemes.php:68
1471
- msgid "3rd Party Themes"
1472
  msgstr ""
1473
 
1474
- #: app/helper/RTMediaThemes.php:105
1475
- msgid "rtDating"
1476
  msgstr ""
1477
 
1478
- #. Author of the plugin/theme
1479
- msgid "rtCamp"
1480
  msgstr ""
1481
 
1482
- #: app/helper/RTMediaThemes.php:111
1483
- msgid ""
1484
- "rtDating is a unique, clean and modern theme only for WordPress. This theme "
1485
- "is mostly useful for dating sites and community websites. It can also be "
1486
- "use for any other WordPress based website."
1487
  msgstr ""
1488
 
1489
- #: app/helper/RTMediaThemes.php:115
1490
- msgid "InspireBook"
1491
  msgstr ""
1492
 
1493
- #: app/helper/RTMediaThemes.php:121
1494
  msgid ""
1495
- "InspireBook is a premium WordPress theme, designed especially for "
1496
- "BuddyPress and rtMedia powered social-networks."
1497
  msgstr ""
1498
 
1499
- #: app/helper/RTMediaThemes.php:125
1500
- msgid "Foodmania"
1501
  msgstr ""
1502
 
1503
- #: app/helper/RTMediaThemes.php:131
 
1504
  msgid ""
1505
- "Its premium WordPress theme, designed especially for Food, recipe and "
1506
- "photography community sites."
 
 
1507
  msgstr ""
1508
 
1509
- #: app/helper/RTMediaThemes.php:149 app/helper/RTMediaThemes.php:274
1510
- msgid "Theme Details"
1511
  msgstr ""
1512
 
1513
- #: app/helper/RTMediaThemes.php:161 app/helper/RTMediaThemes.php:286
1514
- msgid "Show previous theme"
1515
  msgstr ""
1516
 
1517
- #: app/helper/RTMediaThemes.php:162 app/helper/RTMediaThemes.php:287
1518
- msgid "Show next theme"
1519
  msgstr ""
1520
 
1521
- #: app/helper/RTMediaThemes.php:163 app/helper/RTMediaThemes.php:288
1522
- msgid "Close overlay"
1523
  msgstr ""
1524
 
1525
- #: app/helper/RTMediaThemes.php:176 app/helper/RTMediaThemes.php:301
1526
- msgid "Read More"
1527
  msgstr ""
1528
 
1529
- #: app/helper/RTMediaThemes.php:177 app/helper/RTMediaThemes.php:302
1530
- msgid "Tags:"
1531
  msgstr ""
1532
 
1533
- #: app/helper/RTMediaThemes.php:209
1534
- msgid "Thrive - Intranet & Community WordPress Theme"
 
1535
  msgstr ""
1536
 
1537
- #: app/helper/RTMediaThemes.php:212 app/helper/RTMediaThemes.php:232
1538
- msgid "dunhakdis"
1539
  msgstr ""
1540
 
1541
- #: app/helper/RTMediaThemes.php:215
1542
- msgid ""
1543
- "Thrive is an innovative WordPress Theme designed to cater company portals, "
1544
- "organisational websites, company intranet and extranets."
1545
  msgstr ""
1546
 
1547
- #: app/helper/RTMediaThemes.php:219
1548
- msgid "(M) SOCIAL NETWORK BUDDYPRESS THEME"
1549
  msgstr ""
1550
 
1551
- #: app/helper/RTMediaThemes.php:222
1552
- msgid "gavick"
1553
  msgstr ""
1554
 
1555
- #: app/helper/RTMediaThemes.php:225
1556
- msgid ""
1557
- "(M)Social is a sophisticated, vibrant community theme that offers "
1558
- "incredible grid layouts, with full BuddyPress support so your users can "
1559
- "interact with each other, create their own pages, and share their thoughts "
1560
- "and images with the community."
1561
  msgstr ""
1562
 
1563
- #: app/helper/RTMediaThemes.php:229
1564
- msgid "Klein"
1565
- msgstr ""
1566
-
1567
- #: app/helper/RTMediaThemes.php:235
1568
  msgid ""
1569
- "Klein is an innovative WordPress theme built to support BuddyPress, "
1570
- "bbPress, and WooCommerce out of the box. Perfect for websites that "
1571
- "interacts with many users."
1572
  msgstr ""
1573
 
1574
- #: app/helper/RTMediaThemes.php:239
1575
- msgid "SweetDate"
1576
  msgstr ""
1577
 
1578
- #: app/helper/RTMediaThemes.php:242 app/helper/RTMediaThemes.php:252
1579
- msgid "SeventhQueen"
1580
  msgstr ""
1581
 
1582
- #: app/helper/RTMediaThemes.php:245
1583
- msgid ""
1584
- "SweetDate is a unique, clean and modern Premium Wordpress theme. It is "
1585
- "perfect for a dating or community website but can be used as well for any "
1586
- "other domain. They added all the things you need to create a perfect "
1587
- "community system."
1588
  msgstr ""
1589
 
1590
- #: app/helper/RTMediaThemes.php:249
1591
- msgid "KLEO"
1592
  msgstr ""
1593
 
1594
- #: app/helper/RTMediaThemes.php:255
1595
- msgid ""
1596
- "You no longer need to be a professional developer or designer to create an "
1597
- "awesome website. Let your imagination run wild and create the site of your "
1598
- "dreams. KLEO has all the tools to get you started."
1599
  msgstr ""
1600
 
1601
- #: app/helper/RTMediaThemes.php:318
1602
- msgid ""
1603
- "These are the third party themes. For any issues or queries regarding these "
1604
- "themes please contact theme developers."
1605
  msgstr ""
1606
 
1607
- #: app/helper/RTMediaThemes.php:321
1608
- msgid "Are you a developer?"
1609
  msgstr ""
1610
 
1611
- #: app/helper/RTMediaThemes.php:324
1612
- msgid ""
1613
- "If you have developed a rtMedia compatible theme and would like it to list "
1614
- "here, please email us at"
1615
  msgstr ""
1616
 
1617
- #: app/helper/RTMediaThemes.php:325
1618
- msgid "product@rtcamp.com"
1619
  msgstr ""
1620
 
1621
- #: app/helper/RTMediaUploadException.php:41
1622
- msgid ""
1623
- "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in "
1624
- "the HTML form"
1625
  msgstr ""
1626
 
1627
- #: app/helper/RTMediaUploadException.php:44
1628
- msgid "No file was uploaded"
1629
  msgstr ""
1630
 
1631
- #: app/helper/RTMediaUploadException.php:49
1632
- msgid "Uploade failed due to internal server error."
1633
  msgstr ""
1634
 
1635
- #: app/helper/RTMediaUploadException.php:52
1636
- msgid "File type not allowed."
1637
  msgstr ""
1638
 
1639
- #: app/helper/RTMediaUploadException.php:56
1640
- msgid "Invalid Context for upload."
1641
  msgstr ""
1642
 
1643
- #: app/helper/RTMediaUploadException.php:59
1644
- msgid "Unknown file upload error."
 
1645
  msgstr ""
1646
 
1647
- #: app/helper/rtFormInvalidArgumentsException.php:21
1648
- msgid ""
1649
- "Error on line %s in %s : <b>The method expects an array in arguments for %s "
1650
- "provided.</b>"
1651
  msgstr ""
1652
 
1653
- #: app/importers/BPMediaAlbumimporter.php:71
1654
- msgid "Warning!"
 
1655
  msgstr ""
1656
 
1657
- #: app/importers/BPMediaAlbumimporter.php:71
1658
- msgid ""
1659
- "This import process is irreversible. Although everything is tested, please "
1660
- "take a <a target=\"_blank\" "
1661
- "href=\"http://codex.wordpress.org/WordPress_Backups\">backup of your "
1662
- "database and files</a>, before proceeding. If you don't know your way "
1663
- "around databases and files, consider <a target=\"_blank\" "
1664
- "href=\"%s\">hiring us</a>, or another professional."
1665
  msgstr ""
1666
 
1667
- #: app/importers/BPMediaAlbumimporter.php:72
1668
- msgid ""
1669
- "If you have set \"WP_DEBUG\" in you wp-config.php file, please make sure it "
1670
- "is set to \"false\", so that it doesn't conflict with the import process."
1671
  msgstr ""
1672
 
1673
- #: app/importers/BPMediaAlbumimporter.php:73
1674
- msgid "I have taken a backup of the database and files of this site."
 
1675
  msgstr ""
1676
 
1677
- #: app/importers/BPMediaAlbumimporter.php:75
1678
- msgid "Start Import"
1679
  msgstr ""
1680
 
1681
- #: app/importers/BPMediaAlbumimporter.php:80
1682
- msgid "Users"
1683
  msgstr ""
1684
 
1685
- #: app/importers/BPMediaAlbumimporter.php:90 app/main/RTMedia.php:562
1686
- msgid "Media"
1687
  msgstr ""
1688
 
1689
- #: app/importers/BPMediaAlbumimporter.php:110
1690
- msgid "Comments"
 
 
1691
  msgstr ""
1692
 
1693
- #: app/importers/BPMediaAlbumimporter.php:116
1694
- msgid "Comments: 0/0 (No comments to import)"
1695
  msgstr ""
1696
 
1697
- #: app/importers/BPMediaAlbumimporter.php:123
1698
- msgid "User's Favorites"
1699
  msgstr ""
1700
 
1701
- #: app/importers/BPMediaAlbumimporter.php:132
1702
- msgid "BP-Album is active on your site and will cause problems with the import."
1703
  msgstr ""
1704
 
1705
- #: app/importers/BPMediaAlbumimporter.php:133
1706
- msgid "Click here to deactivate BP-Album and continue importing"
1707
  msgstr ""
1708
 
1709
- #: app/importers/BPMediaAlbumimporter.php:139
1710
- msgid "Some of the media failed to import. The file might be corrupt or deleted."
1711
  msgstr ""
1712
 
1713
- #: app/importers/BPMediaAlbumimporter.php:140
1714
- msgid "The following %d BP Album Media id's could not be imported"
1715
  msgstr ""
1716
 
1717
- #: app/importers/BPMediaAlbumimporter.php:149
1718
- msgid "I just imported bp-album to @rtMediaWP http://rt.cx/rtmedia on %s"
1719
  msgstr ""
1720
 
1721
- #: app/importers/BPMediaAlbumimporter.php:150
1722
- msgid "Congratulations!"
1723
  msgstr ""
1724
 
1725
- #: app/importers/BPMediaAlbumimporter.php:150
1726
- msgid "All media from BP Album has been imported."
1727
  msgstr ""
1728
 
1729
- #: app/importers/BPMediaAlbumimporter.php:151
1730
- msgid "Tweet this"
1731
  msgstr ""
1732
 
1733
- #: app/importers/BPMediaAlbumimporter.php:155
 
1734
  msgid ""
1735
- "However, a lot of unnecessary files and a database table are still eating "
1736
- "up your resources. If everything seems fine, you can clean this data up."
 
1737
  msgstr ""
1738
 
1739
- #: app/importers/BPMediaAlbumimporter.php:158
1740
- msgid "Clean up Now"
1741
  msgstr ""
1742
 
1743
- #: app/importers/BPMediaAlbumimporter.php:161
1744
- msgid "Clean up Later"
1745
  msgstr ""
1746
 
1747
- #: app/importers/BPMediaAlbumimporter.php:166
1748
- msgid "Why don't you try adding some instagram like effects to your images?"
1749
  msgstr ""
1750
 
1751
- #: app/importers/BPMediaAlbumimporter.php:173
1752
- msgid ""
1753
- "BuddyPress Media Instagram adds Instagram like filters to images uploaded "
1754
- "with BuddyPress Media."
1755
  msgstr ""
1756
 
1757
- #: app/importers/BPMediaAlbumimporter.php:174
1758
- msgid "Important"
1759
  msgstr ""
1760
 
1761
- #: app/importers/BPMediaAlbumimporter.php:174
1762
- msgid ""
1763
- "You need to have ImageMagick installed on your server for this addon to "
1764
- "work."
1765
  msgstr ""
1766
 
1767
- #: app/importers/BPMediaAlbumimporter.php:184
1768
- msgid ""
1769
- "Looks like you don't use BP Album. Is there any other BuddyPress Plugin you "
1770
- "want an importer for?"
1771
  msgstr ""
1772
 
1773
- #: app/importers/BPMediaAlbumimporter.php:185
1774
- msgid "<a href=\"%s\">Create an issue</a> on GitHub requesting the same."
1775
  msgstr ""
1776
 
1777
- #: app/importers/RTMediaActivityUpgrade.php:20
1778
- msgid "Media activity upgrade"
1779
  msgstr ""
1780
 
1781
- #: app/importers/RTMediaMediaSizeImporter.php:25
1782
- msgid "Media Size Import"
1783
  msgstr ""
1784
 
1785
- #: app/importers/RTMediaMigration.php:64
1786
- msgid "Please Migrate your Database"
1787
  msgstr ""
1788
 
1789
- #: app/importers/RTMediaMigration.php:64
1790
- msgid "Click Here"
1791
  msgstr ""
1792
 
1793
- #: app/importers/RTMediaMigration.php:375
1794
- msgid ""
1795
- "Please Backup your <strong>DATABASE</strong> and <strong>UPLOAD</strong> "
1796
- "folder before Migration."
1797
  msgstr ""
1798
 
1799
- #: app/importers/RTMediaMigration.php:383
1800
- msgid "rtMedia Migration"
1801
  msgstr ""
1802
 
1803
- #: app/importers/RTMediaMigration.php:385
1804
- msgid "It will migrate following things"
1805
  msgstr ""
1806
 
1807
- #: app/importers/RTMediaMigration.php:453
1808
- msgid "Error During Migration, Please Refresh Page then try again"
1809
  msgstr ""
1810
 
1811
- #: app/importers/RTMediaMigration.php:473
1812
- msgid "Start"
 
1813
  msgstr ""
1814
 
1815
- #: app/importers/RTMediaMigration.php:1024
1816
- msgid " day"
1817
  msgstr ""
1818
 
1819
- #: app/importers/RTMediaMigration.php:1028
1820
- msgid " hour"
1821
  msgstr ""
1822
 
1823
- #: app/importers/RTMediaMigration.php:1032
1824
- msgid " minute"
1825
  msgstr ""
1826
 
1827
- #: app/importers/RTMediaMigration.php:1036
1828
- msgid " second"
1829
  msgstr ""
1830
 
1831
- #: app/importers/RTMediaMigration.php:1042
1832
- msgid "No time remaining."
1833
  msgstr ""
1834
 
1835
- #: app/main/RTMedia.php:302
1836
- msgid "Photo"
1837
  msgstr ""
1838
 
1839
- #: app/main/RTMedia.php:303
1840
- msgid "Photos"
1841
  msgstr ""
1842
 
1843
- #: app/main/RTMedia.php:311
1844
- msgid "Video"
1845
  msgstr ""
1846
 
1847
- #: app/main/RTMedia.php:312
1848
- msgid "Videos"
1849
  msgstr ""
1850
 
1851
- #: app/main/RTMedia.php:320 app/main/RTMedia.php:321
1852
- msgid "Music"
1853
  msgstr ""
1854
 
1855
- #: app/main/RTMedia.php:408
1856
- msgid "Private - Visible only to the user"
1857
  msgstr ""
1858
 
1859
- #: app/main/RTMedia.php:409
1860
- msgid "Friends - Visible to user's friends"
 
 
 
 
1861
  msgstr ""
1862
 
1863
- #: app/main/RTMedia.php:410
1864
- msgid "Logged in Users - Visible to registered users"
 
1865
  msgstr ""
1866
 
1867
- #: app/main/RTMedia.php:411
1868
- msgid "Public - Visible to the world"
 
1869
  msgstr ""
1870
 
1871
- #: app/main/RTMedia.php:568 app/main/controllers/template/RTMediaNav.php:177
1872
- #: app/main/controllers/template/rt-template-functions.php:83
1873
- msgid "All"
 
 
 
1874
  msgstr ""
1875
 
1876
- #: app/main/RTMedia.php:577 app/main/controllers/media/RTMediaAlbum.php:49
1877
- #: app/main/controllers/template/rt-template-functions.php:1391
1878
- #: app/main/controllers/upload/RTMediaUploadView.php:51
1879
- #: app/main/controllers/upload/RTMediaUploadView.php:54
1880
- msgid "Album"
 
1881
  msgstr ""
1882
 
1883
- #: app/main/RTMedia.php:580 app/main/controllers/media/RTMediaAlbum.php:48
1884
- #: app/main/controllers/media/RTMediaAlbum.php:60
1885
- msgid "Albums"
1886
  msgstr ""
1887
 
1888
- #: app/main/RTMedia.php:588 app/main/controllers/media/RTMediaLoginPopup.php:38
1889
- #: app/main/controllers/template/rt-template-functions.php:2160
1890
- #: app/main/controllers/template/rt-template-functions.php:2164
1891
- msgid "Upload"
1892
  msgstr ""
1893
 
1894
- #: app/main/RTMedia.php:592
1895
- msgid "Wall Post"
1896
  msgstr ""
1897
 
1898
- #: app/main/RTMedia.php:805 app/main/RTMedia.php:814
1899
- msgid "Wall Posts"
 
 
1900
  msgstr ""
1901
 
1902
- #: app/main/RTMedia.php:857
1903
- msgid ": Can't Create Database table. Please check create table permission."
 
1904
  msgstr ""
1905
 
1906
- #: app/main/RTMedia.php:901
1907
- msgid "Loading media"
1908
  msgstr ""
1909
 
1910
- #: app/main/RTMedia.php:902
1911
- msgid "Please enter some content to post."
 
1912
  msgstr ""
1913
 
1914
- #: app/main/RTMedia.php:903
1915
- msgid "Empty Comment is not allowed."
1916
  msgstr ""
1917
 
1918
- #: app/main/RTMedia.php:904
1919
- msgid "Are you sure you want to delete this media?"
1920
  msgstr ""
1921
 
1922
- #: app/main/RTMedia.php:905
1923
- msgid "Are you sure you want to delete this comment?"
 
 
1924
  msgstr ""
1925
 
1926
- #: app/main/RTMedia.php:906
1927
- msgid "Are you sure you want to delete this Album?"
1928
  msgstr ""
1929
 
1930
- #: app/main/RTMedia.php:907
1931
- msgid "Drop files here"
1932
  msgstr ""
1933
 
1934
- #: app/main/RTMedia.php:908
1935
- msgid "album created successfully."
1936
  msgstr ""
1937
 
1938
- #: app/main/RTMedia.php:909
1939
- msgid "Something went wrong. Please try again."
1940
  msgstr ""
1941
 
1942
- #: app/main/RTMedia.php:910
1943
- msgid "Enter an album name."
1944
  msgstr ""
1945
 
1946
- #: app/main/RTMedia.php:911
1947
- msgid "Max file Size Limit : "
1948
  msgstr ""
1949
 
1950
- #: app/main/RTMedia.php:912
1951
- msgid "Allowed File Formats"
1952
  msgstr ""
1953
 
1954
- #: app/main/RTMedia.php:913 templates/media/album-single-edit.php:62
1955
- msgid "Select All Visible"
1956
  msgstr ""
1957
 
1958
- #: app/main/RTMedia.php:914
1959
- msgid "Unselect All Visible"
1960
  msgstr ""
1961
 
1962
- #: app/main/RTMedia.php:915
1963
- msgid "Please select some media."
1964
  msgstr ""
1965
 
1966
- #: app/main/RTMedia.php:916
1967
- msgid "Are you sure you want to delete the selected media?"
1968
  msgstr ""
1969
 
1970
- #: app/main/RTMedia.php:917
1971
- msgid "Are you sure you want to move the selected media?"
1972
  msgstr ""
1973
 
1974
- #: app/main/RTMedia.php:918
1975
- msgid "Waiting"
1976
  msgstr ""
1977
 
1978
- #: app/main/RTMedia.php:919
1979
- msgid "Uploaded"
 
 
1980
  msgstr ""
1981
 
1982
- #: app/main/RTMedia.php:920
1983
- msgid "Uploading"
1984
  msgstr ""
1985
 
1986
- #: app/main/RTMedia.php:921
1987
- msgid "Failed"
1988
  msgstr ""
1989
 
1990
- #: app/main/RTMedia.php:922
1991
- msgid "Close"
1992
  msgstr ""
1993
 
1994
- #: app/main/RTMedia.php:923
1995
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:61
1996
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
1997
- #: app/main/controllers/template/rt-template-functions.php:733
1998
- #: app/main/controllers/template/rt-template-functions.php:754
1999
- msgid "Edit"
2000
  msgstr ""
2001
 
2002
- #: app/main/RTMedia.php:924
2003
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:64
2004
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
2005
- #: app/main/controllers/template/rt-template-functions.php:1471
2006
- #: app/main/controllers/template/rt-template-functions.php:1478
2007
- #: templates/media/album-single-edit.php:65
2008
- msgid "Delete"
2009
  msgstr ""
2010
 
2011
- #: app/main/RTMedia.php:925 templates/media/media-single-edit.php:8
2012
- msgid "Edit Media"
2013
  msgstr ""
2014
 
2015
- #: app/main/RTMedia.php:926
2016
- msgid "Remove from queue"
2017
  msgstr ""
2018
 
2019
- #: app/main/RTMedia.php:927
2020
- msgid "Add more files"
 
 
 
2021
  msgstr ""
2022
 
2023
- #: app/main/RTMedia.php:928
2024
- msgid "File not supported"
2025
  msgstr ""
2026
 
2027
- #: app/main/RTMedia.php:929
2028
- msgid "more"
 
 
2029
  msgstr ""
2030
 
2031
- #: app/main/RTMedia.php:930
2032
- msgid "less"
2033
  msgstr ""
2034
 
2035
- #: app/main/RTMedia.php:931
2036
- msgid "This media is uploaded. Are you sure you want to delete this media?"
2037
  msgstr ""
2038
 
2039
- #: app/main/RTMedia.php:939
2040
- msgid "Featured media set successfully."
2041
  msgstr ""
2042
 
2043
- #: app/main/RTMedia.php:940
2044
- msgid "Featured media removed successfully."
 
 
2045
  msgstr ""
2046
 
2047
- #: app/main/RTMedia.php:977
2048
- msgid "There are some uploads in progress. Do you want to cancel them?"
2049
  msgstr ""
2050
 
2051
- #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:240
2052
- msgid "Media Files"
2053
  msgstr ""
2054
 
2055
- #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:264
2056
- #: app/main/controllers/shortcodes/RTMediaUploadShortcode.php:103
2057
- #: app/main/controllers/template/rt-template-functions.php:1505
2058
- msgid "You are not allowed to upload/attach media."
2059
  msgstr ""
2060
 
2061
- #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:400
2062
- msgid "%s added a %s"
2063
  msgstr ""
2064
 
2065
- #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:406
2066
- #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:408
2067
- #: app/main/controllers/upload/RTMediaUploadEndpoint.php:105
2068
- msgid "%s added %d %s"
2069
  msgstr ""
2070
 
2071
- #: app/main/controllers/api/RTMediaJsonApi.php:166
2072
- msgid "username/password empty"
2073
- msgstr ""
2074
 
2075
- #: app/main/controllers/api/RTMediaJsonApi.php:169
2076
- msgid "incorrect username"
2077
  msgstr ""
2078
 
2079
- #: app/main/controllers/api/RTMediaJsonApi.php:172
2080
- msgid "incorrect password"
2081
  msgstr ""
2082
 
2083
- #: app/main/controllers/api/RTMediaJsonApi.php:175
2084
- msgid "login success"
2085
  msgstr ""
2086
 
2087
- #: app/main/controllers/api/RTMediaJsonApi.php:221
2088
- msgid "fields empty"
2089
  msgstr ""
2090
 
2091
- #: app/main/controllers/api/RTMediaJsonApi.php:224
2092
- msgid "invalid email"
2093
  msgstr ""
2094
 
2095
- #: app/main/controllers/api/RTMediaJsonApi.php:227
2096
- msgid "password do not match"
2097
  msgstr ""
2098
 
2099
- #: app/main/controllers/api/RTMediaJsonApi.php:230
2100
- msgid "username already registered"
2101
  msgstr ""
2102
 
2103
- #: app/main/controllers/api/RTMediaJsonApi.php:233
2104
- msgid "email already exists"
2105
  msgstr ""
2106
 
2107
- #: app/main/controllers/api/RTMediaJsonApi.php:236
2108
- msgid "new user created"
2109
  msgstr ""
2110
 
2111
- #: app/main/controllers/api/RTMediaJsonApi.php:297
2112
- msgid "email empty"
2113
  msgstr ""
2114
 
2115
- #: app/main/controllers/api/RTMediaJsonApi.php:300
2116
- msgid "username/email not registered"
2117
  msgstr ""
2118
 
2119
- #: app/main/controllers/api/RTMediaJsonApi.php:303
2120
- msgid "reset link sent"
2121
  msgstr ""
2122
 
2123
- #: app/main/controllers/api/RTMediaJsonApi.php:335
2124
- msgid "Someone has asked to reset the password for the following site and username."
2125
  msgstr ""
2126
 
2127
- #: app/main/controllers/api/RTMediaJsonApi.php:337
2128
- msgid "Username: %s"
2129
  msgstr ""
2130
 
2131
- #: app/main/controllers/api/RTMediaJsonApi.php:338
2132
- msgid ""
2133
- "To reset your password visit the following address, otherwise just ignore "
2134
- "this email and nothing will happen."
2135
  msgstr ""
2136
 
2137
- #: app/main/controllers/api/RTMediaJsonApi.php:341
2138
- msgid "[%s] Password Reset"
2139
  msgstr ""
2140
 
2141
- #: app/main/controllers/api/RTMediaJsonApi.php:356
2142
- msgid "bp activities"
2143
  msgstr ""
2144
 
2145
- #: app/main/controllers/api/RTMediaJsonApi.php:359
2146
- msgid "user activities"
2147
  msgstr ""
2148
 
2149
- #: app/main/controllers/api/RTMediaJsonApi.php:389
2150
- msgid "comment content missing"
 
 
2151
  msgstr ""
2152
 
2153
- #: app/main/controllers/api/RTMediaJsonApi.php:392
2154
- msgid "comment posted"
2155
  msgstr ""
2156
 
2157
- #: app/main/controllers/api/RTMediaJsonApi.php:439
2158
- msgid "unliked media"
2159
  msgstr ""
2160
 
2161
- #: app/main/controllers/api/RTMediaJsonApi.php:442
2162
- msgid "liked media"
 
2163
  msgstr ""
2164
 
2165
- #: app/main/controllers/api/RTMediaJsonApi.php:526
2166
- msgid "no comments"
2167
  msgstr ""
2168
 
2169
- #: app/main/controllers/api/RTMediaJsonApi.php:529
2170
- msgid "media comments"
2171
  msgstr ""
2172
 
2173
- #: app/main/controllers/api/RTMediaJsonApi.php:532
2174
- msgid "my comments"
2175
  msgstr ""
2176
 
2177
- #: app/main/controllers/api/RTMediaJsonApi.php:582
2178
- msgid "no likes"
 
 
2179
  msgstr ""
2180
 
2181
- #: app/main/controllers/api/RTMediaJsonApi.php:585
2182
- msgid "media likes"
2183
  msgstr ""
2184
 
2185
- #: app/main/controllers/api/RTMediaJsonApi.php:627
2186
- msgid "invalid comment/media id"
2187
  msgstr ""
2188
 
2189
- #: app/main/controllers/api/RTMediaJsonApi.php:630
2190
- msgid "no comment id"
2191
  msgstr ""
2192
 
2193
- #: app/main/controllers/api/RTMediaJsonApi.php:633
2194
- msgid "comment deleted"
2195
  msgstr ""
2196
 
2197
- #: app/main/controllers/api/RTMediaJsonApi.php:676
2198
- msgid "no profile found"
2199
  msgstr ""
2200
 
2201
- #: app/main/controllers/api/RTMediaJsonApi.php:679
2202
- msgid "profile fields"
2203
  msgstr ""
2204
 
2205
- #: app/main/controllers/api/RTMediaJsonApi.php:773
2206
- msgid "follow user id missing"
2207
  msgstr ""
2208
 
2209
- #: app/main/controllers/api/RTMediaJsonApi.php:776
2210
- msgid "started following"
 
 
2211
  msgstr ""
2212
 
2213
- #: app/main/controllers/api/RTMediaJsonApi.php:779
2214
- msgid "already following"
2215
  msgstr ""
2216
 
2217
- #: app/main/controllers/api/RTMediaJsonApi.php:811
2218
- msgid "unfollow id missing"
2219
  msgstr ""
2220
 
2221
- #: app/main/controllers/api/RTMediaJsonApi.php:814
2222
- msgid "stopped following"
2223
  msgstr ""
2224
 
2225
- #: app/main/controllers/api/RTMediaJsonApi.php:817
2226
- msgid "not following"
2227
  msgstr ""
2228
 
2229
- #: app/main/controllers/api/RTMediaJsonApi.php:849
2230
- msgid "name/location empty"
2231
  msgstr ""
2232
 
2233
- #: app/main/controllers/api/RTMediaJsonApi.php:852
2234
- msgid "profile updated"
2235
  msgstr ""
2236
 
2237
- #: app/main/controllers/api/RTMediaJsonApi.php:878
2238
- #: app/main/controllers/api/RTMediaJsonApi.php:905
2239
- msgid "no file"
2240
  msgstr ""
2241
 
2242
- #: app/main/controllers/api/RTMediaJsonApi.php:881
2243
- #: app/main/controllers/api/RTMediaJsonApi.php:917
2244
- msgid "upload failed, check size and file type"
2245
  msgstr ""
2246
 
2247
- #: app/main/controllers/api/RTMediaJsonApi.php:884
2248
- msgid "avatar updated"
 
 
 
 
2249
  msgstr ""
2250
 
2251
- #: app/main/controllers/api/RTMediaJsonApi.php:908
2252
- msgid "invalid file string"
2253
  msgstr ""
2254
 
2255
- #: app/main/controllers/api/RTMediaJsonApi.php:911
2256
- msgid "image type missing"
 
2257
  msgstr ""
2258
 
2259
- #: app/main/controllers/api/RTMediaJsonApi.php:914
2260
- msgid "no title"
2261
  msgstr ""
2262
 
2263
- #: app/main/controllers/api/RTMediaJsonApi.php:920
2264
- msgid "media updated"
2265
  msgstr ""
2266
 
2267
- #: app/main/controllers/api/RTMediaJsonApi.php:1050
2268
- msgid "media list"
2269
  msgstr ""
2270
 
2271
- #: app/main/controllers/api/RTMediaJsonApi.php:1053
2272
- msgid "no media found for requested media type"
 
2273
  msgstr ""
2274
 
2275
- #: app/main/controllers/api/RTMediaJsonApi.php:1056
2276
- msgid "media_type not allowed"
2277
  msgstr ""
2278
 
2279
- #: app/main/controllers/api/RTMediaJsonApi.php:1146
2280
- msgid "single media"
 
 
2281
  msgstr ""
2282
 
2283
- #: app/main/controllers/group/RTMediaGroupExtension.php:30
2284
- #: app/main/controllers/group/RTMediaGroupExtension.php:92
2285
- msgid "Album Creation Control"
2286
  msgstr ""
2287
 
2288
- #: app/main/controllers/group/RTMediaGroupExtension.php:31
2289
- #: app/main/controllers/group/RTMediaGroupExtension.php:93
2290
- msgid "Who can create Albums in this group?"
2291
  msgstr ""
2292
 
2293
- #: app/main/controllers/group/RTMediaGroupExtension.php:35
2294
- #: app/main/controllers/group/RTMediaGroupExtension.php:97
2295
- msgid "All Group Members"
2296
  msgstr ""
2297
 
2298
- #: app/main/controllers/group/RTMediaGroupExtension.php:39
2299
- #: app/main/controllers/group/RTMediaGroupExtension.php:101
2300
- msgid "Group Admins and Mods only"
2301
  msgstr ""
2302
 
2303
- #: app/main/controllers/group/RTMediaGroupExtension.php:43
2304
- #: app/main/controllers/group/RTMediaGroupExtension.php:105
2305
- msgid "Group Admin only"
2306
  msgstr ""
2307
 
2308
- #: app/main/controllers/group/RTMediaGroupExtension.php:113
2309
- #: app/main/controllers/privacy/RTMediaPrivacy.php:303
2310
- #: templates/media/album-single-edit.php:47
2311
- msgid "Save Changes"
2312
  msgstr ""
2313
 
2314
- #: app/main/controllers/group/RTMediaGroupExtension.php:142
2315
- msgid "There was an error saving, please try again"
2316
  msgstr ""
2317
 
2318
- #: app/main/controllers/group/RTMediaGroupExtension.php:144
2319
- msgid "Settings saved successfully"
2320
  msgstr ""
2321
 
2322
- #: app/main/controllers/group/RTMediaGroupExtension.php:164
2323
- msgid ""
2324
- "You could display a small snippet of information from your group extension "
2325
- "here. It will show on the group\n"
2326
- "\t home screen."
2327
  msgstr ""
2328
 
2329
- #: app/main/controllers/media/RTMediaAlbum.php:35
2330
- msgid "Hidden (%s)"
2331
- msgid_plural "Hidden (%s)"
2332
- msgstr[0] ""
2333
- msgstr[1] ""
2334
 
2335
- #: app/main/controllers/media/RTMediaAlbum.php:50
2336
- msgid "Create"
 
 
 
 
2337
  msgstr ""
2338
 
2339
- #: app/main/controllers/media/RTMediaAlbum.php:51
2340
- #: app/main/controllers/template/rt-template-functions.php:1786
2341
- msgid "Create Album"
 
2342
  msgstr ""
2343
 
2344
- #: app/main/controllers/media/RTMediaAlbum.php:52
2345
- #: app/main/controllers/template/rt-template-functions.php:1866
2346
- msgid "Edit Album"
 
 
2347
  msgstr ""
2348
 
2349
- #: app/main/controllers/media/RTMediaAlbum.php:53
2350
- msgid "New Album"
2351
  msgstr ""
2352
 
2353
- #: app/main/controllers/media/RTMediaAlbum.php:54
2354
- msgid "All Albums"
2355
  msgstr ""
2356
 
2357
- #: app/main/controllers/media/RTMediaAlbum.php:55
2358
- msgid "View Album"
2359
  msgstr ""
2360
 
2361
- #: app/main/controllers/media/RTMediaAlbum.php:56
2362
- msgid "Search Albums"
2363
  msgstr ""
2364
 
2365
- #: app/main/controllers/media/RTMediaAlbum.php:57
2366
- msgid "No album found"
2367
  msgstr ""
2368
 
2369
- #: app/main/controllers/media/RTMediaAlbum.php:58
2370
- msgid "No album found in Trash"
2371
  msgstr ""
2372
 
2373
- #: app/main/controllers/media/RTMediaAlbum.php:59
2374
- msgid "Parent"
2375
  msgstr ""
2376
 
2377
- #: app/main/controllers/media/RTMediaAlbum.php:145
2378
- msgid "Untitled Album"
2379
  msgstr ""
2380
 
2381
- #: app/main/controllers/media/RTMediaFeatured.php:25
2382
- #: app/main/controllers/media/RTMediaGroupFeatured.php:17
2383
- msgid "Set as Featured"
2384
  msgstr ""
2385
 
2386
- #: app/main/controllers/media/RTMediaFeatured.php:27
2387
- #: app/main/controllers/media/RTMediaGroupFeatured.php:19
2388
- msgid "Unset Featured"
2389
  msgstr ""
2390
 
2391
- #: app/main/controllers/media/RTMediaFeatured.php:191
2392
- #: app/main/controllers/media/RTMediaGroupFeatured.php:194
2393
- msgid "Media type is not allowed"
2394
  msgstr ""
2395
 
2396
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:60
2397
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
2398
- msgid "Edit this media"
2399
  msgstr ""
2400
 
2401
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:63
2402
- #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
2403
- msgid "Delete this media"
2404
  msgstr ""
2405
 
2406
- #: app/main/controllers/media/RTMediaLike.php:18
2407
- msgid "Like"
2408
  msgstr ""
2409
 
2410
- #: app/main/controllers/media/RTMediaLike.php:20
2411
- msgid "Unlike"
2412
  msgstr ""
2413
 
2414
- #: app/main/controllers/media/RTMediaLoginPopup.php:38
2415
- #: app/main/controllers/template/rt-template-functions.php:2160
2416
- #: app/main/controllers/template/rt-template-functions.php:2164
2417
- msgid "Upload Media"
2418
  msgstr ""
2419
 
2420
- #: app/main/controllers/media/RTMediaLoginPopup.php:47
2421
- msgid "Please login"
2422
  msgstr ""
2423
 
2424
- #: app/main/controllers/media/RTMediaLoginPopup.php:49
2425
- msgid "You need to be logged in to upload Media or to create Album."
2426
  msgstr ""
2427
 
2428
- #: app/main/controllers/media/RTMediaLoginPopup.php:52
2429
- msgid "Login"
2430
  msgstr ""
2431
 
2432
- #: app/main/controllers/media/RTMediaLoginPopup.php:52
2433
- msgid "HERE"
2434
  msgstr ""
2435
 
2436
- #: app/main/controllers/media/RTMediaLoginPopup.php:52
2437
- msgid " to login."
2438
  msgstr ""
2439
 
2440
- #: app/main/controllers/media/RTMediaMedia.php:487
2441
- msgid "Error creating attachment for the media file, please try again"
2442
  msgstr ""
2443
 
2444
- #: app/main/controllers/media/RTMediaMedia.php:589
2445
- msgid "%1$s added a %2$s"
2446
  msgstr ""
2447
 
2448
- #: app/main/controllers/media/RTMediaMedia.php:589
2449
- msgid "%1$s added %4$d %3$s"
2450
  msgstr ""
2451
 
2452
- #: app/main/controllers/privacy/RTMediaPrivacy.php:268
2453
- msgid "No changes were made to your account."
2454
  msgstr ""
2455
 
2456
- #: app/main/controllers/privacy/RTMediaPrivacy.php:271
2457
- msgid "Your default privacy settings saved successfully."
 
 
 
 
2458
  msgstr ""
2459
 
2460
- #: app/main/controllers/privacy/RTMediaPrivacy.php:294
2461
- msgid "Default Privacy"
 
 
 
 
 
2462
  msgstr ""
2463
 
2464
- #: app/main/controllers/shortcodes/RTMediaGalleryShortcode.php:182
2465
- msgid "You do not have sufficient privileges to view this gallery"
2466
  msgstr ""
2467
 
2468
- #: app/main/controllers/shortcodes/RTMediaUploadShortcode.php:91
2469
- msgid "The web browser on your device cannot be used to upload files."
2470
  msgstr ""
2471
 
2472
- #: app/main/controllers/template/RTMediaAJAX.php:33
2473
- msgid "You can not create album in this group."
2474
  msgstr ""
2475
 
2476
- #: app/main/controllers/template/RTMediaAJAX.php:39
2477
- msgid "You can not create album."
2478
  msgstr ""
2479
 
2480
- #: app/main/controllers/template/RTMediaAJAX.php:44
2481
- msgid "You can not create more albums, you exceed your album limit."
2482
  msgstr ""
2483
 
2484
- #: app/main/controllers/template/RTMediaAJAX.php:89
2485
- msgid "Data mismatch, Please insert data properly."
2486
  msgstr ""
2487
 
2488
- #: app/main/controllers/template/RTMediaTemplate.php:97
2489
- #: app/main/controllers/template/RTMediaTemplate.php:149
2490
- msgid "Invalid attribute passed for rtmedia_gallery shortcode."
2491
  msgstr ""
2492
 
2493
- #: app/main/controllers/template/RTMediaTemplate.php:329
2494
- #: app/main/controllers/template/RTMediaTemplate.php:403
2495
- #: app/main/controllers/template/RTMediaTemplate.php:492
2496
- #: app/main/controllers/template/RTMediaTemplate.php:618
2497
- msgid "Ooops !!! Invalid access. No nonce was found !!"
2498
  msgstr ""
2499
 
2500
- #: app/main/controllers/template/RTMediaTemplate.php:336
2501
- msgid "Media updated Sucessfully"
2502
  msgstr ""
2503
 
2504
- #: app/main/controllers/template/RTMediaTemplate.php:342
2505
- msgid "Error in updating Media"
2506
  msgstr ""
2507
 
2508
- #: app/main/controllers/template/rt-template-functions.php:709
2509
- #: app/main/controllers/template/rt-template-functions.php:1697
2510
- msgid "Options"
2511
  msgstr ""
2512
 
2513
- #: app/main/controllers/template/rt-template-functions.php:798
2514
- msgid "There are no comments on this media yet."
2515
  msgstr ""
2516
 
2517
- #: app/main/controllers/template/rt-template-functions.php:834
2518
- msgid "Delete Comment"
 
 
2519
  msgstr ""
2520
 
2521
- #: app/main/controllers/template/rt-template-functions.php:1032
2522
- msgid "Go to page no : "
 
2523
  msgstr ""
2524
 
2525
- #: app/main/controllers/template/rt-template-functions.php:1037
2526
- msgid "Go"
 
 
 
2527
  msgstr ""
2528
 
2529
- #: app/main/controllers/template/rt-template-functions.php:1210
2530
- msgid "Video Thumbnail"
 
2531
  msgstr ""
2532
 
2533
- #: app/main/controllers/template/rt-template-functions.php:1259
2534
- msgid "Video Thumbnail:"
 
2535
  msgstr ""
2536
 
2537
- #: app/main/controllers/template/rt-template-functions.php:1342
2538
- msgid "Image"
 
2539
  msgstr ""
2540
 
2541
- #: app/main/controllers/template/rt-template-functions.php:1359
2542
- msgid "Modify Image"
 
2543
  msgstr ""
2544
 
2545
- #: app/main/controllers/template/rt-template-functions.php:1434
2546
- msgid "Type Comment..."
 
2547
  msgstr ""
2548
 
2549
- #: app/main/controllers/template/rt-template-functions.php:1435
2550
- #: templates/media/media-single.php:82 templates/media/media-single.php:122
2551
- msgid "Comment"
2552
  msgstr ""
2553
 
2554
- #: app/main/controllers/template/rt-template-functions.php:1471
2555
- #: app/main/controllers/template/rt-template-functions.php:1478
2556
- msgid "Delete Media"
2557
  msgstr ""
2558
 
2559
- #: app/main/controllers/template/rt-template-functions.php:1639
2560
- msgid "Profile Albums"
2561
  msgstr ""
2562
 
2563
- #: app/main/controllers/template/rt-template-functions.php:1642
2564
- #: app/main/controllers/template/rt-template-functions.php:1676
2565
- msgid "Group Albums"
2566
  msgstr ""
2567
 
2568
- #: app/main/controllers/template/rt-template-functions.php:1760
2569
- msgid "Create New Album"
 
 
2570
  msgstr ""
2571
 
2572
- #: app/main/controllers/template/rt-template-functions.php:1760
2573
- msgid "Add Album"
2574
  msgstr ""
2575
 
2576
- #: app/main/controllers/template/rt-template-functions.php:1776
2577
- msgid "Create an Album"
2578
  msgstr ""
2579
 
2580
- #: app/main/controllers/template/rt-template-functions.php:1778
2581
- msgid "Album Title : "
 
2582
  msgstr ""
2583
 
2584
- #: app/main/controllers/template/rt-template-functions.php:1817
2585
- #: app/main/controllers/template/rt-template-functions.php:1824
2586
- #: app/main/controllers/template/rt-template-functions.php:1876
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2587
  msgid "Merge Album"
2588
  msgstr ""
2589
 
@@ -2591,6 +2984,11 @@ msgstr ""
2591
  msgid "Select Album to merge with : "
2592
  msgstr ""
2593
 
 
 
 
 
 
2594
  #: app/main/controllers/template/rt-template-functions.php:1867
2595
  msgid "Delete Album"
2596
  msgstr ""
@@ -2607,6 +3005,12 @@ msgstr ""
2607
  msgid "people like this"
2608
  msgstr ""
2609
 
 
 
 
 
 
 
2610
  #: app/main/controllers/template/rt-template-functions.php:2247
2611
  msgid "Empowering your community with "
2612
  msgstr ""
@@ -2640,29 +3044,32 @@ msgid "Blocked temporarily"
2640
  msgstr ""
2641
 
2642
  #: app/main/controllers/template/rt-template-functions.php:2331
 
2643
  msgid "%s ago "
2644
  msgstr ""
2645
 
2646
  #: app/main/controllers/template/rt-template-functions.php:2344
 
2647
  msgid "1 second"
2648
  msgid_plural "%s seconds"
2649
  msgstr[0] ""
2650
  msgstr[1] ""
2651
 
2652
  #: app/main/controllers/template/rt-template-functions.php:2347
 
2653
  msgid "1 minute"
2654
  msgid_plural "%s minutes"
2655
  msgstr[0] ""
2656
  msgstr[1] ""
2657
 
2658
  #: app/main/controllers/template/rt-template-functions.php:2350
 
2659
  msgid "1 hour"
2660
  msgid_plural "%s hours"
2661
  msgstr[0] ""
2662
  msgstr[1] ""
2663
 
2664
  #: app/main/controllers/template/rt-template-functions.php:2705
2665
- #. translators: date format, see http:php.net/date
2666
  msgid "You can consider rtMedia Team for following :"
2667
  msgstr ""
2668
 
@@ -2678,8 +3085,45 @@ msgstr ""
2678
  msgid "WordPress/BuddyPress Plugin Development"
2679
  msgstr ""
2680
 
2681
- #: app/main/controllers/template/rt-template-functions.php:2714
2682
- msgid "Contact Us"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2683
  msgstr ""
2684
 
2685
  #: app/main/controllers/upload/RTMediaUploadView.php:70
@@ -2746,235 +3190,1242 @@ msgid ""
2746
  "Supported audio format is MP3."
2747
  msgstr ""
2748
 
2749
- #: app/main/controllers/upload/processors/RTMediaUploadFile.php:271
2750
- msgid "The MP3 file you have uploaded is not an audio file."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2751
  msgstr ""
2752
 
2753
- #: app/main/controllers/upload/processors/RTMediaUploadFile.php:279
2754
  msgid ""
2755
- "Media File you have tried to upload is not supported. Supported media files "
2756
- "are .jpg, .png, .gif, .mp3, .mov and .mp4."
2757
  msgstr ""
2758
 
2759
- #: app/main/deprecated/RTMediaDeprecated.php:27
2760
- msgid "Deprecated %s. Please use %s."
2761
  msgstr ""
2762
 
2763
- #: app/services/RTMediaEncoding.php:158
2764
- msgid "rtMedia Encoding: Nearing quota limit."
2765
  msgstr ""
2766
 
2767
- #: app/services/RTMediaEncoding.php:159
2768
  msgid ""
2769
- "<p>You are nearing the quota limit for your rtMedia encoding "
2770
- "service.</p><p>Following are the details:</p><p><strong>Used:</strong> "
2771
- "%s</p><p><strong>Remaining</strong>: %s</p><p><strong>Total:</strong> %s</p>"
 
2772
  msgstr ""
2773
 
2774
- #: app/services/RTMediaEncoding.php:173
2775
- msgid "rtMedia Encoding: Usage quota over."
2776
  msgstr ""
2777
 
2778
- #: app/services/RTMediaEncoding.php:174
2779
  msgid ""
2780
- "<p>Your usage quota is over. Upgrade your plan</p><p>Following are the "
2781
- "details:</p><p><strong>Used:</strong> %s</p><p><strong>Remaining</strong>: "
2782
- "%s</p><p><strong>Total:</strong> %s</p>"
2783
  msgstr ""
2784
 
2785
- #: app/services/RTMediaEncoding.php:237
2786
- msgid "You have successfully subscribed for the <strong>%s</strong> plan"
2787
  msgstr ""
2788
 
2789
- #: app/services/RTMediaEncoding.php:249
2790
- msgid "Unsubscribe"
2791
  msgstr ""
2792
 
2793
- #: app/services/RTMediaEncoding.php:251
2794
  msgid ""
2795
- "Just to improve our service we would like to know the reason for you to "
2796
- "leave us."
 
 
2797
  msgstr ""
2798
 
2799
- #: app/services/RTMediaEncoding.php:300 app/services/RTMediaEncoding.php:402
2800
- msgid "Current Plan"
2801
  msgstr ""
2802
 
2803
- #: app/services/RTMediaEncoding.php:300
2804
- msgid "Unsubscribed"
 
 
 
2805
  msgstr ""
2806
 
2807
- #: app/services/RTMediaEncoding.php:302
2808
- msgid "Used"
 
 
2809
  msgstr ""
2810
 
2811
- #: app/services/RTMediaEncoding.php:304
2812
- msgid "Remaining"
2813
  msgstr ""
2814
 
2815
- #: app/services/RTMediaEncoding.php:306
2816
- msgid "Total"
 
 
2817
  msgstr ""
2818
 
2819
- #: app/services/RTMediaEncoding.php:310
2820
- msgid "Your usage limit has been reached. Upgrade your plan."
2821
  msgstr ""
2822
 
2823
- #: app/services/RTMediaEncoding.php:312
2824
- msgid "Your API key is not valid or is expired."
 
 
 
2825
  msgstr ""
2826
 
2827
- #: app/services/RTMediaEncoding.php:314
2828
- msgid "Encoding Usage"
2829
  msgstr ""
2830
 
2831
- #: app/services/RTMediaEncoding.php:320
2832
- msgid "Audio/Video encoding service"
2833
  msgstr ""
2834
 
2835
- #: app/services/RTMediaEncoding.php:322
2836
- msgid "rtMedia team has started offering an audio/video encoding service."
2837
  msgstr ""
2838
 
2839
- #: app/services/RTMediaEncoding.php:325
2840
- msgid "Enter API KEY"
2841
  msgstr ""
2842
 
2843
- #: app/services/RTMediaEncoding.php:327
2844
- msgid "Save Key"
2845
  msgstr ""
2846
 
2847
- #: app/services/RTMediaEncoding.php:348
2848
- msgid "Feature\\Plan"
2849
  msgstr ""
2850
 
2851
- #: app/services/RTMediaEncoding.php:349 app/services/RTMediaEncoding.php:392
2852
- msgid "Free"
2853
  msgstr ""
2854
 
2855
- #: app/services/RTMediaEncoding.php:350
2856
- msgid "Silver"
2857
  msgstr ""
2858
 
2859
- #: app/services/RTMediaEncoding.php:351
2860
- msgid "Gold"
2861
  msgstr ""
2862
 
2863
- #: app/services/RTMediaEncoding.php:352
2864
- msgid "Platinum"
2865
  msgstr ""
2866
 
2867
- #: app/services/RTMediaEncoding.php:358
2868
- msgid "File Size Limit"
2869
  msgstr ""
2870
 
2871
- #: app/services/RTMediaEncoding.php:363
2872
- msgid "Bandwidth (monthly)"
2873
  msgstr ""
2874
 
2875
- #: app/services/RTMediaEncoding.php:370
2876
- msgid "Overage Bandwidth"
2877
  msgstr ""
2878
 
2879
- #: app/services/RTMediaEncoding.php:371 app/services/RTMediaEncoding.php:378
2880
- #: app/services/RTMediaEncoding.php:383
2881
- msgid "Not Available"
 
 
2882
  msgstr ""
2883
 
2884
- #: app/services/RTMediaEncoding.php:377
2885
- msgid "Amazon S3 Support"
2886
  msgstr ""
2887
 
2888
- #: app/services/RTMediaEncoding.php:379 app/services/RTMediaEncoding.php:384
2889
- #: app/services/RTMediaEncoding.php:388
2890
- msgid "Coming Soon"
2891
  msgstr ""
2892
 
2893
- #: app/services/RTMediaEncoding.php:382
2894
- msgid "HD Profile"
2895
  msgstr ""
2896
 
2897
- #: app/services/RTMediaEncoding.php:387
2898
- msgid "Webcam Recording"
2899
  msgstr ""
2900
 
2901
- #: app/services/RTMediaEncoding.php:391
2902
- msgid "Pricing"
2903
  msgstr ""
2904
 
2905
- #: app/services/RTMediaEncoding.php:393
2906
- msgid "$9/month"
2907
  msgstr ""
2908
 
2909
- #: app/services/RTMediaEncoding.php:394
2910
- msgid "$99/month"
2911
  msgstr ""
2912
 
2913
- #: app/services/RTMediaEncoding.php:395
2914
- msgid "$999/month"
2915
  msgstr ""
2916
 
2917
- #: app/services/RTMediaEncoding.php:406
2918
- msgid "Try Now"
 
 
 
2919
  msgstr ""
2920
 
2921
- #: app/services/RTMediaEncoding.php:560
2922
- msgid "Could not read file."
2923
  msgstr ""
2924
 
2925
- #: app/services/RTMediaEncoding.php:564
2926
- msgid ""
2927
- "Something went wrong. The required attachment id does not exists. It must "
2928
- "have been deleted."
2929
  msgstr ""
2930
 
2931
- #: app/services/RTMediaEncoding.php:579
2932
- msgid "rtMedia Encoding: Download Failed"
 
 
 
 
 
2933
  msgstr ""
2934
 
2935
- #: app/services/RTMediaEncoding.php:580
2936
  msgid ""
2937
- "<p><a href=\"%s\">Media</a> was successfully encoded but there was an error "
2938
- "while downloading:</p>\n"
2939
- " <p><code>%s</code></p>\n"
2940
- " <p>You can <a href=\"%s\">retry the "
2941
- "download</a>.</p>"
2942
  msgstr ""
2943
 
2944
- #: app/services/RTMediaEncoding.php:594
2945
- msgid "Done"
 
2946
  msgstr ""
2947
 
2948
- #: app/services/RTMediaEncoding.php:619 app/services/RTMediaEncoding.php:641
2949
- msgid "Something went wrong please try again."
 
2950
  msgstr ""
2951
 
2952
- #: app/services/RTMediaEncoding.php:638
2953
- msgid "Your subscription was cancelled successfully"
2954
  msgstr ""
2955
 
2956
- #: app/services/RTMediaEncoding.php:650
2957
- msgid "Please enter the api key."
 
2958
  msgstr ""
2959
 
2960
- #: app/services/RTMediaEncoding.php:657
2961
- msgid "Encoding disabled successfully."
2962
  msgstr ""
2963
 
2964
- #: app/services/RTMediaEncoding.php:663
2965
- msgid "Encoding enabled successfully."
 
2966
  msgstr ""
2967
 
2968
  #: templates/media/album-gallery.php:14
2969
  msgid "Album List"
2970
  msgstr ""
2971
 
2972
- #: templates/media/album-gallery.php:64
2973
- #: templates/media/media-single-edit.php:61
2974
- #: templates/media/media-single.php:146
2975
- msgid "Sorry !! There's no media found for the request !!"
2976
- msgstr ""
2977
-
2978
  #: templates/media/album-single-edit.php:12
2979
  msgid "Edit Album : "
2980
  msgstr ""
@@ -2983,21 +4434,6 @@ msgstr ""
2983
  msgid "Manage Media"
2984
  msgstr ""
2985
 
2986
- #: templates/media/album-single-edit.php:32
2987
- #: templates/media/media-single-edit.php:26
2988
- msgid "Title : "
2989
- msgstr ""
2990
-
2991
- #: templates/media/album-single-edit.php:37
2992
- #: templates/media/media-single-edit.php:32
2993
- msgid "Description: "
2994
- msgstr ""
2995
-
2996
- #: templates/media/album-single-edit.php:48
2997
- #: templates/media/media-single-edit.php:47
2998
- msgid "Back"
2999
- msgstr ""
3000
-
3001
  #: templates/media/album-single-edit.php:63
3002
  msgid "Move Selected media to another album."
3003
  msgstr ""
@@ -3042,47 +4478,6 @@ msgstr ""
3042
  msgid "Oops !! There's no media found for the request !!"
3043
  msgstr ""
3044
 
3045
- #: templates/media/media-single-edit.php:46
3046
- msgid "Save"
3047
- msgstr ""
3048
-
3049
- #: templates/media/media-single-edit.php:54
3050
- msgid "Sorry !! You do not have rights to edit this media"
3051
- msgstr ""
3052
-
3053
  #: templates/media/media-single.php:35
3054
  msgid "under"
3055
  msgstr ""
3056
-
3057
- #. Plugin Name of the plugin/theme
3058
- msgid "rtMedia for WordPress, BuddyPress and bbPress"
3059
- msgstr ""
3060
-
3061
- #. Plugin URI of the plugin/theme
3062
- msgid ""
3063
- "http://rtcamp.com/rtmedia/?utm_source=dashboard&utm_medium=plugin&utm_"
3064
- "campaign=buddypress-media"
3065
- msgstr ""
3066
-
3067
- #. Description of the plugin/theme
3068
- msgid ""
3069
- "This plugin adds missing media rich features like photos, videos and audio "
3070
- "uploading to BuddyPress which are essential if you are building social "
3071
- "network, seriously!"
3072
- msgstr ""
3073
-
3074
- #. Author URI of the plugin/theme
3075
- msgid ""
3076
- "http://rtcamp.com/?utm_source=dashboard&utm_medium=plugin&utm_campaign="
3077
- "buddypress-media"
3078
- msgstr ""
3079
-
3080
- #: app/main/controllers/media/RTMediaAlbum.php:35
3081
- msgctxt "Status General Name"
3082
- msgid "hidden"
3083
- msgstr ""
3084
-
3085
- #: app/main/controllers/template/RTMediaNav.php:32
3086
- msgctxt "My Account Privacy sub nav"
3087
- msgid "Privacy"
3088
- msgstr ""
2
  # This file is distributed under the same license as the rtMedia for WordPress, BuddyPress and bbPress package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: rtMedia for WordPress, BuddyPress and bbPress 3.9.4\n"
6
  "Report-Msgid-Bugs-To: http://community.rtcamp.com/c/rtmedia/\n"
7
+ "POT-Creation-Date: 2015-12-22 16:22+0530\n"
8
+ "PO-Revision-Date: 2015-12-22 16:22+0530\n"
 
 
 
9
  "Last-Translator: rtMedia <rtmedia@rtcamp.com>\n"
10
  "Language-Team: rtMedia <rtmedia@rtcamp.com>\n"
 
 
 
 
11
  "Language: en\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=utf-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Generator: Poedit 1.5.4\n"
16
+ "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;"
17
+ "_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;"
18
+ "esc_html_x:1,2c\n"
19
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
20
  "X-Poedit-SourceCharset: UTF-8\n"
21
  "X-Poedit-Basepath: ../\n"
 
 
22
  "X-Textdomain-Support: yes\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
 
25
+ #: node_modules/grunt-wp-i18n/test/fixtures/translator-comments/translator-comments.php:7
26
+ msgid "A"
27
  msgstr ""
28
 
29
+ #: node_modules/grunt-wp-i18n/test/fixtures/translator-comments/translator-comments.php:15
30
+ msgid "B"
31
  msgstr ""
32
 
33
+ #: node_modules/grunt-wp-i18n/test/fixtures/basic-theme/exclude/file.php:3
34
+ #: node_modules/grunt-wp-i18n/test/fixtures/plugin-include/plugin-include.php:6
35
+ msgid "Exclude"
36
  msgstr ""
37
 
38
+ #: node_modules/grunt-wp-i18n/test/fixtures/plugin-include/include/file.php:2
39
+ msgid "Include"
40
  msgstr ""
41
 
42
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:2
43
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:3
44
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:4
45
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/add-domain.php:2
46
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-domains.php:2
47
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-domains.php:3
48
+ msgid "String"
49
  msgstr ""
50
 
51
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:6
52
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:7
53
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:8
54
+ msgctxt "a string"
55
+ msgid "String"
56
  msgstr ""
57
 
58
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:9
59
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:10
60
+ #: node_modules/grunt-wp-i18n/test/fixtures/text-domains/update-all-domains.php:11
61
+ #, php-format
62
+ msgid "1 Star"
63
+ msgid_plural "%s Stars"
64
+ msgstr[0] ""
65
+ msgstr[1] ""
66
+
67
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:3
68
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:5
69
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:9
70
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:10
71
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:14
72
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:15
73
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:4
74
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:6
75
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:10
76
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:11
77
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:15
78
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:16
79
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:3
80
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:5
81
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:9
82
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:10
83
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:14
84
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:15
85
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:3
86
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:5
87
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:9
88
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:10
89
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:14
90
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:15
91
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:3
92
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:5
93
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:9
94
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:10
95
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:14
96
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:15
97
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:4
98
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:6
99
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:10
100
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:11
101
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:15
102
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:16
103
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:3
104
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:5
105
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:9
106
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:10
107
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:14
108
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:15
109
+ msgid "Hello World"
110
+ msgstr ""
111
+
112
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:4
113
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:6
114
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:11
115
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:16
116
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:5
117
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:7
118
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:12
119
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:17
120
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:4
121
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:6
122
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:11
123
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:16
124
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:4
125
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:6
126
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:11
127
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:16
128
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:4
129
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:6
130
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:11
131
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:16
132
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:5
133
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:7
134
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:12
135
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:17
136
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:4
137
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:6
138
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:11
139
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:16
140
+ msgctxt "verb"
141
+ msgid "Post"
142
+ msgstr ""
143
+
144
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:20
145
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:24
146
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:21
147
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:25
148
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:20
149
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:24
150
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:20
151
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:24
152
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:20
153
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:24
154
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:21
155
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:25
156
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:3
157
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:8
158
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:15
159
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:20
160
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:24
161
+ #, php-format
162
+ msgid "%d apple"
163
+ msgid_plural "%d apples"
164
+ msgstr[0] ""
165
+ msgstr[1] ""
166
+
167
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:21
168
+ #: node_modules/grunt-checktextdomain/test/expected/incorrect-domain-autocorrect.php:25
169
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:22
170
+ #: node_modules/grunt-checktextdomain/test/expected/variable-domain-autocorrect.php:26
171
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:21
172
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain-autocorrect.php:25
173
+ #: node_modules/grunt-checktextdomain/test/fixtures/missing-domain.php:25
174
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:21
175
+ #: node_modules/grunt-checktextdomain/test/fixtures/incorrect-domain.php:25
176
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:22
177
+ #: node_modules/grunt-checktextdomain/test/fixtures/variable-domain-autocorrect.php:26
178
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:4
179
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:9
180
+ #: node_modules/grunt-checktextdomain/test/fixtures/plurals.php:16
181
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:21
182
+ #: node_modules/grunt-checktextdomain/test/fixtures/correct-domain.php:25
183
+ #, php-format
184
+ msgctxt "noun, job positions"
185
+ msgid "%d post"
186
+ msgid_plural "%d posts"
187
+ msgstr[0] ""
188
+ msgstr[1] ""
189
+
190
+ #: lib/freemius/includes/i18n.php:5
191
+ msgid "Account"
192
  msgstr ""
193
 
194
+ #: lib/freemius/includes/i18n.php:6
195
+ msgid "Add On"
196
  msgstr ""
197
 
198
+ #: lib/freemius/includes/i18n.php:7
199
+ #: app/main/controllers/template/rt-template-functions.php:2714
200
+ msgid "Contact Us"
201
  msgstr ""
202
 
203
+ #: lib/freemius/includes/i18n.php:8
204
+ msgid "Change Ownership"
205
  msgstr ""
206
 
207
+ #: lib/freemius/includes/i18n.php:9 app/admin/RTMediaAdmin.php:743
208
+ #: app/admin/RTMediaAdmin.php:746 app/admin/RTMediaAdmin.php:872
209
+ #: app/admin/RTMediaAdmin.php:1414 app/helper/RTMediaSupport.php:51
210
+ #: app/helper/RTMediaSupport.php:52 app/helper/RTMediaSettings.php:210
211
+ msgid "Support"
212
  msgstr ""
213
 
214
+ #: lib/freemius/includes/i18n.php:10
215
+ msgid "Support Forum"
216
  msgstr ""
217
 
218
+ #: lib/freemius/includes/i18n.php:11
219
+ msgid "Add Ons"
220
  msgstr ""
221
 
222
+ #: lib/freemius/includes/i18n.php:12
223
+ msgctxt "verb"
224
+ msgid "Upgrade"
225
  msgstr ""
226
 
227
+ #: lib/freemius/includes/i18n.php:13
228
+ msgid "Awesome"
229
  msgstr ""
230
 
231
+ #: lib/freemius/includes/i18n.php:14 app/services/RTMediaEncoding.php:391
232
+ msgid "Pricing"
233
  msgstr ""
234
 
235
+ #: lib/freemius/includes/i18n.php:15
236
+ msgctxt "noun"
237
+ msgid "Price"
238
  msgstr ""
239
 
240
+ #: lib/freemius/includes/i18n.php:16
241
+ msgid "Unlimited Updates"
242
  msgstr ""
243
 
244
+ #: lib/freemius/includes/i18n.php:17
245
+ msgctxt "verb"
246
+ msgid "Downgrade"
247
  msgstr ""
248
 
249
+ #: lib/freemius/includes/i18n.php:18
250
+ msgid "Free Trial"
251
  msgstr ""
252
 
253
+ #: lib/freemius/includes/i18n.php:19 app/helper/RTMediaSupport.php:447
254
+ #: templates/media/media-single-edit.php:16
255
+ #: templates/media/album-single-edit.php:16
256
+ msgid "Details"
257
  msgstr ""
258
 
259
+ #: lib/freemius/includes/i18n.php:20
260
+ msgid "Account Details"
261
  msgstr ""
262
 
263
+ #: lib/freemius/includes/i18n.php:21
264
+ msgctxt "verb"
265
+ msgid "Delete"
266
  msgstr ""
267
 
268
+ #: lib/freemius/includes/i18n.php:22
269
+ msgid "Delete Account"
 
270
  msgstr ""
271
 
272
+ #: lib/freemius/includes/i18n.php:23 app/admin/RTMediaAdmin.php:395
273
+ msgid "Dismiss"
 
274
  msgstr ""
275
 
276
+ #: lib/freemius/includes/i18n.php:24
277
+ msgctxt "as product pricing plan"
278
+ msgid "Plan"
 
 
279
  msgstr ""
280
 
281
+ #: lib/freemius/includes/i18n.php:25
282
+ msgid "Change Plan"
 
283
  msgstr ""
284
 
285
+ #: lib/freemius/includes/i18n.php:26
286
+ #, php-format
287
+ msgctxt "as download professional version"
288
+ msgid "Download %s Version"
289
  msgstr ""
290
 
291
+ #: lib/freemius/includes/i18n.php:27
292
+ #, php-format
293
+ msgctxt "as download professional version now"
294
+ msgid "Download %s version now"
295
  msgstr ""
296
 
297
+ #: lib/freemius/includes/i18n.php:28
298
+ msgctxt "as download latest version"
299
+ msgid "Download Latest"
300
  msgstr ""
301
 
302
+ #: lib/freemius/includes/i18n.php:29
303
+ #, php-format
304
+ msgctxt "E.g. you have a professional license."
305
+ msgid "You have a %s license."
306
  msgstr ""
307
 
308
+ #: lib/freemius/includes/i18n.php:30
309
+ msgid "New"
310
  msgstr ""
311
 
312
+ #: lib/freemius/includes/i18n.php:31 app/services/RTMediaEncoding.php:349
313
+ #: app/services/RTMediaEncoding.php:392
314
+ msgid "Free"
 
315
  msgstr ""
316
 
317
+ #: lib/freemius/includes/i18n.php:32
318
+ msgctxt "as trial plan"
319
+ msgid "Trial"
320
  msgstr ""
321
 
322
+ #: lib/freemius/includes/i18n.php:33
323
+ msgctxt "verb"
324
+ msgid "Purchase"
325
  msgstr ""
326
 
327
+ #: lib/freemius/includes/i18n.php:34
328
+ msgid "Single Site License"
329
  msgstr ""
330
 
331
+ #: lib/freemius/includes/i18n.php:35
332
+ msgid "Unlimited Licenses"
333
  msgstr ""
334
 
335
+ #: lib/freemius/includes/i18n.php:36
336
+ #, php-format
337
+ msgid "Up to %s Sites"
338
  msgstr ""
339
 
340
+ #: lib/freemius/includes/i18n.php:37
341
+ #, php-format
342
+ msgctxt "e.g. Professional Plan"
343
+ msgid "%s Plan"
344
  msgstr ""
345
 
346
+ #: lib/freemius/includes/i18n.php:38
347
+ #, php-format
348
+ msgid "You are just one step away - %s"
349
  msgstr ""
350
 
351
+ #: lib/freemius/includes/i18n.php:39
352
+ #, php-format
353
+ msgctxt "%s - plugin name. As complete \"Jetpack\" activation now"
354
+ msgid "Complete \"%s\" Activation Now"
355
  msgstr ""
356
 
357
+ #: lib/freemius/includes/i18n.php:40
358
+ #, php-format
359
+ msgid "We made a few tweaks to the plugin, %s"
360
  msgstr ""
361
 
362
+ #: lib/freemius/includes/i18n.php:41
363
+ #, php-format
364
+ msgid "Opt-in to make \"%s\" Better!"
365
  msgstr ""
366
 
367
+ #: lib/freemius/includes/i18n.php:42
368
+ msgid "Error"
 
 
 
369
  msgstr ""
370
 
371
+ #: lib/freemius/includes/i18n.php:43
372
+ msgid ""
373
+ "Freemius SDK couldn't find the plugin's main file. Please contact "
374
+ "sdk@freemius.com with the current error."
375
  msgstr ""
376
 
377
+ #: lib/freemius/includes/i18n.php:46
378
+ msgctxt "as expiration date"
379
+ msgid "Expiration"
380
  msgstr ""
381
 
382
+ #: lib/freemius/includes/i18n.php:47
383
+ msgid "not verified"
384
  msgstr ""
385
 
386
+ #: lib/freemius/includes/i18n.php:48
387
+ msgid "Verify Email"
388
  msgstr ""
389
 
390
+ #: lib/freemius/includes/i18n.php:49
391
+ #, php-format
392
+ msgctxt "e.g. expires in 2 months"
393
+ msgid "Expires in %s"
394
  msgstr ""
395
 
396
+ #: lib/freemius/includes/i18n.php:50
397
+ #, php-format
398
+ msgctxt "e.g. auto renews in 2 months"
399
+ msgid "Auto renews in %s"
400
  msgstr ""
401
 
402
+ #: lib/freemius/includes/i18n.php:51
403
+ msgid "No expiration"
404
  msgstr ""
405
 
406
+ #: lib/freemius/includes/i18n.php:52
407
+ msgid "Expired"
408
  msgstr ""
409
 
410
+ #: lib/freemius/includes/i18n.php:53
411
+ #, php-format
412
+ msgid "In %s"
413
  msgstr ""
414
 
415
+ #: lib/freemius/includes/i18n.php:54
416
+ msgctxt "as plugin version"
417
+ msgid "Version"
418
  msgstr ""
419
 
420
+ #: lib/freemius/includes/i18n.php:55 app/helper/RTMediaSupport.php:415
421
+ msgid "Name"
422
  msgstr ""
423
 
424
+ #: lib/freemius/includes/i18n.php:56 app/helper/RTMediaSupport.php:426
425
+ msgid "Email"
426
  msgstr ""
427
 
428
+ #: lib/freemius/includes/i18n.php:57
429
+ msgid "Verified"
 
430
  msgstr ""
431
 
432
+ #: lib/freemius/includes/i18n.php:58
433
+ msgid "Plugin"
434
  msgstr ""
435
 
436
+ #: lib/freemius/includes/i18n.php:59
437
+ msgid "Title"
438
  msgstr ""
439
 
440
+ #: lib/freemius/includes/i18n.php:60
441
+ msgctxt "as WP plugin slug"
442
+ msgid "Slug"
443
  msgstr ""
444
 
445
+ #: lib/freemius/includes/i18n.php:61
446
+ msgid "ID"
447
  msgstr ""
448
 
449
+ #: lib/freemius/includes/i18n.php:62 app/importers/BPMediaAlbumimporter.php:80
450
+ msgid "Users"
451
  msgstr ""
452
 
453
+ #: lib/freemius/includes/i18n.php:63
454
+ msgid "Plugin Installs"
455
  msgstr ""
456
 
457
+ #: lib/freemius/includes/i18n.php:64
458
+ msgctxt "like websites"
459
+ msgid "Sites"
460
  msgstr ""
461
 
462
+ #: lib/freemius/includes/i18n.php:65
463
+ msgid "User ID"
464
  msgstr ""
465
 
466
+ #: lib/freemius/includes/i18n.php:66
467
+ msgid "Site ID"
468
  msgstr ""
469
 
470
+ #: lib/freemius/includes/i18n.php:67
471
+ msgid "Public Key"
472
  msgstr ""
473
 
474
+ #: lib/freemius/includes/i18n.php:68
475
+ msgid "Secret Key"
476
  msgstr ""
477
 
478
+ #: lib/freemius/includes/i18n.php:69
479
+ msgctxt "as secret encryption key missing"
480
+ msgid "No Secret"
481
  msgstr ""
482
 
483
+ #: lib/freemius/includes/i18n.php:70
484
+ msgid "No ID"
485
  msgstr ""
486
 
487
+ #: lib/freemius/includes/i18n.php:71
488
+ msgctxt "as synchronize license"
489
+ msgid "Sync License"
490
  msgstr ""
491
 
492
+ #: lib/freemius/includes/i18n.php:72 app/helper/RTMediaLicense.php:96
493
+ msgid "Deactivate License"
494
  msgstr ""
495
 
496
+ #: lib/freemius/includes/i18n.php:73
497
+ msgid "Activate"
 
 
 
498
  msgstr ""
499
 
500
+ #: lib/freemius/includes/i18n.php:74 lib/freemius/includes/i18n.php:95
501
+ msgid "Deactivate"
 
502
  msgstr ""
503
 
504
+ #: lib/freemius/includes/i18n.php:75
505
+ msgctxt "active mode"
506
+ msgid "Active"
507
  msgstr ""
508
 
509
+ #: lib/freemius/includes/i18n.php:76
510
+ #: lib/freemius/includes/fs-plugin-functions.php:390
511
+ msgid "Install Now"
 
 
512
  msgstr ""
513
 
514
+ #: lib/freemius/includes/i18n.php:77
515
+ #: lib/freemius/includes/fs-plugin-functions.php:395
516
+ msgid "Install Update Now"
 
 
517
  msgstr ""
518
 
519
+ #: lib/freemius/includes/i18n.php:78
520
+ #, php-format
521
+ msgid "More information about %s"
522
  msgstr ""
523
 
524
+ #: lib/freemius/includes/i18n.php:79
525
+ msgid "Localhost"
526
  msgstr ""
527
 
528
+ #: lib/freemius/includes/i18n.php:80
529
+ #, php-format
530
+ msgctxt "as activate Professional plan"
531
+ msgid "Activate %s Plan"
532
  msgstr ""
533
 
534
+ #: lib/freemius/includes/i18n.php:81
535
+ #, php-format
536
+ msgid "What is your %s?"
 
 
537
  msgstr ""
538
 
539
+ #: lib/freemius/includes/i18n.php:82
540
+ msgid "Activate this add-on"
 
 
541
  msgstr ""
542
 
543
+ #: lib/freemius/includes/i18n.php:83
544
+ msgid ""
545
+ "Deactivating your license will block all premium features, but will enable "
546
+ "you to activate the license on another site. Are you sure you want to "
547
+ "proceed?"
548
  msgstr ""
549
 
550
+ #: lib/freemius/includes/i18n.php:84
551
+ #, php-format
552
+ msgid ""
553
+ "Deleting the account will automatically deactivate your %s plan license so "
554
+ "you can use it on other sites. If you want to terminate the recurring "
555
+ "payments as well, click the \"Cancel\" button, and first \"Downgrade\" your "
556
+ "account. Are you sure you would like to continue with the deletion?"
557
  msgstr ""
558
 
559
+ #: lib/freemius/includes/i18n.php:85
560
+ msgid ""
561
+ "Deletion is not temporary. Only delete if you no longer want to use this "
562
+ "plugin anymore. Are you sure you would like to continue with the deletion?"
563
  msgstr ""
564
 
565
+ #: lib/freemius/includes/i18n.php:86
566
+ #, php-format
567
+ msgid ""
568
+ "Downgrading your plan will immediately stop all future recurring payments "
569
+ "and your %s plan license will expire in %s."
570
  msgstr ""
571
 
572
+ #: lib/freemius/includes/i18n.php:87
573
+ #, php-format
574
+ msgid ""
575
+ "You can still enjoy all %s features but you will not have access to plugin "
576
+ "updates and support."
577
  msgstr ""
578
 
579
+ #: lib/freemius/includes/i18n.php:88
580
+ #, php-format
581
  msgid ""
582
+ "Once your license expire you can still use the Free version but you will NOT "
583
+ "have access to the %s features."
584
  msgstr ""
585
 
586
+ #: lib/freemius/includes/i18n.php:89
587
+ msgid "Are you sure you want to proceed?"
588
  msgstr ""
589
 
590
+ #: lib/freemius/includes/i18n.php:92
591
+ #, php-format
592
+ msgid "Add Ons for %s"
593
  msgstr ""
594
 
595
+ #: lib/freemius/includes/i18n.php:94
596
+ msgid "If you have a moment, please let us know why you are deactivating"
597
  msgstr ""
598
 
599
+ #: lib/freemius/includes/i18n.php:96
600
+ msgid "Yes - Deactivate"
601
  msgstr ""
602
 
603
+ #: lib/freemius/includes/i18n.php:97
604
+ msgid "Submit & Deactivate"
605
  msgstr ""
606
 
607
+ #: lib/freemius/includes/i18n.php:98
608
+ msgctxt "the text of the cancel button of the plugin deactivation dialog box."
609
+ msgid "Cancel"
610
  msgstr ""
611
 
612
+ #: lib/freemius/includes/i18n.php:99
613
+ msgid "I no longer need the plugin"
614
  msgstr ""
615
 
616
+ #: lib/freemius/includes/i18n.php:100
617
+ msgid "I found a better plugin"
618
  msgstr ""
619
 
620
+ #: lib/freemius/includes/i18n.php:101
621
+ msgid "I only needed the plugin for a short period"
622
  msgstr ""
623
 
624
+ #: lib/freemius/includes/i18n.php:102
625
+ msgid "The plugin broke my site"
626
  msgstr ""
627
 
628
+ #: lib/freemius/includes/i18n.php:103
629
+ msgid "The plugin suddenly stopped working"
630
  msgstr ""
631
 
632
+ #: lib/freemius/includes/i18n.php:104
633
+ msgid "I can't pay for it anymore"
634
  msgstr ""
635
 
636
+ #: lib/freemius/includes/i18n.php:105
637
+ msgctxt ""
638
+ "the text of the \"other\" reason for deactivating the plugin that is shown "
639
+ "in the modal box."
640
+ msgid "Other"
641
  msgstr ""
642
 
643
+ #: lib/freemius/includes/i18n.php:106
644
+ msgid "What's the plugin's name?"
 
 
645
  msgstr ""
646
 
647
+ #: lib/freemius/includes/i18n.php:107
648
+ msgid "What price would you feel comfortable paying?"
649
  msgstr ""
650
 
651
+ #: lib/freemius/includes/i18n.php:108
652
+ msgid "I couldn't understand how to make it work"
653
  msgstr ""
654
 
655
+ #: lib/freemius/includes/i18n.php:109
656
+ msgid "The plugin is great, but I need specific feature that you don't support"
657
  msgstr ""
658
 
659
+ #: lib/freemius/includes/i18n.php:110
660
+ msgid "The plugin is not working"
661
  msgstr ""
662
 
663
+ #: lib/freemius/includes/i18n.php:111
664
+ msgid "It's not what I was looking for"
665
  msgstr ""
666
 
667
+ #: lib/freemius/includes/i18n.php:112
668
+ msgid "The plugin didn't work as expected"
669
  msgstr ""
670
 
671
+ #: lib/freemius/includes/i18n.php:113
672
+ msgid "What feature?"
673
  msgstr ""
674
 
675
+ #: lib/freemius/includes/i18n.php:114
676
+ msgid "Kindly share what didn't work so we can fix it for future users..."
 
 
 
677
  msgstr ""
678
 
679
+ #: lib/freemius/includes/i18n.php:115
680
+ msgid "What you've been looking for?"
681
  msgstr ""
682
 
683
+ #: lib/freemius/includes/i18n.php:116
684
+ msgid "What did you expect?"
 
 
685
  msgstr ""
686
 
687
+ #: lib/freemius/includes/i18n.php:117
688
+ msgid "The plugin didn't work"
689
  msgstr ""
690
 
691
+ #: lib/freemius/includes/i18n.php:118
692
+ msgid "I don't like to share my information with you"
693
  msgstr ""
694
 
695
+ #: lib/freemius/includes/i18n.php:122
696
+ #, php-format
697
+ msgctxt "greeting"
698
+ msgid "Hey %s,"
699
  msgstr ""
700
 
701
+ #: lib/freemius/includes/i18n.php:123
702
+ #, php-format
703
+ msgctxt "a greeting. E.g. Thanks John!"
704
+ msgid "Thanks %s!"
705
+ msgstr ""
706
+
707
+ #: lib/freemius/includes/i18n.php:124
708
+ #, php-format
709
  msgid ""
710
+ "In order to enjoy all our features and functionality, %s needs to connect "
711
+ "your user, %s at %s, to %s"
712
  msgstr ""
713
 
714
+ #: lib/freemius/includes/i18n.php:125
715
+ #, php-format
716
+ msgid ""
717
+ "You should receive an activation email for %s to your mailbox at %s. Please "
718
+ "make sure you click the activation button in that email to complete the "
719
+ "install."
720
  msgstr ""
721
 
722
+ #: lib/freemius/includes/i18n.php:126
723
+ msgid "What permissions are being granted?"
724
  msgstr ""
725
 
726
+ #: lib/freemius/includes/i18n.php:127
727
+ msgid "Your Profile Overview"
 
728
  msgstr ""
729
 
730
+ #: lib/freemius/includes/i18n.php:128
731
+ msgid "Name and email address"
732
  msgstr ""
733
 
734
+ #: lib/freemius/includes/i18n.php:129
735
+ msgid "Your Site Overview"
 
 
736
  msgstr ""
737
 
738
+ #: lib/freemius/includes/i18n.php:130
739
+ msgid "Site address and WordPress version"
740
  msgstr ""
741
 
742
+ #: lib/freemius/includes/i18n.php:131
743
+ msgid "Current Plugin Events"
744
  msgstr ""
745
 
746
+ #: lib/freemius/includes/i18n.php:132
747
+ msgid "Activation, deactivation and uninstall"
748
  msgstr ""
749
 
750
+ #: lib/freemius/includes/i18n.php:133
751
+ msgid "Privacy Policy"
752
  msgstr ""
753
 
754
+ #: lib/freemius/includes/i18n.php:134
755
+ msgid "Terms of Service"
756
  msgstr ""
757
 
758
+ #: lib/freemius/includes/i18n.php:135
759
+ msgctxt "as activating plugin"
760
+ msgid "Activating"
761
  msgstr ""
762
 
763
+ #: lib/freemius/includes/i18n.php:136
764
+ msgctxt "button label"
765
+ msgid "Allow & Continue"
766
  msgstr ""
767
 
768
+ #: lib/freemius/includes/i18n.php:137
769
+ msgctxt "verb"
770
+ msgid "Skip"
771
  msgstr ""
772
 
773
+ #: lib/freemius/includes/i18n.php:138
774
+ msgid "Re-send activation email"
775
  msgstr ""
776
 
777
+ #: lib/freemius/includes/i18n.php:142
778
+ msgid "Screenshots"
779
  msgstr ""
780
 
781
+ #: lib/freemius/includes/i18n.php:143
782
+ #, php-format
783
+ msgid "Click to view full-size screenshot %d"
784
  msgstr ""
785
 
786
+ #: lib/freemius/includes/i18n.php:147
787
+ #, php-format
788
+ msgid "Add Ons of Plugin %s"
789
  msgstr ""
790
 
791
+ #: lib/freemius/includes/i18n.php:148
792
+ msgid "Are you sure you want to delete the all Freemius data?"
793
  msgstr ""
794
 
795
+ #: lib/freemius/includes/i18n.php:149
796
+ msgid "Delete All Accounts"
797
  msgstr ""
798
 
799
+ #: lib/freemius/includes/i18n.php:153
800
+ msgctxt "as congratulations"
801
+ msgid "Congrats"
802
  msgstr ""
803
 
804
+ #: lib/freemius/includes/i18n.php:154
805
+ msgctxt "exclamation"
806
+ msgid "Oops"
807
  msgstr ""
808
 
809
+ #: lib/freemius/includes/i18n.php:155
810
+ msgctxt "interjection expressing joy or exuberance"
811
+ msgid "Yee-haw"
812
  msgstr ""
813
 
814
+ #: lib/freemius/includes/i18n.php:156
815
+ msgctxt ""
816
+ "(especially in electronic communication) used to express elation, "
817
+ "enthusiasm, or triumph."
818
+ msgid "W00t"
819
  msgstr ""
820
 
821
+ #: lib/freemius/includes/i18n.php:157
822
+ msgctxt "a positive response"
823
+ msgid "Right on"
824
  msgstr ""
825
 
826
+ #: lib/freemius/includes/i18n.php:158
827
+ msgctxt ""
828
+ "something somebody says when they are thinking about what you have just "
829
+ "said. "
830
+ msgid "Hmm"
831
  msgstr ""
832
 
833
+ #: lib/freemius/includes/i18n.php:159
834
+ msgid "O.K"
835
  msgstr ""
836
 
837
+ #: lib/freemius/includes/i18n.php:160
838
+ msgctxt "exclamation"
839
+ msgid "Hey"
840
  msgstr ""
841
 
842
+ #: lib/freemius/includes/i18n.php:161
843
+ msgctxt "advance notice of something that will need attention."
844
+ msgid "Heads up"
845
  msgstr ""
846
 
847
+ #: lib/freemius/includes/i18n.php:165
848
+ msgid "Seems like you got the latest release."
849
  msgstr ""
850
 
851
+ #: lib/freemius/includes/i18n.php:166
852
+ msgid "You are all good!"
853
  msgstr ""
854
 
855
+ #: lib/freemius/includes/i18n.php:167
856
+ msgid ""
857
+ "Sorry, we could not complete the email update. Another user with the same "
858
+ "email is already registered."
859
  msgstr ""
860
 
861
+ #: lib/freemius/includes/i18n.php:168
862
+ #, php-format
863
  msgid ""
864
+ "If you would like to give up the ownership of the plugin's account to %s "
865
+ "click the Change Ownership button."
866
  msgstr ""
867
 
868
+ #: lib/freemius/includes/i18n.php:169
869
+ msgid ""
870
+ "Your email was successfully updated. You should receive an email with "
871
+ "confirmation instructions in few moments."
872
  msgstr ""
873
 
874
+ #: lib/freemius/includes/i18n.php:170
875
+ msgid "Your name was successfully updated."
876
  msgstr ""
877
 
878
+ #: lib/freemius/includes/i18n.php:171
879
+ #, php-format
880
+ msgid "You have successfully updated your %s."
881
  msgstr ""
882
 
883
+ #: lib/freemius/includes/i18n.php:172
884
+ msgid "Please provide your full name."
885
  msgstr ""
886
 
887
+ #: lib/freemius/includes/i18n.php:173
888
+ #, php-format
889
+ msgid ""
890
+ "Verification mail was just sent to %s. If you can't find it after 5 min, "
891
+ "please check your spam box."
892
  msgstr ""
893
 
894
+ #: lib/freemius/includes/i18n.php:174
895
+ #, php-format
896
+ msgid ""
897
+ "Just letting you know that the add-ons information of %s is being pulled "
898
+ "from external server."
899
  msgstr ""
900
 
901
+ #: lib/freemius/includes/i18n.php:175
902
+ msgid "No credit card required"
903
  msgstr ""
904
 
905
+ #: lib/freemius/includes/i18n.php:176
906
+ msgid "Premium plugin version was successfully activated."
 
 
907
  msgstr ""
908
 
909
+ #: lib/freemius/includes/i18n.php:177
910
+ #, php-format
911
+ msgid "The upgrade of %s was successfully completed."
912
  msgstr ""
913
 
914
+ #: lib/freemius/includes/i18n.php:178
915
+ #, php-format
916
+ msgid "Your account was successfully activated with the %s plan."
917
  msgstr ""
918
 
919
+ #: lib/freemius/includes/i18n.php:179
920
+ #, php-format
921
+ msgid "Download the latest %s version now"
922
  msgstr ""
923
 
924
+ #: lib/freemius/includes/i18n.php:180
925
+ msgid "Download the latest version now"
926
  msgstr ""
927
 
928
+ #: lib/freemius/includes/i18n.php:181
929
+ #, php-format
930
+ msgctxt "%s - product name, e.g. Facebook add-on was successfully..."
931
+ msgid "%s Add-on was successfully purchased."
932
  msgstr ""
933
 
934
+ #: lib/freemius/includes/i18n.php:182
935
+ #, php-format
936
+ msgid "Your %s Add-on plan was successfully upgraded."
937
  msgstr ""
938
 
939
+ #: lib/freemius/includes/i18n.php:183
940
+ msgid "Your email has been successfully verified - you are AWESOME!"
941
  msgstr ""
942
 
943
+ #: lib/freemius/includes/i18n.php:184
944
+ msgid "Your plan was successfully upgraded."
945
  msgstr ""
946
 
947
+ #: lib/freemius/includes/i18n.php:185
948
+ #, php-format
949
+ msgid "Your plan was successfully changed to %s."
950
+ msgstr ""
951
+
952
+ #: lib/freemius/includes/i18n.php:186
953
  msgid ""
954
+ "Your license has expired. You can still continue using the free plugin "
955
+ "forever."
 
 
956
  msgstr ""
957
 
958
+ #: lib/freemius/includes/i18n.php:187
959
+ msgid "Your trial has been successfully started."
960
  msgstr ""
961
 
962
+ #: lib/freemius/includes/i18n.php:188
963
+ msgid "Your license was successfully activated."
 
 
964
  msgstr ""
965
 
966
+ #: lib/freemius/includes/i18n.php:189
967
+ msgid "It looks like your site currently don't have an active license."
968
  msgstr ""
969
 
970
+ #: lib/freemius/includes/i18n.php:190
971
+ #, php-format
972
+ msgid "Your license was successfully deactivated, you are back to the %s plan."
 
973
  msgstr ""
974
 
975
+ #: lib/freemius/includes/i18n.php:191
976
+ msgid "It looks like the license deactivation failed."
977
  msgstr ""
978
 
979
+ #: lib/freemius/includes/i18n.php:192
980
+ msgid "It looks like the license could not be activated."
981
  msgstr ""
982
 
983
+ #: lib/freemius/includes/i18n.php:193
984
+ msgid "Error received from the server:"
985
  msgstr ""
986
 
987
+ #: lib/freemius/includes/i18n.php:194
988
  msgid ""
989
+ "Your trial has expired. You can still continue using all our free features."
 
 
990
  msgstr ""
991
 
992
+ #: lib/freemius/includes/i18n.php:195
993
+ #, php-format
994
+ msgid ""
995
+ "Your plan was successfully downgraded. Your %s plan license will expire in "
996
+ "%s."
997
  msgstr ""
998
 
999
+ #: lib/freemius/includes/i18n.php:196
1000
  msgid ""
1001
+ "Seems like we are having some temporary issue with your plan downgrade. "
1002
+ "Please try again in few minutes."
1003
  msgstr ""
1004
 
1005
+ #: lib/freemius/includes/i18n.php:197
1006
+ msgid ""
1007
+ "It looks like you are not in trial mode anymore so there's nothing to "
1008
+ "cancel :)"
1009
  msgstr ""
1010
 
1011
+ #: lib/freemius/includes/i18n.php:198
1012
+ #, php-format
1013
+ msgid "Your %s Plan trial was successfully cancelled."
 
1014
  msgstr ""
1015
 
1016
+ #: lib/freemius/includes/i18n.php:199
1017
+ #, php-format
1018
+ msgctxt "%s - numeric version number"
1019
+ msgid "Version %s was released."
1020
  msgstr ""
1021
 
1022
+ #: lib/freemius/includes/i18n.php:200
1023
+ #, php-format
1024
+ msgid "Please download %s."
 
1025
  msgstr ""
1026
 
1027
+ #: lib/freemius/includes/i18n.php:201
1028
+ #, php-format
1029
+ msgctxt "%s - plan name, as the latest professional version here"
1030
+ msgid "the latest %s version here"
1031
  msgstr ""
1032
 
1033
+ #: lib/freemius/includes/i18n.php:202
1034
+ #, php-format
1035
  msgid ""
1036
+ "How do you like %s so far? Test all our %s premium features with a %d-day "
1037
+ "free trial."
1038
  msgstr ""
1039
 
1040
+ #: lib/freemius/includes/i18n.php:203
1041
+ msgctxt "call to action"
1042
+ msgid "Start free trial"
1043
  msgstr ""
1044
 
1045
+ #: lib/freemius/includes/i18n.php:204
1046
  msgid ""
1047
+ "Seems like we are having some temporary issue with your trial cancellation. "
1048
+ "Please try again in few minutes."
1049
  msgstr ""
1050
 
1051
+ #: lib/freemius/includes/i18n.php:205
1052
+ #, php-format
1053
+ msgid "No commitment for %s days - cancel anytime!"
1054
  msgstr ""
1055
 
1056
+ #: lib/freemius/includes/i18n.php:206
1057
+ #, php-format
1058
  msgid ""
1059
+ "Your license has expired. You can still continue using all the %s features, "
1060
+ "but you'll need to renew your license to continue getting updates and "
1061
+ "support."
1062
  msgstr ""
1063
 
1064
+ #: lib/freemius/includes/i18n.php:207
1065
+ #, php-format
1066
+ msgid "Couldn't activate %s."
1067
  msgstr ""
1068
 
1069
+ #: lib/freemius/includes/i18n.php:208
1070
+ msgid "Please contact us with the following message:"
1071
+ msgstr ""
1072
+
1073
+ #: lib/freemius/includes/i18n.php:209
1074
  msgid ""
1075
+ "It looks like your plan did't change. If you did upgrade, it's probably an "
1076
+ "issue on our side - sorry."
1077
  msgstr ""
1078
 
1079
+ #: lib/freemius/includes/i18n.php:210
1080
+ msgid "Please contact us here"
1081
  msgstr ""
1082
 
1083
+ #: lib/freemius/includes/i18n.php:211
1084
+ #, php-format
1085
  msgid ""
1086
+ "I have upgraded my account but when I try to Sync the License, the plan "
1087
+ "remains %s."
1088
  msgstr ""
1089
 
1090
+ #: lib/freemius/includes/i18n.php:214
1091
+ msgid "From unknown reason, the API connectivity test fails."
1092
  msgstr ""
1093
 
1094
+ #: lib/freemius/includes/i18n.php:215
1095
+ msgid ""
1096
+ "We use PHP cURL library for the API calls, which is a very common library "
1097
+ "and usually installed out of the box. Unfortunately, cURL is not installed "
1098
+ "on your server."
1099
  msgstr ""
1100
 
1101
+ #: lib/freemius/includes/i18n.php:216
1102
+ msgid ""
1103
+ "From unknown reason, CloudFlare, the firewall we use, blocks the connection."
1104
  msgstr ""
1105
 
1106
+ #: lib/freemius/includes/i18n.php:217
1107
+ #, php-format
1108
+ msgctxt "as pluginX requires an access to our API"
1109
+ msgid "%s requires an access to our API."
1110
+ msgstr ""
1111
+
1112
+ #: lib/freemius/includes/i18n.php:218
1113
  msgid ""
1114
+ "It looks like your server is using Squid ACL (access control lists), which "
1115
+ "blocks the connection."
1116
  msgstr ""
1117
 
1118
+ #: lib/freemius/includes/i18n.php:219
1119
+ msgid "I don't know what is Squid or ACL, help me!"
1120
  msgstr ""
1121
 
1122
+ #: lib/freemius/includes/i18n.php:220 lib/freemius/includes/i18n.php:224
1123
+ #, php-format
1124
  msgid ""
1125
+ "We'll make sure to contact your hosting company and resolve the issue. You "
1126
+ "will get a follow-up email to %s once we have an update."
1127
  msgstr ""
1128
 
1129
+ #: lib/freemius/includes/i18n.php:221
1130
+ msgid "I'm a system administrator"
1131
  msgstr ""
1132
 
1133
+ #: lib/freemius/includes/i18n.php:222
1134
+ #, php-format
1135
  msgid ""
1136
+ "Great, please whitelist the following domains: %s. Once you done, deactivate "
1137
+ "the plugin and activate it again."
1138
  msgstr ""
1139
 
1140
+ #: lib/freemius/includes/i18n.php:223
1141
+ msgid "I don't know what is cURL or how to install it, help me!"
1142
  msgstr ""
1143
 
1144
+ #: lib/freemius/includes/i18n.php:225
1145
  msgid ""
1146
+ "Great, please install cURL and enable it in your php.ini file. To make sure "
1147
+ "it was successfully activated, use 'phpinfo()'. Once activated, deactivate "
1148
+ "the plugin and reactivate it back again."
1149
  msgstr ""
1150
 
1151
+ #: lib/freemius/includes/i18n.php:226
1152
+ msgid ""
1153
+ "We are sure it's an issue on our side and more than happy to resolve it for "
1154
+ "you ASAP if you give us a chance."
1155
  msgstr ""
1156
 
1157
+ #: lib/freemius/includes/i18n.php:227
1158
+ msgid "Yes - I'm giving you a chance to fix it"
1159
+ msgstr ""
1160
+
1161
+ #: lib/freemius/includes/i18n.php:228
1162
+ #, php-format
1163
  msgid ""
1164
+ "We will do our best to whitelist your server and resolve this issue ASAP. "
1165
+ "You will get a follow-up email to %s once we have an update."
1166
  msgstr ""
1167
 
1168
+ #: lib/freemius/includes/i18n.php:229
1169
+ msgid "Let's try your previous version"
1170
  msgstr ""
1171
 
1172
+ #: lib/freemius/includes/i18n.php:230
1173
+ msgid "Uninstall this version and install the previous one."
1174
  msgstr ""
1175
 
1176
+ #: lib/freemius/includes/i18n.php:231
1177
+ msgid "That's exhausting, please deactivate"
1178
  msgstr ""
1179
 
1180
+ #: lib/freemius/includes/i18n.php:232
1181
  msgid ""
1182
+ "We feel your frustration and sincerely apologize for the inconvenience. Hope "
1183
+ "to see you again in the future."
1184
  msgstr ""
1185
 
1186
+ #: lib/freemius/includes/i18n.php:233
1187
+ #, php-format
1188
+ msgid ""
1189
+ "Thank for giving us the chance to fix it! A message was just sent to our "
1190
+ "technical staff. We will get back to you as soon as we have an update to %s. "
1191
+ "Appreciate your patience."
1192
  msgstr ""
1193
 
1194
+ #: lib/freemius/includes/i18n.php:234
1195
+ #, php-format
1196
+ msgctxt "%1s - plugin title, %2s - API domain"
1197
  msgid ""
1198
+ "Your server is blocking the access to Freemius' API, which is crucial for "
1199
+ "%1s license synchronization. Please contact your host to whitelist %2s"
 
1200
  msgstr ""
1201
 
1202
+ #: lib/freemius/includes/i18n.php:235
1203
+ msgid ""
1204
+ "It seems like one of the authentication parameters is wrong. Update your "
1205
+ "Public Key, Secret Key & User ID, and try again."
1206
  msgstr ""
1207
 
1208
+ #: lib/freemius/includes/i18n.php:238
1209
+ #, php-format
1210
+ msgid ""
1211
+ "Please check your mailbox, you should receive an email via %s to confirm the "
1212
+ "ownership change. From security reasons, you must confirm the change within "
1213
+ "the next 15 min. If you cannot find the email, please check your spam folder."
1214
  msgstr ""
1215
 
1216
+ #: lib/freemius/includes/i18n.php:239
1217
+ #, php-format
1218
+ msgid ""
1219
+ "Thanks for confirming the ownership change. An email was just sent to %s for "
1220
+ "final approval."
1221
  msgstr ""
1222
 
1223
+ #: lib/freemius/includes/i18n.php:240
1224
+ #, php-format
1225
+ msgid "%s is the new owner of the account."
1226
  msgstr ""
1227
 
1228
+ #: lib/freemius/includes/i18n.php:242
1229
+ msgid "Freemius Debug"
1230
  msgstr ""
1231
 
1232
+ #: lib/freemius/includes/i18n.php:243
1233
+ #, php-format
1234
+ msgctxt "addonX cannot run without pluginY"
1235
+ msgid "%s cannot run without %s."
1236
  msgstr ""
1237
 
1238
+ #: lib/freemius/includes/i18n.php:244
1239
+ #, php-format
1240
+ msgctxt "addonX cannot run..."
1241
+ msgid "%s cannot run without the plugin."
1242
  msgstr ""
1243
 
1244
+ #: lib/freemius/includes/i18n.php:245
1245
+ #, php-format
1246
+ msgctxt "pluginX activation was successfully..."
1247
+ msgid "%s activation was successfully completed."
 
1248
  msgstr ""
1249
 
1250
+ #: lib/freemius/includes/i18n.php:246
1251
+ msgctxt "Plugin installer section title"
1252
+ msgid "Features & Pricing"
1253
  msgstr ""
1254
 
1255
+ #: lib/freemius/includes/fs-plugin-functions.php:87
1256
+ msgctxt "Plugin installer section title"
1257
+ msgid "Description"
 
1258
  msgstr ""
1259
 
1260
+ #: lib/freemius/includes/fs-plugin-functions.php:88
1261
+ msgctxt "Plugin installer section title"
1262
+ msgid "Installation"
1263
  msgstr ""
1264
 
1265
+ #: lib/freemius/includes/fs-plugin-functions.php:89
1266
+ msgctxt "Plugin installer section title"
1267
+ msgid "FAQ"
 
 
1268
  msgstr ""
1269
 
1270
+ #: lib/freemius/includes/fs-plugin-functions.php:90
1271
+ msgctxt "Plugin installer section title"
1272
+ msgid "Screenshots"
1273
  msgstr ""
1274
 
1275
+ #: lib/freemius/includes/fs-plugin-functions.php:91
1276
+ msgctxt "Plugin installer section title"
1277
+ msgid "Changelog"
 
 
1278
  msgstr ""
1279
 
1280
+ #: lib/freemius/includes/fs-plugin-functions.php:92
1281
+ msgctxt "Plugin installer section title"
1282
+ msgid "Reviews"
1283
  msgstr ""
1284
 
1285
+ #: lib/freemius/includes/fs-plugin-functions.php:93
1286
+ msgctxt "Plugin installer section title"
1287
+ msgid "Other Notes"
 
1288
  msgstr ""
1289
 
1290
+ #: lib/freemius/includes/fs-plugin-functions.php:116
1291
+ msgid "Plugin Install"
1292
  msgstr ""
1293
 
1294
+ #: lib/freemius/includes/fs-plugin-functions.php:249
1295
+ msgid "Version:"
 
 
 
1296
  msgstr ""
1297
 
1298
+ #: lib/freemius/includes/fs-plugin-functions.php:253
1299
+ msgid "Author:"
1300
  msgstr ""
1301
 
1302
+ #: lib/freemius/includes/fs-plugin-functions.php:257
1303
+ msgid "Last Updated:"
1304
  msgstr ""
1305
 
1306
+ #: lib/freemius/includes/fs-plugin-functions.php:259
1307
+ #, php-format
1308
+ msgid "%s ago"
1309
  msgstr ""
1310
 
1311
+ #: lib/freemius/includes/fs-plugin-functions.php:264
1312
+ msgid "Requires WordPress Version:"
 
 
1313
  msgstr ""
1314
 
1315
+ #: lib/freemius/includes/fs-plugin-functions.php:264
1316
+ #, php-format
1317
+ msgid "%s or higher"
1318
  msgstr ""
1319
 
1320
+ #: lib/freemius/includes/fs-plugin-functions.php:268
1321
+ msgid "Compatible up to:"
 
 
 
1322
  msgstr ""
1323
 
1324
+ #: lib/freemius/includes/fs-plugin-functions.php:272
1325
+ msgid "Downloaded:"
1326
  msgstr ""
1327
 
1328
+ #: lib/freemius/includes/fs-plugin-functions.php:272
1329
+ #, php-format
1330
+ msgid "%s time"
1331
+ msgid_plural "%s times"
1332
+ msgstr[0] ""
1333
+ msgstr[1] ""
1334
 
1335
+ #: lib/freemius/includes/fs-plugin-functions.php:277
1336
+ msgid "WordPress.org Plugin Page &#187;"
1337
  msgstr ""
1338
 
1339
+ #: lib/freemius/includes/fs-plugin-functions.php:282
1340
+ msgid "Plugin Homepage &#187;"
 
 
 
1341
  msgstr ""
1342
 
1343
+ #: lib/freemius/includes/fs-plugin-functions.php:287
1344
+ #: lib/freemius/includes/fs-plugin-functions.php:344
1345
+ msgid "Donate to this plugin &#187;"
1346
  msgstr ""
1347
 
1348
+ #: lib/freemius/includes/fs-plugin-functions.php:293
1349
+ msgid "Average Rating"
1350
  msgstr ""
1351
 
1352
+ #: lib/freemius/includes/fs-plugin-functions.php:299
1353
+ #, php-format
1354
+ msgid "(based on %s rating)"
1355
+ msgid_plural "(based on %s ratings)"
1356
+ msgstr[0] ""
1357
+ msgstr[1] ""
1358
+
1359
+ #: lib/freemius/includes/fs-plugin-functions.php:312
1360
+ #, php-format
1361
+ msgid "Click to see reviews that provided a rating of %d star"
1362
+ msgid_plural "Click to see reviews that provided a rating of %d stars"
1363
+ msgstr[0] ""
1364
+ msgstr[1] ""
1365
+
1366
+ #: lib/freemius/includes/fs-plugin-functions.php:312
1367
+ #, php-format
1368
+ msgid "%d star"
1369
+ msgid_plural "%d stars"
1370
+ msgstr[0] ""
1371
+ msgstr[1] ""
1372
+
1373
+ #: lib/freemius/includes/fs-plugin-functions.php:323
1374
+ msgid "Contributors"
1375
  msgstr ""
1376
 
1377
+ #: lib/freemius/includes/fs-plugin-functions.php:351
1378
+ #: lib/freemius/includes/fs-plugin-functions.php:353
1379
+ msgid "Warning:"
 
1380
  msgstr ""
1381
 
1382
+ #: lib/freemius/includes/fs-plugin-functions.php:351
1383
+ msgid "This plugin has not been tested with your current version of WordPress."
1384
  msgstr ""
1385
 
1386
+ #: lib/freemius/includes/fs-plugin-functions.php:353
1387
  msgid ""
1388
+ "This plugin has not been marked as compatible with your version of WordPress."
 
1389
  msgstr ""
1390
 
1391
+ #: lib/freemius/includes/fs-plugin-functions.php:399
1392
+ #, php-format
1393
+ msgid "Newer Version (%s) Installed"
1394
  msgstr ""
1395
 
1396
+ #: lib/freemius/includes/fs-plugin-functions.php:402
1397
+ msgid "Latest Version Installed"
 
 
1398
  msgstr ""
1399
 
1400
+ #: lib/freemius/templates/account.php:274
1401
+ msgctxt "verb"
1402
+ msgid "Edit"
1403
  msgstr ""
1404
 
1405
+ #: app/importers/RTMediaActivityUpgrade.php:20
1406
+ msgid "Media activity upgrade"
 
 
1407
  msgstr ""
1408
 
1409
+ #: app/importers/RTMediaMediaSizeImporter.php:25
1410
+ msgid "Media Size Import"
1411
  msgstr ""
1412
 
1413
+ #: app/importers/RTMediaMediaSizeImporter.php:66
1414
+ #: app/importers/RTMediaMigration.php:64 app/admin/RTMediaAdmin.php:1944
1415
+ msgid "Hide"
 
1416
  msgstr ""
1417
 
1418
+ #: app/importers/BPMediaAlbumimporter.php:71
1419
+ msgid "Warning!"
1420
  msgstr ""
1421
 
1422
+ #: app/importers/BPMediaAlbumimporter.php:71
1423
+ #, php-format
1424
  msgid ""
1425
+ "This import process is irreversible. Although everything is tested, please "
1426
+ "take a <a target=\"_blank\" href=\"http://codex.wordpress.org/"
1427
+ "WordPress_Backups\">backup of your database and files</a>, before "
1428
+ "proceeding. If you don't know your way around databases and files, consider "
1429
+ "<a target=\"_blank\" href=\"%s\">hiring us</a>, or another professional."
 
1430
  msgstr ""
1431
 
1432
+ #: app/importers/BPMediaAlbumimporter.php:72
1433
+ msgid ""
1434
+ "If you have set \"WP_DEBUG\" in you wp-config.php file, please make sure it "
1435
+ "is set to \"false\", so that it doesn't conflict with the import process."
1436
  msgstr ""
1437
 
1438
+ #: app/importers/BPMediaAlbumimporter.php:73
1439
+ msgid "I have taken a backup of the database and files of this site."
 
 
1440
  msgstr ""
1441
 
1442
+ #: app/importers/BPMediaAlbumimporter.php:75
1443
+ msgid "Start Import"
 
 
1444
  msgstr ""
1445
 
1446
+ #: app/importers/BPMediaAlbumimporter.php:90 app/main/RTMedia.php:562
1447
+ msgid "Media"
1448
  msgstr ""
1449
 
1450
+ #: app/importers/BPMediaAlbumimporter.php:110
1451
+ msgid "Comments"
1452
  msgstr ""
1453
 
1454
+ #: app/importers/BPMediaAlbumimporter.php:116
1455
+ msgid "Comments: 0/0 (No comments to import)"
1456
  msgstr ""
1457
 
1458
+ #: app/importers/BPMediaAlbumimporter.php:123
1459
+ msgid "User's Favorites"
1460
  msgstr ""
1461
 
1462
+ #: app/importers/BPMediaAlbumimporter.php:132
1463
+ msgid ""
1464
+ "BP-Album is active on your site and will cause problems with the import."
1465
  msgstr ""
1466
 
1467
+ #: app/importers/BPMediaAlbumimporter.php:133
1468
+ msgid "Click here to deactivate BP-Album and continue importing"
1469
  msgstr ""
1470
 
1471
+ #: app/importers/BPMediaAlbumimporter.php:139
1472
+ msgid ""
1473
+ "Some of the media failed to import. The file might be corrupt or deleted."
1474
  msgstr ""
1475
 
1476
+ #: app/importers/BPMediaAlbumimporter.php:140
1477
+ #, php-format
1478
+ msgid "The following %d BP Album Media id's could not be imported"
1479
  msgstr ""
1480
 
1481
+ #: app/importers/BPMediaAlbumimporter.php:149
1482
+ #, php-format
1483
+ msgid "I just imported bp-album to @rtMediaWP http://rt.cx/rtmedia on %s"
1484
  msgstr ""
1485
 
1486
+ #: app/importers/BPMediaAlbumimporter.php:150
1487
+ msgid "Congratulations!"
1488
  msgstr ""
1489
 
1490
+ #: app/importers/BPMediaAlbumimporter.php:150
1491
+ msgid "All media from BP Album has been imported."
1492
  msgstr ""
1493
 
1494
+ #: app/importers/BPMediaAlbumimporter.php:151
1495
+ msgid "Tweet this"
1496
  msgstr ""
1497
 
1498
+ #: app/importers/BPMediaAlbumimporter.php:155
1499
+ msgid ""
1500
+ "However, a lot of unnecessary files and a database table are still eating up "
1501
+ "your resources. If everything seems fine, you can clean this data up."
1502
  msgstr ""
1503
 
1504
+ #: app/importers/BPMediaAlbumimporter.php:158
1505
+ msgid "Clean up Now"
1506
  msgstr ""
1507
 
1508
+ #: app/importers/BPMediaAlbumimporter.php:161
1509
+ msgid "Clean up Later"
1510
  msgstr ""
1511
 
1512
+ #: app/importers/BPMediaAlbumimporter.php:166
1513
+ msgid "Why don't you try adding some instagram like effects to your images?"
1514
  msgstr ""
1515
 
1516
+ #: app/importers/BPMediaAlbumimporter.php:173
1517
+ msgid ""
1518
+ "BuddyPress Media Instagram adds Instagram like filters to images uploaded "
1519
+ "with BuddyPress Media."
1520
  msgstr ""
1521
 
1522
+ #: app/importers/BPMediaAlbumimporter.php:174
1523
+ msgid "Important"
1524
  msgstr ""
1525
 
1526
+ #: app/importers/BPMediaAlbumimporter.php:174
1527
  msgid ""
1528
+ "You need to have ImageMagick installed on your server for this addon to work."
 
1529
  msgstr ""
1530
 
1531
+ #: app/importers/BPMediaAlbumimporter.php:178 app/helper/RTMediaAddon.php:606
1532
+ #: app/helper/RTMediaThemes.php:155 app/helper/RTMediaThemes.php:183
1533
+ #: app/helper/RTMediaThemes.php:280 app/helper/RTMediaThemes.php:308
1534
+ msgid "Buy Now"
1535
  msgstr ""
1536
 
1537
+ #: app/importers/BPMediaAlbumimporter.php:179 app/helper/RTMediaAddon.php:635
1538
+ #: app/helper/RTMediaThemes.php:154 app/helper/RTMediaThemes.php:182
1539
+ #: app/helper/RTMediaThemes.php:279 app/helper/RTMediaThemes.php:307
1540
+ msgid "Live Demo"
1541
  msgstr ""
1542
 
1543
+ #: app/importers/BPMediaAlbumimporter.php:184
1544
+ msgid ""
1545
+ "Looks like you don't use BP Album. Is there any other BuddyPress Plugin you "
1546
+ "want an importer for?"
1547
  msgstr ""
1548
 
1549
+ #: app/importers/BPMediaAlbumimporter.php:185
1550
+ #, php-format
1551
+ msgid "<a href=\"%s\">Create an issue</a> on GitHub requesting the same."
1552
  msgstr ""
1553
 
1554
+ #: app/importers/RTMediaMigration.php:64
1555
+ msgid "Please Migrate your Database"
1556
  msgstr ""
1557
 
1558
+ #: app/importers/RTMediaMigration.php:64
1559
+ msgid "Click Here"
1560
  msgstr ""
1561
 
1562
+ #: app/importers/RTMediaMigration.php:83 app/helper/RTMediaSupport.php:66
1563
+ #: app/helper/RTMediaSupport.php:67
1564
+ msgid "Migration"
1565
  msgstr ""
1566
 
1567
+ #: app/importers/RTMediaMigration.php:375
1568
+ msgid ""
1569
+ "Please Backup your <strong>DATABASE</strong> and <strong>UPLOAD</strong> "
1570
+ "folder before Migration."
1571
  msgstr ""
1572
 
1573
+ #: app/importers/RTMediaMigration.php:383
1574
+ msgid "rtMedia Migration"
 
 
1575
  msgstr ""
1576
 
1577
+ #: app/importers/RTMediaMigration.php:385
1578
+ msgid "It will migrate following things"
1579
  msgstr ""
1580
 
1581
+ #: app/importers/RTMediaMigration.php:453
1582
+ msgid "Error During Migration, Please Refresh Page then try again"
1583
  msgstr ""
1584
 
1585
+ #: app/importers/RTMediaMigration.php:473
1586
+ msgid "Start"
 
 
 
 
1587
  msgstr ""
1588
 
1589
+ #: app/importers/RTMediaMigration.php:1024
1590
+ msgid " day"
 
 
 
1591
  msgstr ""
1592
 
1593
+ #: app/importers/RTMediaMigration.php:1028
1594
+ msgid " hour"
 
1595
  msgstr ""
1596
 
1597
+ #: app/importers/RTMediaMigration.php:1032
1598
+ msgid " minute"
 
1599
  msgstr ""
1600
 
1601
+ #: app/importers/RTMediaMigration.php:1036
1602
+ msgid " second"
1603
  msgstr ""
1604
 
1605
+ #: app/importers/RTMediaMigration.php:1042
1606
+ msgid "No time remaining."
1607
  msgstr ""
1608
 
1609
+ #: app/services/RTMediaEncoding.php:158
1610
+ msgid "rtMedia Encoding: Nearing quota limit."
1611
  msgstr ""
1612
 
1613
+ #: app/services/RTMediaEncoding.php:159
1614
+ #, php-format
1615
+ msgid ""
1616
+ "<p>You are nearing the quota limit for your rtMedia encoding service.</"
1617
+ "p><p>Following are the details:</p><p><strong>Used:</strong> %s</"
1618
+ "p><p><strong>Remaining</strong>: %s</p><p><strong>Total:</strong> %s</p>"
1619
  msgstr ""
1620
 
1621
+ #: app/services/RTMediaEncoding.php:173
1622
+ msgid "rtMedia Encoding: Usage quota over."
1623
  msgstr ""
1624
 
1625
+ #: app/services/RTMediaEncoding.php:174
1626
+ #, php-format
1627
+ msgid ""
1628
+ "<p>Your usage quota is over. Upgrade your plan</p><p>Following are the "
1629
+ "details:</p><p><strong>Used:</strong> %s</p><p><strong>Remaining</strong>: "
1630
+ "%s</p><p><strong>Total:</strong> %s</p>"
1631
  msgstr ""
1632
 
1633
+ #: app/services/RTMediaEncoding.php:237
1634
+ #, php-format
1635
+ msgid "You have successfully subscribed for the <strong>%s</strong> plan"
1636
  msgstr ""
1637
 
1638
+ #: app/services/RTMediaEncoding.php:249
1639
+ msgid "Unsubscribe"
1640
  msgstr ""
1641
 
1642
+ #: app/services/RTMediaEncoding.php:251
1643
+ msgid ""
1644
+ "Just to improve our service we would like to know the reason for you to "
1645
+ "leave us."
1646
  msgstr ""
1647
 
1648
+ #: app/services/RTMediaEncoding.php:300 app/services/RTMediaEncoding.php:402
1649
+ msgid "Current Plan"
1650
  msgstr ""
1651
 
1652
+ #: app/services/RTMediaEncoding.php:300
1653
+ msgid "Unsubscribed"
1654
  msgstr ""
1655
 
1656
+ #: app/services/RTMediaEncoding.php:302
1657
+ msgid "Used"
1658
  msgstr ""
1659
 
1660
+ #: app/services/RTMediaEncoding.php:304
1661
+ msgid "Remaining"
1662
  msgstr ""
1663
 
1664
+ #: app/services/RTMediaEncoding.php:306
1665
+ msgid "Total"
 
 
 
 
1666
  msgstr ""
1667
 
1668
+ #: app/services/RTMediaEncoding.php:310
1669
+ msgid "Your usage limit has been reached. Upgrade your plan."
 
 
 
1670
  msgstr ""
1671
 
1672
+ #: app/services/RTMediaEncoding.php:312
1673
+ msgid "Your API key is not valid or is expired."
1674
  msgstr ""
1675
 
1676
+ #: app/services/RTMediaEncoding.php:314
1677
+ msgid "Encoding Usage"
1678
  msgstr ""
1679
 
1680
+ #: app/services/RTMediaEncoding.php:320
1681
+ msgid "Audio/Video encoding service"
1682
  msgstr ""
1683
 
1684
+ #: app/services/RTMediaEncoding.php:322
1685
+ msgid "rtMedia team has started offering an audio/video encoding service."
1686
  msgstr ""
1687
 
1688
+ #: app/services/RTMediaEncoding.php:325
1689
+ msgid "Enter API KEY"
1690
  msgstr ""
1691
 
1692
+ #: app/services/RTMediaEncoding.php:327
1693
+ msgid "Save Key"
1694
  msgstr ""
1695
 
1696
+ #: app/services/RTMediaEncoding.php:348
1697
+ msgid "Feature\\Plan"
 
1698
  msgstr ""
1699
 
1700
+ #: app/services/RTMediaEncoding.php:350
1701
+ msgid "Silver"
1702
  msgstr ""
1703
 
1704
+ #: app/services/RTMediaEncoding.php:351
1705
+ msgid "Gold"
1706
  msgstr ""
1707
 
1708
+ #: app/services/RTMediaEncoding.php:352
1709
+ msgid "Platinum"
1710
  msgstr ""
1711
 
1712
+ #: app/services/RTMediaEncoding.php:358
1713
+ msgid "File Size Limit"
1714
  msgstr ""
1715
 
1716
+ #: app/services/RTMediaEncoding.php:363
1717
+ msgid "Bandwidth (monthly)"
1718
  msgstr ""
1719
 
1720
+ #: app/services/RTMediaEncoding.php:370
1721
+ msgid "Overage Bandwidth"
1722
  msgstr ""
1723
 
1724
+ #: app/services/RTMediaEncoding.php:371 app/services/RTMediaEncoding.php:378
1725
+ #: app/services/RTMediaEncoding.php:383
1726
+ msgid "Not Available"
1727
  msgstr ""
1728
 
1729
+ #: app/services/RTMediaEncoding.php:377
1730
+ msgid "Amazon S3 Support"
1731
  msgstr ""
1732
 
1733
+ #: app/services/RTMediaEncoding.php:379 app/services/RTMediaEncoding.php:384
1734
+ #: app/services/RTMediaEncoding.php:388
1735
+ msgid "Coming Soon"
1736
  msgstr ""
1737
 
1738
+ #: app/services/RTMediaEncoding.php:382
1739
+ msgid "HD Profile"
 
 
1740
  msgstr ""
1741
 
1742
+ #: app/services/RTMediaEncoding.php:387
1743
+ msgid "Webcam Recording"
1744
  msgstr ""
1745
 
1746
+ #: app/services/RTMediaEncoding.php:393
1747
+ msgid "$9/month"
1748
  msgstr ""
1749
 
1750
+ #: app/services/RTMediaEncoding.php:394
1751
+ msgid "$99/month"
1752
  msgstr ""
1753
 
1754
+ #: app/services/RTMediaEncoding.php:395
1755
+ msgid "$999/month"
1756
  msgstr ""
1757
 
1758
+ #: app/services/RTMediaEncoding.php:406
1759
+ msgid "Try Now"
 
 
 
1760
  msgstr ""
1761
 
1762
+ #: app/services/RTMediaEncoding.php:560
1763
+ msgid "Could not read file."
1764
  msgstr ""
1765
 
1766
+ #: app/services/RTMediaEncoding.php:564
1767
  msgid ""
1768
+ "Something went wrong. The required attachment id does not exists. It must "
1769
+ "have been deleted."
1770
  msgstr ""
1771
 
1772
+ #: app/services/RTMediaEncoding.php:579
1773
+ msgid "rtMedia Encoding: Download Failed"
1774
  msgstr ""
1775
 
1776
+ #: app/services/RTMediaEncoding.php:580
1777
+ #, php-format
1778
  msgid ""
1779
+ "<p><a href=\"%s\">Media</a> was successfully encoded but there was an error "
1780
+ "while downloading:</p>\n"
1781
+ " <p><code>%s</code></p>\n"
1782
+ " <p>You can <a href=\"%s\">retry the download</a>.</p>"
1783
  msgstr ""
1784
 
1785
+ #: app/services/RTMediaEncoding.php:594
1786
+ msgid "Done"
1787
  msgstr ""
1788
 
1789
+ #: app/services/RTMediaEncoding.php:619 app/services/RTMediaEncoding.php:641
1790
+ msgid "Something went wrong please try again."
1791
  msgstr ""
1792
 
1793
+ #: app/services/RTMediaEncoding.php:638
1794
+ msgid "Your subscription was cancelled successfully"
1795
  msgstr ""
1796
 
1797
+ #: app/services/RTMediaEncoding.php:650
1798
+ msgid "Please enter the api key."
1799
  msgstr ""
1800
 
1801
+ #: app/services/RTMediaEncoding.php:657
1802
+ msgid "Encoding disabled successfully."
1803
  msgstr ""
1804
 
1805
+ #: app/services/RTMediaEncoding.php:663
1806
+ msgid "Encoding enabled successfully."
1807
  msgstr ""
1808
 
1809
+ #: app/admin/RTMediaAdmin.php:127
1810
+ #, php-format
1811
+ msgid "View &#8220;%s&#8221;"
1812
  msgstr ""
1813
 
1814
+ #: app/admin/RTMediaAdmin.php:127
1815
+ msgid "View"
1816
  msgstr ""
1817
 
1818
+ #: app/admin/RTMediaAdmin.php:369
1819
+ msgid " You must"
 
 
1820
  msgstr ""
1821
 
1822
+ #: app/admin/RTMediaAdmin.php:369
1823
+ msgid "update permalink structure"
1824
  msgstr ""
1825
 
1826
+ #: app/admin/RTMediaAdmin.php:369
1827
+ msgid "to something other than the default for it to work."
1828
  msgstr ""
1829
 
1830
+ #: app/admin/RTMediaAdmin.php:395
1831
+ msgid "rtMedia:"
 
 
 
 
1832
  msgstr ""
1833
 
1834
+ #: app/admin/RTMediaAdmin.php:395
 
 
 
 
1835
  msgid ""
1836
+ "Please update all premium add-ons that you have purchased from rtCamp from"
 
 
1837
  msgstr ""
1838
 
1839
+ #: app/admin/RTMediaAdmin.php:395
1840
+ msgid "your account"
1841
  msgstr ""
1842
 
1843
+ #: app/admin/RTMediaAdmin.php:508
1844
+ msgid "rtMedia Pro is released"
1845
  msgstr ""
1846
 
1847
+ #: app/admin/RTMediaAdmin.php:529
1848
+ msgid "Media Stats"
 
 
 
 
1849
  msgstr ""
1850
 
1851
+ #: app/admin/RTMediaAdmin.php:556
1852
+ msgid "Usage Stats"
1853
  msgstr ""
1854
 
1855
+ #: app/admin/RTMediaAdmin.php:565
1856
+ msgid "Total "
 
 
 
1857
  msgstr ""
1858
 
1859
+ #: app/admin/RTMediaAdmin.php:573
1860
+ msgid "With Media"
 
 
1861
  msgstr ""
1862
 
1863
+ #: app/admin/RTMediaAdmin.php:581
1864
+ msgid "Comments "
1865
  msgstr ""
1866
 
1867
+ #: app/admin/RTMediaAdmin.php:589
1868
+ #: app/main/controllers/media/RTMediaLike.php:19
1869
+ msgid "Likes"
 
1870
  msgstr ""
1871
 
1872
+ #: app/admin/RTMediaAdmin.php:600
1873
+ msgid "rtMedia Links:"
1874
  msgstr ""
1875
 
1876
+ #: app/admin/RTMediaAdmin.php:601
1877
+ msgid "Homepage"
 
 
1878
  msgstr ""
1879
 
1880
+ #: app/admin/RTMediaAdmin.php:602
1881
+ msgid "Free Support"
1882
  msgstr ""
1883
 
1884
+ #: app/admin/RTMediaAdmin.php:603
1885
+ msgid "Premium Addons"
1886
  msgstr ""
1887
 
1888
+ #: app/admin/RTMediaAdmin.php:619
1889
+ msgid "Right Now in rtMedia"
1890
  msgstr ""
1891
 
1892
+ #: app/admin/RTMediaAdmin.php:673 app/admin/RTMediaAdmin.php:882
1893
+ msgid "Regenerate Thumbnail"
1894
  msgstr ""
1895
 
1896
+ #: app/admin/RTMediaAdmin.php:714 app/admin/RTMediaAdmin.php:1368
1897
+ #: app/admin/RTMediaAdmin.php:1369
1898
+ msgid "rtMedia"
1899
  msgstr ""
1900
 
1901
+ #: app/admin/RTMediaAdmin.php:721 app/admin/RTMediaAdmin.php:724
1902
+ #: app/admin/RTMediaAdmin.php:870 app/admin/RTMediaAdmin.php:1398
1903
+ msgid "Settings"
 
1904
  msgstr ""
1905
 
1906
+ #: app/admin/RTMediaAdmin.php:732 app/admin/RTMediaAdmin.php:735
1907
+ #: app/admin/RTMediaAdmin.php:871 app/admin/RTMediaAdmin.php:1402
1908
+ msgid "Addons"
1909
  msgstr ""
1910
 
1911
+ #: app/admin/RTMediaAdmin.php:754 app/admin/RTMediaAdmin.php:757
1912
+ #: app/admin/RTMediaAdmin.php:873 app/admin/RTMediaAdmin.php:1406
1913
+ msgid "Themes"
 
 
 
 
 
1914
  msgstr ""
1915
 
1916
+ #: app/admin/RTMediaAdmin.php:765 app/admin/RTMediaAdmin.php:768
1917
+ #: app/admin/RTMediaAdmin.php:874 app/admin/RTMediaAdmin.php:1410
1918
+ msgid "Hire Us"
 
1919
  msgstr ""
1920
 
1921
+ #: app/admin/RTMediaAdmin.php:777 app/admin/RTMediaAdmin.php:780
1922
+ #: app/admin/RTMediaAdmin.php:876 app/admin/RTMediaAdmin.php:1422
1923
+ msgid "Licenses"
1924
  msgstr ""
1925
 
1926
+ #: app/admin/RTMediaAdmin.php:831
1927
+ msgid "ON"
1928
  msgstr ""
1929
 
1930
+ #: app/admin/RTMediaAdmin.php:832
1931
+ msgid "OFF"
1932
  msgstr ""
1933
 
1934
+ #: app/admin/RTMediaAdmin.php:838
1935
+ msgid "Please do not refresh this page."
1936
  msgstr ""
1937
 
1938
+ #: app/admin/RTMediaAdmin.php:839
1939
+ msgid ""
1940
+ "Something went wrong. Please <a href onclick=\"location.reload();\">refresh</"
1941
+ "a> page."
1942
  msgstr ""
1943
 
1944
+ #: app/admin/RTMediaAdmin.php:840
1945
+ msgid "This will subscribe you to the free plan."
1946
  msgstr ""
1947
 
1948
+ #: app/admin/RTMediaAdmin.php:841
1949
+ msgid "Are you sure you want to disable the encoding service?"
1950
  msgstr ""
1951
 
1952
+ #: app/admin/RTMediaAdmin.php:842
1953
+ msgid "Are you sure you want to enable the encoding service?"
1954
  msgstr ""
1955
 
1956
+ #: app/admin/RTMediaAdmin.php:882
1957
+ msgid "Regen. Thumbnail "
1958
  msgstr ""
1959
 
1960
+ #: app/admin/RTMediaAdmin.php:900 app/admin/RTMediaAdmin.php:1879
1961
+ msgid "Regenerate Video Thumbnails"
1962
  msgstr ""
1963
 
1964
+ #: app/admin/RTMediaAdmin.php:918
1965
+ msgid "Regenerate Pending Thumbnails"
1966
  msgstr ""
1967
 
1968
+ #: app/admin/RTMediaAdmin.php:928
1969
+ msgid "Total Videos"
1970
  msgstr ""
1971
 
1972
+ #: app/admin/RTMediaAdmin.php:931
1973
+ msgid "Sent of regenerate thumbails"
1974
  msgstr ""
1975
 
1976
+ #: app/admin/RTMediaAdmin.php:933
1977
+ msgid "Fail to regenerate thumbails"
1978
  msgstr ""
1979
 
1980
+ #: app/admin/RTMediaAdmin.php:972
1981
+ msgid "Regenerate Video Thumbnails Done"
1982
  msgstr ""
1983
 
1984
+ #: app/admin/RTMediaAdmin.php:1016
1985
+ #, php-format
1986
  msgid ""
1987
+ "You have %s videos without thumbnails. Click <a href='%s'> here </a> to "
1988
+ "generate thumbnails. <a href='#' onclick='rtmedia_hide_video_thumb_notice()' "
1989
+ "style='float:right'>Hide</a>"
1990
  msgstr ""
1991
 
1992
+ #: app/admin/RTMediaAdmin.php:1094
1993
+ msgid "not a video ..."
1994
  msgstr ""
1995
 
1996
+ #: app/admin/RTMediaAdmin.php:1259
1997
+ msgid "Empowering The Web With WordPress"
1998
  msgstr ""
1999
 
2000
+ #: app/admin/RTMediaAdmin.php:1279
2001
+ msgid "Settings saved successfully!"
2002
  msgstr ""
2003
 
2004
+ #: app/admin/RTMediaAdmin.php:1282 app/admin/RTMediaAdmin.php:1305
2005
+ msgid "Save Settings"
 
 
2006
  msgstr ""
2007
 
2008
+ #: app/admin/RTMediaAdmin.php:1504 app/admin/RTMediaAdmin.php:1505
2009
+ msgid "Display"
2010
  msgstr ""
2011
 
2012
+ #: app/admin/RTMediaAdmin.php:1513
2013
+ msgid "rtMedia BuddyPress"
 
 
2014
  msgstr ""
2015
 
2016
+ #: app/admin/RTMediaAdmin.php:1514
2017
+ msgid "BuddyPress"
 
 
2018
  msgstr ""
2019
 
2020
+ #: app/admin/RTMediaAdmin.php:1522
2021
+ msgid "rtMedia Types"
2022
  msgstr ""
2023
 
2024
+ #: app/admin/RTMediaAdmin.php:1523
2025
+ msgid "Types"
2026
  msgstr ""
2027
 
2028
+ #: app/admin/RTMediaAdmin.php:1530
2029
+ msgid "rtMedia Sizes"
2030
  msgstr ""
2031
 
2032
+ #: app/admin/RTMediaAdmin.php:1531
2033
+ msgid "Media Sizes"
2034
  msgstr ""
2035
 
2036
+ #: app/admin/RTMediaAdmin.php:1538
2037
+ msgid "rtMedia Privacy"
2038
  msgstr ""
2039
 
2040
+ #: app/admin/RTMediaAdmin.php:1539
2041
+ #: app/main/controllers/privacy/RTMediaPrivacy.php:395
2042
+ msgid "Privacy"
 
2043
  msgstr ""
2044
 
2045
+ #: app/admin/RTMediaAdmin.php:1545
2046
+ msgid "rtMedia Custom CSS"
2047
  msgstr ""
2048
 
2049
+ #: app/admin/RTMediaAdmin.php:1546
2050
+ msgid "Custom CSS"
2051
  msgstr ""
2052
 
2053
+ #: app/admin/RTMediaAdmin.php:1555 app/admin/RTMediaAdmin.php:1556
2054
+ msgid "Other Settings"
2055
  msgstr ""
2056
 
2057
+ #: app/admin/RTMediaAdmin.php:1651
2058
+ #, php-format
2059
+ msgid "I use @rtMediaWP http://rt.cx/rtmedia on %s"
2060
  msgstr ""
2061
 
2062
+ #: app/admin/RTMediaAdmin.php:1653
2063
+ msgid "Post to Twitter Now"
2064
  msgstr ""
2065
 
2066
+ #: app/admin/RTMediaAdmin.php:1653
2067
+ msgid "Post to Twitter"
2068
  msgstr ""
2069
 
2070
+ #: app/admin/RTMediaAdmin.php:1654
2071
+ msgid "Share on Facebook Now"
2072
  msgstr ""
2073
 
2074
+ #: app/admin/RTMediaAdmin.php:1654
2075
+ msgid "Share on Facebook"
2076
  msgstr ""
2077
 
2078
+ #: app/admin/RTMediaAdmin.php:1655
2079
+ msgid "Rate rtMedia on Wordpress.org"
2080
  msgstr ""
2081
 
2082
+ #: app/admin/RTMediaAdmin.php:1655
2083
+ msgid "Rate on Wordpress.org"
2084
  msgstr ""
2085
 
2086
+ #: app/admin/RTMediaAdmin.php:1656
2087
+ msgid "Subscribe to our Feeds"
2088
  msgstr ""
2089
 
2090
+ #: app/admin/RTMediaAdmin.php:1659
2091
+ msgid "Spread the Word"
2092
  msgstr ""
2093
 
2094
+ #: app/admin/RTMediaAdmin.php:1665 app/admin/RTMediaAdmin.php:1672
2095
+ msgid "Subscribe"
2096
  msgstr ""
2097
 
2098
+ #: app/admin/RTMediaAdmin.php:1694
2099
+ msgid "Thank you for your time."
2100
  msgstr ""
2101
 
2102
+ #: app/admin/RTMediaAdmin.php:1706
2103
+ msgid "Premium Add-ons"
2104
  msgstr ""
2105
 
2106
+ #: app/admin/RTMediaAdmin.php:1722
2107
+ #, php-format
2108
+ msgid ""
2109
+ "You have images enabled on rtMedia but your network allowed filetypes do not "
2110
+ "permit uploading of %s. Click <a href=\"%s\">here</a> to change your "
2111
+ "settings manually."
2112
  msgstr ""
2113
 
2114
+ #: app/admin/RTMediaAdmin.php:1723 app/admin/RTMediaAdmin.php:1734
2115
+ #: app/admin/RTMediaAdmin.php:1743
2116
+ msgid "Recommended"
2117
  msgstr ""
2118
 
2119
+ #: app/admin/RTMediaAdmin.php:1723 app/admin/RTMediaAdmin.php:1734
2120
+ #: app/admin/RTMediaAdmin.php:1743
2121
+ msgid "Update Network Settings Automatically"
2122
  msgstr ""
2123
 
2124
+ #: app/admin/RTMediaAdmin.php:1733
2125
+ #, php-format
2126
+ msgid ""
2127
+ "You have video enabled on BuddyPress Media but your network allowed "
2128
+ "filetypes do not permit uploading of mp4. Click <a href=\"%s\">here</a> to "
2129
+ "change your settings manually."
2130
  msgstr ""
2131
 
2132
+ #: app/admin/RTMediaAdmin.php:1742
2133
+ #, php-format
2134
+ msgid ""
2135
+ "You have audio enabled on BuddyPress Media but your network allowed "
2136
+ "filetypes do not permit uploading of mp3. Click <a href=\"%s\">here</a> to "
2137
+ "change your settings manually."
2138
  msgstr ""
2139
 
2140
+ #: app/admin/RTMediaAdmin.php:1757
2141
+ msgid "Network settings updated successfully."
 
2142
  msgstr ""
2143
 
2144
+ #: app/admin/RTMediaAdmin.php:1863
2145
+ msgid "Video is sent to generate thumbnails."
 
 
2146
  msgstr ""
2147
 
2148
+ #: app/admin/RTMediaAdmin.php:1865
2149
+ msgid "Video cannot be sent to generate thumbnails."
2150
  msgstr ""
2151
 
2152
+ #: app/admin/RTMediaAdmin.php:1944
2153
+ msgid ""
2154
+ "Please update rtMedia template files if you have overridden the default "
2155
+ "rtMedia templates in your theme. If not, you can ignore and hide this notice."
2156
  msgstr ""
2157
 
2158
+ #: app/admin/RTMediaFormHandler.php:65 app/admin/RTMediaFormHandler.php:107
2159
+ #: app/admin/RTMediaFormHandler.php:202 app/admin/RTMediaFormHandler.php:237
2160
+ msgid "Please provide a \"value\" in the argument."
2161
  msgstr ""
2162
 
2163
+ #: app/admin/RTMediaFormHandler.php:150
2164
+ msgid "Need to specify atleast two radios, else use a checkbox instead"
2165
  msgstr ""
2166
 
2167
+ #: app/admin/RTMediaFormHandler.php:285 templates/media/album-gallery.php:56
2168
+ #: templates/media/media-gallery.php:65
2169
+ msgid "Load More"
2170
  msgstr ""
2171
 
2172
+ #: app/admin/RTMediaFormHandler.php:286
2173
+ msgid "Pagination"
2174
  msgstr ""
2175
 
2176
+ #: app/admin/RTMediaFormHandler.php:298
2177
+ msgid "Allow user to comment on uploaded media"
2178
  msgstr ""
2179
 
2180
+ #: app/admin/RTMediaFormHandler.php:303
2181
+ msgid ""
2182
+ "This will display the comment form and comment listing on single media pages "
2183
+ "as well as inside lightbox (if lightbox is enabled)."
2184
  msgstr ""
2185
 
2186
+ #: app/admin/RTMediaFormHandler.php:308
2187
+ msgid "Use lightbox to display media"
2188
  msgstr ""
2189
 
2190
+ #: app/admin/RTMediaFormHandler.php:313
2191
+ msgid "View single media in facebook style lightbox."
2192
  msgstr ""
2193
 
2194
+ #: app/admin/RTMediaFormHandler.php:318
2195
+ msgid "Number of media per page"
2196
  msgstr ""
2197
 
2198
+ #: app/admin/RTMediaFormHandler.php:324
2199
+ msgid "Number of media items you want to show per page on front end."
2200
  msgstr ""
2201
 
2202
+ #: app/admin/RTMediaFormHandler.php:330
2203
+ msgid "Media display pagination option"
2204
  msgstr ""
2205
 
2206
+ #: app/admin/RTMediaFormHandler.php:336
2207
+ msgid "Choose whether you want the load more button or pagination buttons."
2208
  msgstr ""
2209
 
2210
+ #: app/admin/RTMediaFormHandler.php:341
2211
+ msgid "Enable"
2212
  msgstr ""
2213
 
2214
+ #: app/admin/RTMediaFormHandler.php:341
2215
+ msgid "Cascading grid layout"
2216
  msgstr ""
2217
 
2218
+ #: app/admin/RTMediaFormHandler.php:346
2219
+ msgid "If you enable masonry view, it is advisable to"
2220
  msgstr ""
2221
 
2222
+ #: app/admin/RTMediaFormHandler.php:346
2223
+ msgid "for masonry view."
2224
  msgstr ""
2225
 
2226
+ #: app/admin/RTMediaFormHandler.php:350
2227
+ msgid "You might need to"
2228
  msgstr ""
2229
 
2230
+ #: app/admin/RTMediaFormHandler.php:350
2231
+ msgid "change thumbnail size"
2232
  msgstr ""
2233
 
2234
+ #: app/admin/RTMediaFormHandler.php:350
2235
+ msgid "and uncheck the crop box for thumbnails."
2236
  msgstr ""
2237
 
2238
+ #: app/admin/RTMediaFormHandler.php:350
2239
+ msgid ""
2240
+ "To set gallery for fixed width, set image height to 0 and width as per your "
2241
+ "requirement and vice-versa."
2242
  msgstr ""
2243
 
2244
+ #: app/admin/RTMediaFormHandler.php:353
2245
+ msgid "Enable Direct Upload"
2246
  msgstr ""
2247
 
2248
+ #: app/admin/RTMediaFormHandler.php:358
2249
+ msgid "Uploading media directly as soon as it gets selected."
2250
  msgstr ""
2251
 
2252
+ #: app/admin/RTMediaFormHandler.php:384
2253
+ msgid "Single Media View"
2254
  msgstr ""
2255
 
2256
+ #: app/admin/RTMediaFormHandler.php:385
2257
+ msgid "List Media View"
 
 
 
 
2258
  msgstr ""
2259
 
2260
+ #: app/admin/RTMediaFormHandler.php:386
2261
+ msgid "Masonry View"
 
 
 
 
 
2262
  msgstr ""
2263
 
2264
+ #: app/admin/RTMediaFormHandler.php:387
2265
+ msgid "Direct Upload"
2266
  msgstr ""
2267
 
2268
+ #: app/admin/RTMediaFormHandler.php:405
2269
+ msgid "Allow usage data tracking"
2270
  msgstr ""
2271
 
2272
+ #: app/admin/RTMediaFormHandler.php:410
2273
+ msgid ""
2274
+ "To make rtMedia better compatible with your sites, you can help the rtMedia "
2275
+ "team learn what themes and plugins you are using. No private information "
2276
+ "about your setup will be sent during tracking."
2277
  msgstr ""
2278
 
2279
+ #: app/admin/RTMediaFormHandler.php:414
2280
+ msgid "Admin bar menu integration"
2281
  msgstr ""
2282
 
2283
+ #: app/admin/RTMediaFormHandler.php:419
2284
+ msgid ""
2285
+ "Add rtMedia menu to WordPress admin bar for easy access to settings and "
2286
+ "moderation page (if enabled)."
2287
  msgstr ""
2288
 
2289
+ #: app/admin/RTMediaFormHandler.php:424
2290
+ msgid "Add a link to rtMedia in footer"
2291
  msgstr ""
2292
 
2293
+ #: app/admin/RTMediaFormHandler.php:429
2294
+ msgid "Help us promote rtMedia."
2295
  msgstr ""
2296
 
2297
+ #: app/admin/RTMediaFormHandler.php:434
2298
+ msgid "Also add my affiliate-id to rtMedia footer link"
2299
  msgstr ""
2300
 
2301
+ #: app/admin/RTMediaFormHandler.php:439
2302
+ msgid ""
2303
+ "Add your affiliate-id along with footer link and get rewarded by our "
2304
+ "affiliation program."
2305
  msgstr ""
2306
 
2307
+ #: app/admin/RTMediaFormHandler.php:443
2308
+ msgid "Signup for"
2309
  msgstr ""
2310
 
2311
+ #: app/admin/RTMediaFormHandler.php:443
2312
+ msgid "affiliate program"
2313
  msgstr ""
2314
 
2315
+ #: app/admin/RTMediaFormHandler.php:443 app/admin/RTMediaFormHandler.php:454
2316
+ #: app/helper/RTMediaSupport.php:363
2317
+ msgid "here"
 
2318
  msgstr ""
2319
 
2320
+ #: app/admin/RTMediaFormHandler.php:446
2321
+ msgid "Enable JSON API"
2322
  msgstr ""
2323
 
2324
+ #: app/admin/RTMediaFormHandler.php:451
2325
+ msgid ""
2326
+ "This will allow handling API requests for rtMedia sent through any mobile "
2327
+ "app."
2328
  msgstr ""
2329
 
2330
+ #: app/admin/RTMediaFormHandler.php:454
2331
+ msgid "You can refer to the API document from"
2332
+ msgstr ""
2333
 
2334
+ #: app/admin/RTMediaFormHandler.php:477
2335
+ msgid "Admin Settings"
2336
  msgstr ""
2337
 
2338
+ #: app/admin/RTMediaFormHandler.php:478
2339
+ msgid "API Settings"
2340
  msgstr ""
2341
 
2342
+ #: app/admin/RTMediaFormHandler.php:479
2343
+ msgid "Miscellaneous"
2344
  msgstr ""
2345
 
2346
+ #: app/admin/RTMediaFormHandler.php:480
2347
+ msgid "Footer Link"
2348
  msgstr ""
2349
 
2350
+ #: app/admin/RTMediaFormHandler.php:560
2351
+ msgid "Media Types Settings"
2352
  msgstr ""
2353
 
2354
+ #: app/admin/RTMediaFormHandler.php:568 app/helper/RTMediaSettings.php:326
2355
+ msgid "Media Type"
2356
  msgstr ""
2357
 
2358
+ #: app/admin/RTMediaFormHandler.php:573
2359
+ msgid "Allow Upload"
2360
  msgstr ""
2361
 
2362
+ #: app/admin/RTMediaFormHandler.php:575
2363
+ msgid "Allows you to upload a particular media type on your post."
2364
  msgstr ""
2365
 
2366
+ #: app/admin/RTMediaFormHandler.php:583
2367
+ msgid "Set Featured"
2368
  msgstr ""
2369
 
2370
+ #: app/admin/RTMediaFormHandler.php:585
2371
+ msgid "Place a specific media as a featured content on the post."
2372
  msgstr ""
2373
 
2374
+ #: app/admin/RTMediaFormHandler.php:627
2375
+ msgid "File Extensions"
2376
  msgstr ""
2377
 
2378
+ #: app/admin/RTMediaFormHandler.php:715
2379
+ msgid "Media Size Settings"
2380
  msgstr ""
2381
 
2382
+ #: app/admin/RTMediaFormHandler.php:720
2383
+ msgid "Category"
2384
  msgstr ""
2385
 
2386
+ #: app/admin/RTMediaFormHandler.php:721
2387
+ msgid "Entity"
2388
  msgstr ""
2389
 
2390
+ #: app/admin/RTMediaFormHandler.php:722
2391
+ msgid "Width"
 
 
2392
  msgstr ""
2393
 
2394
+ #: app/admin/RTMediaFormHandler.php:723
2395
+ msgid "Height"
2396
  msgstr ""
2397
 
2398
+ #: app/admin/RTMediaFormHandler.php:724
2399
+ msgid "Crop"
2400
  msgstr ""
2401
 
2402
+ #: app/admin/RTMediaFormHandler.php:777
2403
+ msgid "Number of thumbnails to generate on video upload"
2404
  msgstr ""
2405
 
2406
+ #: app/admin/RTMediaFormHandler.php:783
2407
+ msgid ""
2408
+ " If you choose more than 1 thumbnail, your users will be able to change the "
2409
+ "thumbnail by going to video 'edit' section. Maximum value is 10."
2410
  msgstr ""
2411
 
2412
+ #: app/admin/RTMediaFormHandler.php:791
2413
+ msgid "Encoding Settings"
2414
  msgstr ""
2415
 
2416
+ #: app/admin/RTMediaFormHandler.php:798
2417
+ msgid "JPEG/JPG image quality (1-100)"
2418
  msgstr ""
2419
 
2420
+ #: app/admin/RTMediaFormHandler.php:804
2421
+ msgid ""
2422
+ "Enter JPEG/JPG Image Quality. Minimum value is 1. 100 is original quality."
2423
  msgstr ""
2424
 
2425
+ #: app/admin/RTMediaFormHandler.php:812
2426
+ msgid "Image Quality"
2427
  msgstr ""
2428
 
2429
+ #: app/admin/RTMediaFormHandler.php:834
2430
+ msgid "Custom CSS settings"
2431
  msgstr ""
2432
 
2433
+ #: app/admin/RTMediaFormHandler.php:853
2434
+ msgid "rtMedia default styles"
2435
  msgstr ""
2436
 
2437
+ #: app/admin/RTMediaFormHandler.php:859
2438
+ msgid ""
2439
+ "Load default rtMedia styles. You need to write your own style for rtMedia if "
2440
+ "you disable it."
2441
  msgstr ""
2442
 
2443
+ #: app/admin/RTMediaFormHandler.php:864
2444
+ msgid "Paste your CSS code"
2445
  msgstr ""
2446
 
2447
+ #: app/admin/RTMediaFormHandler.php:870
2448
+ msgid "Custom rtMedia CSS container"
2449
  msgstr ""
2450
 
2451
+ #: app/admin/RTMediaFormHandler.php:893
2452
+ msgid "Enable privacy"
2453
  msgstr ""
2454
 
2455
+ #: app/admin/RTMediaFormHandler.php:899
2456
+ msgid "Enable privacy in rtMedia"
2457
  msgstr ""
2458
 
2459
+ #: app/admin/RTMediaFormHandler.php:904
2460
+ msgid "Default privacy"
2461
  msgstr ""
2462
 
2463
+ #: app/admin/RTMediaFormHandler.php:910
2464
+ msgid "Set default privacy for media"
2465
  msgstr ""
2466
 
2467
+ #: app/admin/RTMediaFormHandler.php:916
2468
+ msgid "Allow users to set privacy for their content"
2469
  msgstr ""
2470
 
2471
+ #: app/admin/RTMediaFormHandler.php:921
2472
+ msgid ""
2473
+ "If you choose this, users will be able to change privacy of their own "
2474
+ "uploads."
2475
  msgstr ""
2476
 
2477
+ #: app/admin/RTMediaFormHandler.php:925
2478
+ msgid "For group uploads, BuddyPress groups privacy is used."
2479
  msgstr ""
2480
 
2481
+ #: app/admin/RTMediaFormHandler.php:967
2482
+ msgid "Enable media in profile"
2483
  msgstr ""
2484
 
2485
+ #: app/admin/RTMediaFormHandler.php:972
2486
+ msgid "Enable Media on BuddyPress Profile"
2487
  msgstr ""
2488
 
2489
+ #: app/admin/RTMediaFormHandler.php:977
2490
+ msgid "Enable media in group"
2491
  msgstr ""
2492
 
2493
+ #: app/admin/RTMediaFormHandler.php:982
2494
+ msgid "Enable Media on BuddyPress Groups"
2495
  msgstr ""
2496
 
2497
+ #: app/admin/RTMediaFormHandler.php:987
2498
+ msgid "Allow upload from activity stream"
2499
  msgstr ""
2500
 
2501
+ #: app/admin/RTMediaFormHandler.php:992
2502
+ msgid "Allow upload using status update box present on activity stream page"
 
2503
  msgstr ""
2504
 
2505
+ #: app/admin/RTMediaFormHandler.php:998
2506
+ msgid "Number of media items to show in activity stream"
 
2507
  msgstr ""
2508
 
2509
+ #: app/admin/RTMediaFormHandler.php:1003
2510
+ msgid ""
2511
+ "With bulk uploads activity, the stream may get flooded. You can control the "
2512
+ "maximum number of media items or files per activity. This limit will not "
2513
+ "affect the actual number of uploads. This is only for display. <em>0</em> "
2514
+ "means unlimited."
2515
  msgstr ""
2516
 
2517
+ #: app/admin/RTMediaFormHandler.php:1010
2518
+ msgid "Enable media notification"
2519
  msgstr ""
2520
 
2521
+ #: app/admin/RTMediaFormHandler.php:1015
2522
+ msgid ""
2523
+ "This will enable notifications to media authors for media likes and comments."
2524
  msgstr ""
2525
 
2526
+ #: app/admin/RTMediaFormHandler.php:1021
2527
+ msgid "Create activity for media likes"
2528
  msgstr ""
2529
 
2530
+ #: app/admin/RTMediaFormHandler.php:1026
2531
+ msgid "Enabling this setting will create BuddyPress activity for media likes."
2532
  msgstr ""
2533
 
2534
+ #: app/admin/RTMediaFormHandler.php:1032
2535
+ msgid "Create activity for media comments"
2536
  msgstr ""
2537
 
2538
+ #: app/admin/RTMediaFormHandler.php:1037
2539
+ msgid ""
2540
+ "Enabling this setting will create BuddyPress activity for media comments."
2541
  msgstr ""
2542
 
2543
+ #: app/admin/RTMediaFormHandler.php:1043
2544
+ msgid "Organize media into albums"
2545
  msgstr ""
2546
 
2547
+ #: app/admin/RTMediaFormHandler.php:1049
2548
+ msgid ""
2549
+ "This will add 'album' tab to BuddyPress profile and group depending on the "
2550
+ "^above^ settings."
2551
  msgstr ""
2552
 
2553
+ #: app/main/RTMedia.php:302
2554
+ msgid "Photo"
 
2555
  msgstr ""
2556
 
2557
+ #: app/main/RTMedia.php:303
2558
+ msgid "Photos"
 
2559
  msgstr ""
2560
 
2561
+ #: app/main/RTMedia.php:311
2562
+ msgid "Video"
 
2563
  msgstr ""
2564
 
2565
+ #: app/main/RTMedia.php:312
2566
+ msgid "Videos"
 
2567
  msgstr ""
2568
 
2569
+ #: app/main/RTMedia.php:320 app/main/RTMedia.php:321
2570
+ msgid "Music"
 
2571
  msgstr ""
2572
 
2573
+ #: app/main/RTMedia.php:408
2574
+ msgid "Private - Visible only to the user"
 
 
2575
  msgstr ""
2576
 
2577
+ #: app/main/RTMedia.php:409
2578
+ msgid "Friends - Visible to user's friends"
2579
  msgstr ""
2580
 
2581
+ #: app/main/RTMedia.php:410
2582
+ msgid "Logged in Users - Visible to registered users"
2583
  msgstr ""
2584
 
2585
+ #: app/main/RTMedia.php:411
2586
+ msgid "Public - Visible to the world"
 
 
 
2587
  msgstr ""
2588
 
2589
+ #: app/main/RTMedia.php:568
2590
+ #: app/main/controllers/template/rt-template-functions.php:83
2591
+ #: app/main/controllers/template/RTMediaNav.php:177
2592
+ msgid "All"
2593
+ msgstr ""
2594
 
2595
+ #: app/main/RTMedia.php:577
2596
+ #: app/main/controllers/template/rt-template-functions.php:1391
2597
+ #: app/main/controllers/upload/RTMediaUploadView.php:51
2598
+ #: app/main/controllers/upload/RTMediaUploadView.php:54
2599
+ #: app/main/controllers/media/RTMediaAlbum.php:49
2600
+ msgid "Album"
2601
  msgstr ""
2602
 
2603
+ #: app/main/RTMedia.php:580 app/main/controllers/template/RTMediaNav.php:198
2604
+ #: app/main/controllers/media/RTMediaAlbum.php:48
2605
+ #: app/main/controllers/media/RTMediaAlbum.php:60
2606
+ msgid "Albums"
2607
  msgstr ""
2608
 
2609
+ #: app/main/RTMedia.php:588
2610
+ #: app/main/controllers/template/rt-template-functions.php:2160
2611
+ #: app/main/controllers/template/rt-template-functions.php:2164
2612
+ #: app/main/controllers/media/RTMediaLoginPopup.php:38
2613
+ msgid "Upload"
2614
  msgstr ""
2615
 
2616
+ #: app/main/RTMedia.php:592
2617
+ msgid "Wall Post"
2618
  msgstr ""
2619
 
2620
+ #: app/main/RTMedia.php:805 app/main/RTMedia.php:814
2621
+ msgid "Wall Posts"
2622
  msgstr ""
2623
 
2624
+ #: app/main/RTMedia.php:857
2625
+ msgid ": Can't Create Database table. Please check create table permission."
2626
  msgstr ""
2627
 
2628
+ #: app/main/RTMedia.php:901
2629
+ msgid "Loading media"
2630
  msgstr ""
2631
 
2632
+ #: app/main/RTMedia.php:902
2633
+ msgid "Please enter some content to post."
2634
  msgstr ""
2635
 
2636
+ #: app/main/RTMedia.php:903
2637
+ msgid "Empty Comment is not allowed."
2638
  msgstr ""
2639
 
2640
+ #: app/main/RTMedia.php:904
2641
+ msgid "Are you sure you want to delete this media?"
2642
  msgstr ""
2643
 
2644
+ #: app/main/RTMedia.php:905
2645
+ msgid "Are you sure you want to delete this comment?"
2646
  msgstr ""
2647
 
2648
+ #: app/main/RTMedia.php:906
2649
+ msgid "Are you sure you want to delete this Album?"
 
2650
  msgstr ""
2651
 
2652
+ #: app/main/RTMedia.php:907
2653
+ msgid "Drop files here"
 
2654
  msgstr ""
2655
 
2656
+ #: app/main/RTMedia.php:908
2657
+ msgid "album created successfully."
 
2658
  msgstr ""
2659
 
2660
+ #: app/main/RTMedia.php:909
2661
+ msgid "Something went wrong. Please try again."
 
2662
  msgstr ""
2663
 
2664
+ #: app/main/RTMedia.php:910
2665
+ msgid "Enter an album name."
 
2666
  msgstr ""
2667
 
2668
+ #: app/main/RTMedia.php:911
2669
+ msgid "Max file Size Limit : "
2670
  msgstr ""
2671
 
2672
+ #: app/main/RTMedia.php:912
2673
+ msgid "Allowed File Formats"
2674
  msgstr ""
2675
 
2676
+ #: app/main/RTMedia.php:913 templates/media/album-single-edit.php:62
2677
+ msgid "Select All Visible"
 
 
2678
  msgstr ""
2679
 
2680
+ #: app/main/RTMedia.php:914
2681
+ msgid "Unselect All Visible"
2682
  msgstr ""
2683
 
2684
+ #: app/main/RTMedia.php:915
2685
+ msgid "Please select some media."
2686
  msgstr ""
2687
 
2688
+ #: app/main/RTMedia.php:916
2689
+ msgid "Are you sure you want to delete the selected media?"
2690
  msgstr ""
2691
 
2692
+ #: app/main/RTMedia.php:917
2693
+ msgid "Are you sure you want to move the selected media?"
2694
  msgstr ""
2695
 
2696
+ #: app/main/RTMedia.php:918
2697
+ msgid "Waiting"
2698
  msgstr ""
2699
 
2700
+ #: app/main/RTMedia.php:919
2701
+ msgid "Uploaded"
2702
  msgstr ""
2703
 
2704
+ #: app/main/RTMedia.php:920
2705
+ msgid "Uploading"
2706
  msgstr ""
2707
 
2708
+ #: app/main/RTMedia.php:921
2709
+ msgid "Failed"
2710
  msgstr ""
2711
 
2712
+ #: app/main/RTMedia.php:922
2713
+ msgid "Close"
2714
  msgstr ""
2715
 
2716
+ #: app/main/RTMedia.php:923
2717
+ #: app/main/controllers/template/rt-template-functions.php:733
2718
+ #: app/main/controllers/template/rt-template-functions.php:754
2719
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:61
2720
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
2721
+ msgid "Edit"
2722
  msgstr ""
2723
 
2724
+ #: app/main/RTMedia.php:924
2725
+ #: app/main/controllers/template/rt-template-functions.php:1471
2726
+ #: app/main/controllers/template/rt-template-functions.php:1478
2727
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:64
2728
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
2729
+ #: templates/media/album-single-edit.php:65
2730
+ msgid "Delete"
2731
  msgstr ""
2732
 
2733
+ #: app/main/RTMedia.php:925 templates/media/media-single-edit.php:8
2734
+ msgid "Edit Media"
2735
  msgstr ""
2736
 
2737
+ #: app/main/RTMedia.php:926
2738
+ msgid "Remove from queue"
2739
  msgstr ""
2740
 
2741
+ #: app/main/RTMedia.php:927
2742
+ msgid "Add more files"
2743
  msgstr ""
2744
 
2745
+ #: app/main/RTMedia.php:928
2746
+ msgid "File not supported"
2747
  msgstr ""
2748
 
2749
+ #: app/main/RTMedia.php:929
2750
+ msgid "more"
2751
  msgstr ""
2752
 
2753
+ #: app/main/RTMedia.php:930
2754
+ msgid "less"
2755
  msgstr ""
2756
 
2757
+ #: app/main/RTMedia.php:931
2758
+ msgid "This media is uploaded. Are you sure you want to delete this media?"
 
2759
  msgstr ""
2760
 
2761
+ #: app/main/RTMedia.php:939
2762
+ msgid "Featured media set successfully."
 
 
 
2763
  msgstr ""
2764
 
2765
+ #: app/main/RTMedia.php:940
2766
+ msgid "Featured media removed successfully."
2767
  msgstr ""
2768
 
2769
+ #: app/main/RTMedia.php:977
2770
+ msgid "There are some uploads in progress. Do you want to cancel them?"
2771
  msgstr ""
2772
 
2773
+ #: app/main/deprecated/RTMediaDeprecated.php:27
2774
+ #, php-format
2775
+ msgid "Deprecated %s. Please use %s."
2776
  msgstr ""
2777
 
2778
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:251
2779
+ msgid "Media Files"
2780
  msgstr ""
2781
 
2782
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:275
2783
+ #: app/main/controllers/shortcodes/RTMediaUploadShortcode.php:103
2784
+ #: app/main/controllers/template/rt-template-functions.php:1505
2785
+ msgid "You are not allowed to upload/attach media."
2786
  msgstr ""
2787
 
2788
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:411
2789
+ #, php-format
2790
+ msgid "%s added a %s"
2791
  msgstr ""
2792
 
2793
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:417
2794
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:419
2795
+ #: app/main/controllers/upload/RTMediaUploadEndpoint.php:105
2796
+ #, php-format
2797
+ msgid "%s added %d %s"
2798
  msgstr ""
2799
 
2800
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:470
2801
+ #, php-format
2802
+ msgid "%1$s liked a %2$s in the group %3$s"
2803
  msgstr ""
2804
 
2805
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:473
2806
+ #, php-format
2807
+ msgid "%1$s liked their %2$s"
2808
  msgstr ""
2809
 
2810
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:477
2811
+ #, php-format
2812
+ msgid "%1$s liked %2$s's %3$s"
2813
  msgstr ""
2814
 
2815
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:555
2816
+ #, php-format
2817
+ msgid "%1$s commented on a %2$s in the group %3$s"
2818
  msgstr ""
2819
 
2820
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:558
2821
+ #, php-format
2822
+ msgid "%1$s commented on their %2$s"
2823
  msgstr ""
2824
 
2825
+ #: app/main/controllers/activity/RTMediaBuddyPressActivity.php:562
2826
+ #, php-format
2827
+ msgid "%1$s commented on %2$s's %3$s"
2828
  msgstr ""
2829
 
2830
+ #: app/main/controllers/privacy/RTMediaPrivacy.php:353
2831
+ msgid "No changes were made to your account."
 
2832
  msgstr ""
2833
 
2834
+ #: app/main/controllers/privacy/RTMediaPrivacy.php:356
2835
+ msgid "Your default privacy settings saved successfully."
2836
  msgstr ""
2837
 
2838
+ #: app/main/controllers/privacy/RTMediaPrivacy.php:379
2839
+ msgid "Default Privacy"
 
2840
  msgstr ""
2841
 
2842
+ #: app/main/controllers/privacy/RTMediaPrivacy.php:388
2843
+ #: app/main/controllers/group/RTMediaGroupExtension.php:113
2844
+ #: templates/media/album-single-edit.php:47
2845
+ msgid "Save Changes"
2846
  msgstr ""
2847
 
2848
+ #: app/main/controllers/shortcodes/RTMediaUploadShortcode.php:91
2849
+ msgid "The web browser on your device cannot be used to upload files."
2850
  msgstr ""
2851
 
2852
+ #: app/main/controllers/shortcodes/RTMediaGalleryShortcode.php:182
2853
+ msgid "You do not have sufficient privileges to view this gallery"
2854
  msgstr ""
2855
 
2856
+ #: app/main/controllers/group/RTMediaGroupExtension.php:30
2857
+ #: app/main/controllers/group/RTMediaGroupExtension.php:92
2858
+ msgid "Album Creation Control"
2859
  msgstr ""
2860
 
2861
+ #: app/main/controllers/group/RTMediaGroupExtension.php:31
2862
+ #: app/main/controllers/group/RTMediaGroupExtension.php:93
2863
+ msgid "Who can create Albums in this group?"
2864
+ msgstr ""
2865
+
2866
+ #: app/main/controllers/group/RTMediaGroupExtension.php:35
2867
+ #: app/main/controllers/group/RTMediaGroupExtension.php:97
2868
+ msgid "All Group Members"
2869
+ msgstr ""
2870
+
2871
+ #: app/main/controllers/group/RTMediaGroupExtension.php:39
2872
+ #: app/main/controllers/group/RTMediaGroupExtension.php:101
2873
+ msgid "Group Admins and Mods only"
2874
+ msgstr ""
2875
+
2876
+ #: app/main/controllers/group/RTMediaGroupExtension.php:43
2877
+ #: app/main/controllers/group/RTMediaGroupExtension.php:105
2878
+ msgid "Group Admin only"
2879
+ msgstr ""
2880
+
2881
+ #: app/main/controllers/group/RTMediaGroupExtension.php:142
2882
+ msgid "There was an error saving, please try again"
2883
+ msgstr ""
2884
+
2885
+ #: app/main/controllers/group/RTMediaGroupExtension.php:144
2886
+ msgid "Settings saved successfully"
2887
+ msgstr ""
2888
+
2889
+ #: app/main/controllers/group/RTMediaGroupExtension.php:164
2890
+ msgid ""
2891
+ "You could display a small snippet of information from your group extension "
2892
+ "here. It will show on the group\n"
2893
+ "\t home screen."
2894
+ msgstr ""
2895
+
2896
+ #: app/main/controllers/template/rt-template-functions.php:709
2897
+ #: app/main/controllers/template/rt-template-functions.php:1697
2898
+ msgid "Options"
2899
+ msgstr ""
2900
+
2901
+ #: app/main/controllers/template/rt-template-functions.php:798
2902
+ msgid "There are no comments on this media yet."
2903
+ msgstr ""
2904
+
2905
+ #: app/main/controllers/template/rt-template-functions.php:834
2906
+ msgid "Delete Comment"
2907
+ msgstr ""
2908
+
2909
+ #: app/main/controllers/template/rt-template-functions.php:1032
2910
+ msgid "Go to page no : "
2911
+ msgstr ""
2912
+
2913
+ #: app/main/controllers/template/rt-template-functions.php:1037
2914
+ msgid "Go"
2915
+ msgstr ""
2916
+
2917
+ #: app/main/controllers/template/rt-template-functions.php:1210
2918
+ msgid "Video Thumbnail"
2919
+ msgstr ""
2920
+
2921
+ #: app/main/controllers/template/rt-template-functions.php:1259
2922
+ msgid "Video Thumbnail:"
2923
+ msgstr ""
2924
+
2925
+ #: app/main/controllers/template/rt-template-functions.php:1342
2926
+ msgid "Image"
2927
+ msgstr ""
2928
+
2929
+ #: app/main/controllers/template/rt-template-functions.php:1359
2930
+ msgid "Modify Image"
2931
+ msgstr ""
2932
+
2933
+ #: app/main/controllers/template/rt-template-functions.php:1434
2934
+ msgid "Type Comment..."
2935
+ msgstr ""
2936
+
2937
+ #: app/main/controllers/template/rt-template-functions.php:1435
2938
+ #: templates/media/media-single.php:82 templates/media/media-single.php:122
2939
+ msgid "Comment"
2940
+ msgstr ""
2941
+
2942
+ #: app/main/controllers/template/rt-template-functions.php:1471
2943
+ #: app/main/controllers/template/rt-template-functions.php:1478
2944
+ msgid "Delete Media"
2945
+ msgstr ""
2946
+
2947
+ #: app/main/controllers/template/rt-template-functions.php:1639
2948
+ msgid "Profile Albums"
2949
+ msgstr ""
2950
+
2951
+ #: app/main/controllers/template/rt-template-functions.php:1642
2952
+ #: app/main/controllers/template/rt-template-functions.php:1676
2953
+ msgid "Group Albums"
2954
+ msgstr ""
2955
+
2956
+ #: app/main/controllers/template/rt-template-functions.php:1760
2957
+ msgid "Create New Album"
2958
+ msgstr ""
2959
+
2960
+ #: app/main/controllers/template/rt-template-functions.php:1760
2961
+ msgid "Add Album"
2962
+ msgstr ""
2963
+
2964
+ #: app/main/controllers/template/rt-template-functions.php:1776
2965
+ msgid "Create an Album"
2966
+ msgstr ""
2967
+
2968
+ #: app/main/controllers/template/rt-template-functions.php:1778
2969
+ msgid "Album Title : "
2970
+ msgstr ""
2971
+
2972
+ #: app/main/controllers/template/rt-template-functions.php:1786
2973
+ #: app/main/controllers/media/RTMediaAlbum.php:51
2974
+ msgid "Create Album"
2975
+ msgstr ""
2976
+
2977
+ #: app/main/controllers/template/rt-template-functions.php:1817
2978
+ #: app/main/controllers/template/rt-template-functions.php:1824
2979
+ #: app/main/controllers/template/rt-template-functions.php:1876
2980
  msgid "Merge Album"
2981
  msgstr ""
2982
 
2984
  msgid "Select Album to merge with : "
2985
  msgstr ""
2986
 
2987
+ #: app/main/controllers/template/rt-template-functions.php:1866
2988
+ #: app/main/controllers/media/RTMediaAlbum.php:52
2989
+ msgid "Edit Album"
2990
+ msgstr ""
2991
+
2992
  #: app/main/controllers/template/rt-template-functions.php:1867
2993
  msgid "Delete Album"
2994
  msgstr ""
3005
  msgid "people like this"
3006
  msgstr ""
3007
 
3008
+ #: app/main/controllers/template/rt-template-functions.php:2160
3009
+ #: app/main/controllers/template/rt-template-functions.php:2164
3010
+ #: app/main/controllers/media/RTMediaLoginPopup.php:38
3011
+ msgid "Upload Media"
3012
+ msgstr ""
3013
+
3014
  #: app/main/controllers/template/rt-template-functions.php:2247
3015
  msgid "Empowering your community with "
3016
  msgstr ""
3044
  msgstr ""
3045
 
3046
  #: app/main/controllers/template/rt-template-functions.php:2331
3047
+ #, php-format
3048
  msgid "%s ago "
3049
  msgstr ""
3050
 
3051
  #: app/main/controllers/template/rt-template-functions.php:2344
3052
+ #, php-format
3053
  msgid "1 second"
3054
  msgid_plural "%s seconds"
3055
  msgstr[0] ""
3056
  msgstr[1] ""
3057
 
3058
  #: app/main/controllers/template/rt-template-functions.php:2347
3059
+ #, php-format
3060
  msgid "1 minute"
3061
  msgid_plural "%s minutes"
3062
  msgstr[0] ""
3063
  msgstr[1] ""
3064
 
3065
  #: app/main/controllers/template/rt-template-functions.php:2350
3066
+ #, php-format
3067
  msgid "1 hour"
3068
  msgid_plural "%s hours"
3069
  msgstr[0] ""
3070
  msgstr[1] ""
3071
 
3072
  #: app/main/controllers/template/rt-template-functions.php:2705
 
3073
  msgid "You can consider rtMedia Team for following :"
3074
  msgstr ""
3075
 
3085
  msgid "WordPress/BuddyPress Plugin Development"
3086
  msgstr ""
3087
 
3088
+ #: app/main/controllers/template/RTMediaAJAX.php:33
3089
+ msgid "You can not create album in this group."
3090
+ msgstr ""
3091
+
3092
+ #: app/main/controllers/template/RTMediaAJAX.php:39
3093
+ msgid "You can not create album."
3094
+ msgstr ""
3095
+
3096
+ #: app/main/controllers/template/RTMediaAJAX.php:44
3097
+ msgid "You can not create more albums, you exceed your album limit."
3098
+ msgstr ""
3099
+
3100
+ #: app/main/controllers/template/RTMediaAJAX.php:89
3101
+ msgid "Data mismatch, Please insert data properly."
3102
+ msgstr ""
3103
+
3104
+ #: app/main/controllers/template/RTMediaNav.php:32
3105
+ msgctxt "My Account Privacy sub nav"
3106
+ msgid "Privacy"
3107
+ msgstr ""
3108
+
3109
+ #: app/main/controllers/template/RTMediaTemplate.php:97
3110
+ #: app/main/controllers/template/RTMediaTemplate.php:149
3111
+ msgid "Invalid attribute passed for rtmedia_gallery shortcode."
3112
+ msgstr ""
3113
+
3114
+ #: app/main/controllers/template/RTMediaTemplate.php:329
3115
+ #: app/main/controllers/template/RTMediaTemplate.php:403
3116
+ #: app/main/controllers/template/RTMediaTemplate.php:492
3117
+ #: app/main/controllers/template/RTMediaTemplate.php:618
3118
+ msgid "Ooops !!! Invalid access. No nonce was found !!"
3119
+ msgstr ""
3120
+
3121
+ #: app/main/controllers/template/RTMediaTemplate.php:336
3122
+ msgid "Media updated Sucessfully"
3123
+ msgstr ""
3124
+
3125
+ #: app/main/controllers/template/RTMediaTemplate.php:342
3126
+ msgid "Error in updating Media"
3127
  msgstr ""
3128
 
3129
  #: app/main/controllers/upload/RTMediaUploadView.php:70
3190
  "Supported audio format is MP3."
3191
  msgstr ""
3192
 
3193
+ #: app/main/controllers/upload/processors/RTMediaUploadFile.php:271
3194
+ msgid "The MP3 file you have uploaded is not an audio file."
3195
+ msgstr ""
3196
+
3197
+ #: app/main/controllers/upload/processors/RTMediaUploadFile.php:279
3198
+ msgid ""
3199
+ "Media File you have tried to upload is not supported. Supported media files "
3200
+ "are .jpg, .png, .gif, .mp3, .mov and .mp4."
3201
+ msgstr ""
3202
+
3203
+ #: app/main/controllers/media/RTMediaGroupFeatured.php:17
3204
+ #: app/main/controllers/media/RTMediaFeatured.php:25
3205
+ msgid "Set as Featured"
3206
+ msgstr ""
3207
+
3208
+ #: app/main/controllers/media/RTMediaGroupFeatured.php:19
3209
+ #: app/main/controllers/media/RTMediaFeatured.php:27
3210
+ msgid "Unset Featured"
3211
+ msgstr ""
3212
+
3213
+ #: app/main/controllers/media/RTMediaGroupFeatured.php:194
3214
+ #: app/main/controllers/media/RTMediaFeatured.php:191
3215
+ msgid "Media type is not allowed"
3216
+ msgstr ""
3217
+
3218
+ #: app/main/controllers/media/RTMediaLoginPopup.php:47
3219
+ msgid "Please login"
3220
+ msgstr ""
3221
+
3222
+ #: app/main/controllers/media/RTMediaLoginPopup.php:49
3223
+ msgid "You need to be logged in to upload Media or to create Album."
3224
+ msgstr ""
3225
+
3226
+ #: app/main/controllers/media/RTMediaLoginPopup.php:52
3227
+ #: app/helper/RTMediaSupport.php:363
3228
+ msgid "Click"
3229
+ msgstr ""
3230
+
3231
+ #: app/main/controllers/media/RTMediaLoginPopup.php:52
3232
+ msgid "Login"
3233
+ msgstr ""
3234
+
3235
+ #: app/main/controllers/media/RTMediaLoginPopup.php:52
3236
+ msgid "HERE"
3237
+ msgstr ""
3238
+
3239
+ #: app/main/controllers/media/RTMediaLoginPopup.php:52
3240
+ msgid " to login."
3241
+ msgstr ""
3242
+
3243
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:60
3244
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
3245
+ msgid "Edit this media"
3246
+ msgstr ""
3247
+
3248
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:63
3249
+ #: app/main/controllers/media/RTMediaGalleryItemAction.php:80
3250
+ msgid "Delete this media"
3251
+ msgstr ""
3252
+
3253
+ #: app/main/controllers/media/RTMediaMedia.php:487
3254
+ msgid "Error creating attachment for the media file, please try again"
3255
+ msgstr ""
3256
+
3257
+ #: app/main/controllers/media/RTMediaMedia.php:589
3258
+ #, php-format
3259
+ msgid "%1$s added a %2$s"
3260
+ msgstr ""
3261
+
3262
+ #: app/main/controllers/media/RTMediaMedia.php:589
3263
+ #, php-format
3264
+ msgid "%1$s added %4$d %3$s"
3265
+ msgstr ""
3266
+
3267
+ #: app/main/controllers/media/RTMediaLike.php:18
3268
+ msgid "Like"
3269
+ msgstr ""
3270
+
3271
+ #: app/main/controllers/media/RTMediaLike.php:20
3272
+ msgid "Unlike"
3273
+ msgstr ""
3274
+
3275
+ #: app/main/controllers/media/RTMediaAlbum.php:35
3276
+ msgctxt "Status General Name"
3277
+ msgid "hidden"
3278
+ msgstr ""
3279
+
3280
+ #: app/main/controllers/media/RTMediaAlbum.php:35
3281
+ #, php-format
3282
+ msgid "Hidden (%s)"
3283
+ msgid_plural "Hidden (%s)"
3284
+ msgstr[0] ""
3285
+ msgstr[1] ""
3286
+
3287
+ #: app/main/controllers/media/RTMediaAlbum.php:50
3288
+ msgid "Create"
3289
+ msgstr ""
3290
+
3291
+ #: app/main/controllers/media/RTMediaAlbum.php:53
3292
+ msgid "New Album"
3293
+ msgstr ""
3294
+
3295
+ #: app/main/controllers/media/RTMediaAlbum.php:54
3296
+ msgid "All Albums"
3297
+ msgstr ""
3298
+
3299
+ #: app/main/controllers/media/RTMediaAlbum.php:55
3300
+ msgid "View Album"
3301
+ msgstr ""
3302
+
3303
+ #: app/main/controllers/media/RTMediaAlbum.php:56
3304
+ msgid "Search Albums"
3305
+ msgstr ""
3306
+
3307
+ #: app/main/controllers/media/RTMediaAlbum.php:57
3308
+ msgid "No album found"
3309
+ msgstr ""
3310
+
3311
+ #: app/main/controllers/media/RTMediaAlbum.php:58
3312
+ msgid "No album found in Trash"
3313
+ msgstr ""
3314
+
3315
+ #: app/main/controllers/media/RTMediaAlbum.php:59
3316
+ msgid "Parent"
3317
+ msgstr ""
3318
+
3319
+ #: app/main/controllers/media/RTMediaAlbum.php:145
3320
+ msgid "Untitled Album"
3321
+ msgstr ""
3322
+
3323
+ #: app/main/controllers/api/RTMediaJsonApi.php:166
3324
+ msgid "username/password empty"
3325
+ msgstr ""
3326
+
3327
+ #: app/main/controllers/api/RTMediaJsonApi.php:169
3328
+ msgid "incorrect username"
3329
+ msgstr ""
3330
+
3331
+ #: app/main/controllers/api/RTMediaJsonApi.php:172
3332
+ msgid "incorrect password"
3333
+ msgstr ""
3334
+
3335
+ #: app/main/controllers/api/RTMediaJsonApi.php:175
3336
+ msgid "login success"
3337
+ msgstr ""
3338
+
3339
+ #: app/main/controllers/api/RTMediaJsonApi.php:221
3340
+ msgid "fields empty"
3341
+ msgstr ""
3342
+
3343
+ #: app/main/controllers/api/RTMediaJsonApi.php:224
3344
+ msgid "invalid email"
3345
+ msgstr ""
3346
+
3347
+ #: app/main/controllers/api/RTMediaJsonApi.php:227
3348
+ msgid "password do not match"
3349
+ msgstr ""
3350
+
3351
+ #: app/main/controllers/api/RTMediaJsonApi.php:230
3352
+ msgid "username already registered"
3353
+ msgstr ""
3354
+
3355
+ #: app/main/controllers/api/RTMediaJsonApi.php:233
3356
+ msgid "email already exists"
3357
+ msgstr ""
3358
+
3359
+ #: app/main/controllers/api/RTMediaJsonApi.php:236
3360
+ msgid "new user created"
3361
+ msgstr ""
3362
+
3363
+ #: app/main/controllers/api/RTMediaJsonApi.php:297
3364
+ msgid "email empty"
3365
+ msgstr ""
3366
+
3367
+ #: app/main/controllers/api/RTMediaJsonApi.php:300
3368
+ msgid "username/email not registered"
3369
+ msgstr ""
3370
+
3371
+ #: app/main/controllers/api/RTMediaJsonApi.php:303
3372
+ msgid "reset link sent"
3373
+ msgstr ""
3374
+
3375
+ #: app/main/controllers/api/RTMediaJsonApi.php:335
3376
+ msgid ""
3377
+ "Someone has asked to reset the password for the following site and username."
3378
+ msgstr ""
3379
+
3380
+ #: app/main/controllers/api/RTMediaJsonApi.php:337
3381
+ #, php-format
3382
+ msgid "Username: %s"
3383
+ msgstr ""
3384
+
3385
+ #: app/main/controllers/api/RTMediaJsonApi.php:338
3386
+ msgid ""
3387
+ "To reset your password visit the following address, otherwise just ignore "
3388
+ "this email and nothing will happen."
3389
+ msgstr ""
3390
+
3391
+ #: app/main/controllers/api/RTMediaJsonApi.php:341
3392
+ #, php-format
3393
+ msgid "[%s] Password Reset"
3394
+ msgstr ""
3395
+
3396
+ #: app/main/controllers/api/RTMediaJsonApi.php:356
3397
+ msgid "bp activities"
3398
+ msgstr ""
3399
+
3400
+ #: app/main/controllers/api/RTMediaJsonApi.php:359
3401
+ msgid "user activities"
3402
+ msgstr ""
3403
+
3404
+ #: app/main/controllers/api/RTMediaJsonApi.php:389
3405
+ msgid "comment content missing"
3406
+ msgstr ""
3407
+
3408
+ #: app/main/controllers/api/RTMediaJsonApi.php:392
3409
+ msgid "comment posted"
3410
+ msgstr ""
3411
+
3412
+ #: app/main/controllers/api/RTMediaJsonApi.php:439
3413
+ msgid "unliked media"
3414
+ msgstr ""
3415
+
3416
+ #: app/main/controllers/api/RTMediaJsonApi.php:442
3417
+ msgid "liked media"
3418
+ msgstr ""
3419
+
3420
+ #: app/main/controllers/api/RTMediaJsonApi.php:526
3421
+ msgid "no comments"
3422
+ msgstr ""
3423
+
3424
+ #: app/main/controllers/api/RTMediaJsonApi.php:529
3425
+ msgid "media comments"
3426
+ msgstr ""
3427
+
3428
+ #: app/main/controllers/api/RTMediaJsonApi.php:532
3429
+ msgid "my comments"
3430
+ msgstr ""
3431
+
3432
+ #: app/main/controllers/api/RTMediaJsonApi.php:582
3433
+ msgid "no likes"
3434
+ msgstr ""
3435
+
3436
+ #: app/main/controllers/api/RTMediaJsonApi.php:585
3437
+ msgid "media likes"
3438
+ msgstr ""
3439
+
3440
+ #: app/main/controllers/api/RTMediaJsonApi.php:627
3441
+ msgid "invalid comment/media id"
3442
+ msgstr ""
3443
+
3444
+ #: app/main/controllers/api/RTMediaJsonApi.php:630
3445
+ msgid "no comment id"
3446
+ msgstr ""
3447
+
3448
+ #: app/main/controllers/api/RTMediaJsonApi.php:633
3449
+ msgid "comment deleted"
3450
+ msgstr ""
3451
+
3452
+ #: app/main/controllers/api/RTMediaJsonApi.php:676
3453
+ msgid "no profile found"
3454
+ msgstr ""
3455
+
3456
+ #: app/main/controllers/api/RTMediaJsonApi.php:679
3457
+ msgid "profile fields"
3458
+ msgstr ""
3459
+
3460
+ #: app/main/controllers/api/RTMediaJsonApi.php:773
3461
+ msgid "follow user id missing"
3462
+ msgstr ""
3463
+
3464
+ #: app/main/controllers/api/RTMediaJsonApi.php:776
3465
+ msgid "started following"
3466
+ msgstr ""
3467
+
3468
+ #: app/main/controllers/api/RTMediaJsonApi.php:779
3469
+ msgid "already following"
3470
+ msgstr ""
3471
+
3472
+ #: app/main/controllers/api/RTMediaJsonApi.php:811
3473
+ msgid "unfollow id missing"
3474
+ msgstr ""
3475
+
3476
+ #: app/main/controllers/api/RTMediaJsonApi.php:814
3477
+ msgid "stopped following"
3478
+ msgstr ""
3479
+
3480
+ #: app/main/controllers/api/RTMediaJsonApi.php:817
3481
+ msgid "not following"
3482
+ msgstr ""
3483
+
3484
+ #: app/main/controllers/api/RTMediaJsonApi.php:849
3485
+ msgid "name/location empty"
3486
+ msgstr ""
3487
+
3488
+ #: app/main/controllers/api/RTMediaJsonApi.php:852
3489
+ msgid "profile updated"
3490
+ msgstr ""
3491
+
3492
+ #: app/main/controllers/api/RTMediaJsonApi.php:878
3493
+ #: app/main/controllers/api/RTMediaJsonApi.php:905
3494
+ msgid "no file"
3495
+ msgstr ""
3496
+
3497
+ #: app/main/controllers/api/RTMediaJsonApi.php:881
3498
+ #: app/main/controllers/api/RTMediaJsonApi.php:917
3499
+ msgid "upload failed, check size and file type"
3500
+ msgstr ""
3501
+
3502
+ #: app/main/controllers/api/RTMediaJsonApi.php:884
3503
+ msgid "avatar updated"
3504
+ msgstr ""
3505
+
3506
+ #: app/main/controllers/api/RTMediaJsonApi.php:908
3507
+ msgid "invalid file string"
3508
+ msgstr ""
3509
+
3510
+ #: app/main/controllers/api/RTMediaJsonApi.php:911
3511
+ msgid "image type missing"
3512
+ msgstr ""
3513
+
3514
+ #: app/main/controllers/api/RTMediaJsonApi.php:914
3515
+ msgid "no title"
3516
+ msgstr ""
3517
+
3518
+ #: app/main/controllers/api/RTMediaJsonApi.php:920
3519
+ msgid "media updated"
3520
+ msgstr ""
3521
+
3522
+ #: app/main/controllers/api/RTMediaJsonApi.php:1050
3523
+ msgid "media list"
3524
+ msgstr ""
3525
+
3526
+ #: app/main/controllers/api/RTMediaJsonApi.php:1053
3527
+ msgid "no media found for requested media type"
3528
+ msgstr ""
3529
+
3530
+ #: app/main/controllers/api/RTMediaJsonApi.php:1056
3531
+ msgid "media_type not allowed"
3532
+ msgstr ""
3533
+
3534
+ #: app/main/controllers/api/RTMediaJsonApi.php:1146
3535
+ msgid "single media"
3536
+ msgstr ""
3537
+
3538
+ #: app/helper/RTMediaSupport.php:58 app/helper/RTMediaSupport.php:59
3539
+ #: app/helper/RTMediaSupport.php:305 app/helper/RTMediaSupport.php:560
3540
+ msgid "Debug Info"
3541
+ msgstr ""
3542
+
3543
+ #: app/helper/RTMediaSupport.php:128
3544
+ msgid "Service"
3545
+ msgstr ""
3546
+
3547
+ #: app/helper/RTMediaSupport.php:135
3548
+ msgid "Premium Support"
3549
+ msgstr ""
3550
+
3551
+ #: app/helper/RTMediaSupport.php:141
3552
+ msgid "Bug Report"
3553
+ msgstr ""
3554
+
3555
+ #: app/helper/RTMediaSupport.php:147
3556
+ msgid "New Feature"
3557
+ msgstr ""
3558
+
3559
+ #: app/helper/RTMediaSupport.php:149
3560
+ msgid "Submit"
3561
+ msgstr ""
3562
+
3563
+ #: app/helper/RTMediaSupport.php:195
3564
+ msgid "by"
3565
+ msgstr ""
3566
+
3567
+ #: app/helper/RTMediaSupport.php:195
3568
+ msgid "version"
3569
+ msgstr ""
3570
+
3571
+ #: app/helper/RTMediaSupport.php:357
3572
+ msgid "There is no media found to migrate."
3573
+ msgstr ""
3574
+
3575
+ #: app/helper/RTMediaSupport.php:363
3576
+ msgid "here to migrate media from rtMedia 2.x to rtMedia 3.0+."
3577
+ msgstr ""
3578
+
3579
+ #: app/helper/RTMediaSupport.php:392
3580
+ msgid "Submit a Bug Report"
3581
+ msgstr ""
3582
+
3583
+ #: app/helper/RTMediaSupport.php:395
3584
+ msgid "Submit a New Feature Request"
3585
+ msgstr ""
3586
+
3587
+ #: app/helper/RTMediaSupport.php:398
3588
+ msgid "Submit Support Request"
3589
+ msgstr ""
3590
+
3591
+ #: app/helper/RTMediaSupport.php:405
3592
+ msgid ""
3593
+ "If your site has some issues due to rtMedia and you want support, feel free "
3594
+ "to create a support topic on <a target=\"_blank\" href=\"http://community."
3595
+ "rtcamp.com/c/rtmedia/?"
3596
+ "utm_source=dashboard&utm_medium=plugin&utm_campaign=buddypress-media"
3597
+ "\">Community Forum</a>."
3598
+ msgstr ""
3599
+
3600
+ #: app/helper/RTMediaSupport.php:406
3601
+ msgid ""
3602
+ "If you have any suggestions, enhancements or bug reports, you can open a new "
3603
+ "issue on <a target=\"_blank\" href=\"https://github.com/rtCamp/rtMedia/"
3604
+ "issues/new\">GitHub</a>."
3605
+ msgstr ""
3606
+
3607
+ #: app/helper/RTMediaSupport.php:420
3608
+ msgid "Use actual user name which used during purchased."
3609
+ msgstr ""
3610
+
3611
+ #: app/helper/RTMediaSupport.php:431
3612
+ msgid "Use email id which used during purchased"
3613
+ msgstr ""
3614
+
3615
+ #: app/helper/RTMediaSupport.php:437
3616
+ msgid "Website"
3617
+ msgstr ""
3618
+
3619
+ #: app/helper/RTMediaSupport.php:442
3620
+ msgid "Subject"
3621
+ msgstr ""
3622
+
3623
+ #: app/helper/RTMediaSupport.php:490
3624
+ msgid "rtMedia Premium Support Request from"
3625
+ msgstr ""
3626
+
3627
+ #: app/helper/RTMediaSupport.php:493
3628
+ msgid "rtMedia New Feature Request from"
3629
+ msgstr ""
3630
+
3631
+ #: app/helper/RTMediaSupport.php:496
3632
+ msgid "rtMedia Bug Report from"
3633
+ msgstr ""
3634
+
3635
+ #: app/helper/RTMediaSupport.php:499
3636
+ msgid "rtMedia Contact from"
3637
+ msgstr ""
3638
+
3639
+ #: app/helper/RTMediaSupport.php:577
3640
+ msgid "Thank you for your Feedback/Suggestion."
3641
+ msgstr ""
3642
+
3643
+ #: app/helper/RTMediaSupport.php:579
3644
+ msgid "Thank you for posting your support request."
3645
+ msgstr ""
3646
+
3647
+ #: app/helper/RTMediaSupport.php:580
3648
+ msgid "We will get back to you shortly."
3649
+ msgstr ""
3650
+
3651
+ #: app/helper/RTMediaSupport.php:585
3652
+ msgid "Your server failed to send an email."
3653
+ msgstr ""
3654
+
3655
+ #: app/helper/RTMediaSupport.php:586
3656
+ msgid "Kindly contact your server support to fix this."
3657
+ msgstr ""
3658
+
3659
+ #: app/helper/RTMediaSupport.php:587
3660
+ msgid ""
3661
+ "You can alternatively create a support request <a href=\"https://rtcamp.com/"
3662
+ "premium-support/\" target=\"_blank\">here</a>"
3663
+ msgstr ""
3664
+
3665
+ #: app/helper/RTMediaAddon.php:79 app/helper/RTMediaAddon.php:80
3666
+ msgid "Plugins"
3667
+ msgstr ""
3668
+
3669
+ #: app/helper/RTMediaAddon.php:87 app/helper/RTMediaAddon.php:88
3670
+ msgid "Audio/Video Encoding"
3671
+ msgstr ""
3672
+
3673
+ #: app/helper/RTMediaAddon.php:111
3674
+ msgid "SEO"
3675
+ msgstr ""
3676
+
3677
+ #: app/helper/RTMediaAddon.php:114
3678
+ msgid ""
3679
+ "Generate an XML sitemap for all the public media files uploaded via rtMedia "
3680
+ "plugin. These sitemaps can be useful to index search engine to improve "
3681
+ "website SEO."
3682
+ msgstr ""
3683
+
3684
+ #: app/helper/RTMediaAddon.php:121
3685
+ msgid "Moderation"
3686
+ msgstr ""
3687
+
3688
+ #: app/helper/RTMediaAddon.php:124
3689
+ msgid ""
3690
+ "Report media if they find offensive. Set number of reports to automatically "
3691
+ "take down media from site."
3692
+ msgstr ""
3693
+
3694
+ #: app/helper/RTMediaAddon.php:132
3695
+ msgid "Custom Attributes"
3696
+ msgstr ""
3697
+
3698
+ #: app/helper/RTMediaAddon.php:135
3699
+ msgid ""
3700
+ "Categories media based on attributes. Site owner need to create attributes. "
3701
+ "When user upload a media, can select in which attribute that media can add."
3702
+ msgstr ""
3703
+
3704
+ #: app/helper/RTMediaAddon.php:143
3705
+ msgid "Docs and Other files"
3706
+ msgstr ""
3707
+
3708
+ #: app/helper/RTMediaAddon.php:146
3709
+ msgid ""
3710
+ "Allow users to upload documents and other file type using rtMedia upload "
3711
+ "box. This addon support all the file extensions which WordPress allows."
3712
+ msgstr ""
3713
+
3714
+ #: app/helper/RTMediaAddon.php:154
3715
+ msgid "Default Albums"
3716
+ msgstr ""
3717
+
3718
+ #: app/helper/RTMediaAddon.php:157
3719
+ msgid ""
3720
+ "This plugin allows the creation of multiple default albums for rtMedia "
3721
+ "uploads. One of these albums can be set as the default global album."
3722
+ msgstr ""
3723
+
3724
+ #: app/helper/RTMediaAddon.php:165
3725
+ msgid "Podcast (RSS and Atom feeds)"
3726
+ msgstr ""
3727
+
3728
+ #: app/helper/RTMediaAddon.php:168
3729
+ msgid ""
3730
+ "Read rtMedia uploads from iTunes as well as any RSS feed-reader/podcasting "
3731
+ "software."
3732
+ msgstr ""
3733
+
3734
+ #: app/helper/RTMediaAddon.php:176
3735
+ msgid "Playlists"
3736
+ msgstr ""
3737
+
3738
+ #: app/helper/RTMediaAddon.php:179
3739
+ msgid ""
3740
+ "Audio can be grouped into playlists. Once the user upload any audio file, "
3741
+ "can create a playlist or use existing one to manage audio files."
3742
+ msgstr ""
3743
+
3744
+ #: app/helper/RTMediaAddon.php:187
3745
+ msgid "Favorites"
3746
+ msgstr ""
3747
+
3748
+ #: app/helper/RTMediaAddon.php:190
3749
+ msgid ""
3750
+ "Users can create their list of favorite media in which they can add media "
3751
+ "previously uploaded by any user."
3752
+ msgstr ""
3753
+
3754
+ #: app/helper/RTMediaAddon.php:198
3755
+ msgid "Restrictions"
3756
+ msgstr ""
3757
+
3758
+ #: app/helper/RTMediaAddon.php:201
3759
+ msgid ""
3760
+ "Site admin can set an upload limit on the basis of time span, file size (MB) "
3761
+ "and number of files user can upload."
3762
+ msgstr ""
3763
+
3764
+ #: app/helper/RTMediaAddon.php:209
3765
+ msgid "bbPress Attachments"
3766
+ msgstr ""
3767
+
3768
+ #: app/helper/RTMediaAddon.php:212
3769
+ msgid "Attach media files to bbPress forum topics and replies."
3770
+ msgstr ""
3771
+
3772
+ #: app/helper/RTMediaAddon.php:220
3773
+ msgid "WordPress Sitewide Gallery"
3774
+ msgstr ""
3775
+
3776
+ #: app/helper/RTMediaAddon.php:223
3777
+ msgid ""
3778
+ "Site admin can create and upload media into WordPress album. Create album "
3779
+ "without being dependent on BuddyPress."
3780
+ msgstr ""
3781
+
3782
+ #: app/helper/RTMediaAddon.php:231
3783
+ msgid "WordPress Comment Attachments"
3784
+ msgstr ""
3785
+
3786
+ #: app/helper/RTMediaAddon.php:234
3787
+ msgid ""
3788
+ "Allow users to upload a media file in WordPress comment attachment box. It "
3789
+ "will display a thumbnail of attached file."
3790
+ msgstr ""
3791
+
3792
+ #: app/helper/RTMediaAddon.php:242
3793
+ msgid "Social Sharing"
3794
+ msgstr ""
3795
+
3796
+ #: app/helper/RTMediaAddon.php:245
3797
+ msgid ""
3798
+ "Share uploaded media on social network sites like Facebook, twitter, "
3799
+ "linkedin, Google +. This addon integrate with rtSocial plugin."
3800
+ msgstr ""
3801
+
3802
+ #: app/helper/RTMediaAddon.php:253
3803
+ msgid "Sidebar Widgets"
3804
+ msgstr ""
3805
+
3806
+ #: app/helper/RTMediaAddon.php:256
3807
+ msgid ""
3808
+ "This addon provide widgets to upload media and display gallery for rtMedia "
3809
+ "plugin."
3810
+ msgstr ""
3811
+
3812
+ #: app/helper/RTMediaAddon.php:264
3813
+ msgid "5 Star Ratings"
3814
+ msgstr ""
3815
+
3816
+ #: app/helper/RTMediaAddon.php:267
3817
+ msgid ""
3818
+ "Display 5 star rating for all the uploaded media. User can rate the media "
3819
+ "files from 1 to 5 star."
3820
+ msgstr ""
3821
+
3822
+ #: app/helper/RTMediaAddon.php:275
3823
+ msgid "Edit Mp3 Info (ID3 Tags)"
3824
+ msgstr ""
3825
+
3826
+ #: app/helper/RTMediaAddon.php:278
3827
+ msgid "Allow user to edit MP3 FIle Audio tags (ID 3 tags)."
3828
+ msgstr ""
3829
+
3830
+ #: app/helper/RTMediaAddon.php:286
3831
+ msgid "Media Sorting"
3832
+ msgstr ""
3833
+
3834
+ #: app/helper/RTMediaAddon.php:289
3835
+ msgid ""
3836
+ "Sort uploaded media based on file size, ascending/descending title, upload "
3837
+ "date of media."
3838
+ msgstr ""
3839
+
3840
+ #: app/helper/RTMediaAddon.php:297
3841
+ msgid "Bulk Edit"
3842
+ msgstr ""
3843
+
3844
+ #: app/helper/RTMediaAddon.php:300
3845
+ msgid ""
3846
+ "Bulk edit option will allow user to quickly select media files and do "
3847
+ "required actions like move files from one album to another, change "
3848
+ "attributes, change privacy, delete files."
3849
+ msgstr ""
3850
+
3851
+ #: app/helper/RTMediaAddon.php:308
3852
+ msgid "BuddyPress Profile Picture"
3853
+ msgstr ""
3854
+
3855
+ #: app/helper/RTMediaAddon.php:311
3856
+ msgid ""
3857
+ "User can easily set his/her profile picture from media uploaded via rtMedia."
3858
+ msgstr ""
3859
+
3860
+ #: app/helper/RTMediaAddon.php:319
3861
+ msgid "Album Cover Art"
3862
+ msgstr ""
3863
+
3864
+ #: app/helper/RTMediaAddon.php:322
3865
+ msgid "User can easily set any of the image of the album as album cover photo"
3866
+ msgstr ""
3867
+
3868
+ #: app/helper/RTMediaAddon.php:330
3869
+ msgid "Direct Download Link"
3870
+ msgstr ""
3871
+
3872
+ #: app/helper/RTMediaAddon.php:333
3873
+ msgid ""
3874
+ "User can download media from website. Site owner can restrict which media "
3875
+ "type can be allowed to download."
3876
+ msgstr ""
3877
+
3878
+ #: app/helper/RTMediaAddon.php:341
3879
+ msgid "Upload by URL"
3880
+ msgstr ""
3881
+
3882
+ #: app/helper/RTMediaAddon.php:344
3883
+ msgid ""
3884
+ "Users do not need to download media files from a URL and then upload it with "
3885
+ "rtMedia. Just provide the absolute URL for the media and it will upload on "
3886
+ "site."
3887
+ msgstr ""
3888
+
3889
+ #: app/helper/RTMediaAddon.php:352
3890
+ msgid "Media Likes"
3891
+ msgstr ""
3892
+
3893
+ #: app/helper/RTMediaAddon.php:355
3894
+ msgid ""
3895
+ "This add-on let you know who liked the media. User can also see which media "
3896
+ "they liked under their profile."
3897
+ msgstr ""
3898
+
3899
+ #: app/helper/RTMediaAddon.php:363
3900
+ msgid "Activity URL Preview"
3901
+ msgstr ""
3902
+
3903
+ #: app/helper/RTMediaAddon.php:366
3904
+ msgid ""
3905
+ "This addon provides a preview of the URL that is shared in BuddyPress "
3906
+ "activity. Just enter the URL you want to share on your site and see a "
3907
+ "preview of it before it is shared."
3908
+ msgstr ""
3909
+
3910
+ #: app/helper/RTMediaAddon.php:374
3911
+ msgid "View Counter"
3912
+ msgstr ""
3913
+
3914
+ #: app/helper/RTMediaAddon.php:377
3915
+ msgid ""
3916
+ "Enable view count for all the uploaded media. Whenever user open that media "
3917
+ "file in lightbox or in single media view, that view count will be calculated "
3918
+ "and display next to media file."
3919
+ msgstr ""
3920
+
3921
+ #: app/helper/RTMediaAddon.php:385
3922
+ msgid "Shortcode Generator"
3923
+ msgstr ""
3924
+
3925
+ #: app/helper/RTMediaAddon.php:388
3926
+ msgid ""
3927
+ "This add-on will add shortcode generator button in WordPress post and page "
3928
+ "editor for all the rtMedia shortcodes."
3929
+ msgstr ""
3930
+
3931
+ #: app/helper/RTMediaAddon.php:396
3932
+ msgid "Album Privacy"
3933
+ msgstr ""
3934
+
3935
+ #: app/helper/RTMediaAddon.php:399
3936
+ msgid ""
3937
+ "Set album privacy when user create an album or change album privacy when "
3938
+ "editing existing albums. The privacy levels are Public, Logged in user, "
3939
+ "Friends and Private."
3940
+ msgstr ""
3941
+
3942
+ #: app/helper/RTMediaAddon.php:407
3943
+ msgid "BuddyPress Group Media Control"
3944
+ msgstr ""
3945
+
3946
+ #: app/helper/RTMediaAddon.php:410
3947
+ msgid ""
3948
+ "This add-on allows group owner to manage media upload feature group wise."
3949
+ msgstr ""
3950
+
3951
+ #: app/helper/RTMediaAddon.php:418
3952
+ msgid "Set Custom Thumbnail for Audio/Video"
3953
+ msgstr ""
3954
+
3955
+ #: app/helper/RTMediaAddon.php:421
3956
+ msgid ""
3957
+ "Allow media owner to change the thumbnail of uploaded audio/video files. The "
3958
+ "File Upload box will be provided to change media thumbnail."
3959
+ msgstr ""
3960
+
3961
+ #: app/helper/RTMediaAddon.php:429
3962
+ msgid "myCRED"
3963
+ msgstr ""
3964
+
3965
+ #: app/helper/RTMediaAddon.php:432
3966
+ msgid ""
3967
+ "This plugin integrates rtMedia and myCRED plugin, users can be can award "
3968
+ "virtual points for various rtMedia activities, like media upload, likes, "
3969
+ "deleted etc."
3970
+ msgstr ""
3971
+
3972
+ #: app/helper/RTMediaAddon.php:440
3973
+ msgid "Upload terms"
3974
+ msgstr ""
3975
+
3976
+ #: app/helper/RTMediaAddon.php:443
3977
+ msgid ""
3978
+ "User must have to check the terms and conditions checkbox before uploading "
3979
+ "the media."
3980
+ msgstr ""
3981
+
3982
+ #: app/helper/RTMediaAddon.php:451
3983
+ msgid "CubePoints"
3984
+ msgstr ""
3985
+
3986
+ #: app/helper/RTMediaAddon.php:454
3987
+ msgid ""
3988
+ "If you are using CubePoints plugin on your website than rtMedia CubePoint "
3989
+ "add-on can be integrate with that plugin to setup point management system "
3990
+ "for rtMedia related activities."
3991
+ msgstr ""
3992
+
3993
+ #: app/helper/RTMediaAddon.php:462
3994
+ msgid "Social Sync"
3995
+ msgstr ""
3996
+
3997
+ #: app/helper/RTMediaAddon.php:465
3998
+ msgid ""
3999
+ "rtMedia Social Sync allows you to import media from your Facebook account."
4000
+ msgstr ""
4001
+
4002
+ #: app/helper/RTMediaAddon.php:473
4003
+ msgid "Photo Watermark"
4004
+ msgstr ""
4005
+
4006
+ #: app/helper/RTMediaAddon.php:476
4007
+ msgid ""
4008
+ "rtMedia Photo Watermark let you add watermark on your images uploaded using "
4009
+ "rtMedia."
4010
+ msgstr ""
4011
+
4012
+ #: app/helper/RTMediaAddon.php:484
4013
+ msgid "Photo Tagging"
4014
+ msgstr ""
4015
+
4016
+ #: app/helper/RTMediaAddon.php:487
4017
+ msgid ""
4018
+ "rtMedia Photo Tagging enable users to tag their friends on photos uploaded "
4019
+ "using rtMedia."
4020
+ msgstr ""
4021
+
4022
+ #: app/helper/RTMediaAddon.php:495
4023
+ msgid "Photo Filters"
4024
+ msgstr ""
4025
+
4026
+ #: app/helper/RTMediaAddon.php:498
4027
+ msgid ""
4028
+ "rtMedia Photo Filters adds Instagram like filters to images uploaded with "
4029
+ "rtMedia."
4030
+ msgstr ""
4031
+
4032
+ #: app/helper/RTMediaAddon.php:506
4033
+ msgid "Kaltura Add-on"
4034
+ msgstr ""
4035
+
4036
+ #: app/helper/RTMediaAddon.php:509
4037
+ msgid ""
4038
+ "Add support for more video formats using Kaltura video solution. It works "
4039
+ "with Kaltura.com, self-hosted Kaltura-CE and Kaltura-on-premise."
4040
+ msgstr ""
4041
+
4042
+ #: app/helper/RTMediaAddon.php:517
4043
+ msgid "FFMPEG Add-on"
4044
+ msgstr ""
4045
+
4046
+ #: app/helper/RTMediaAddon.php:520
4047
+ msgid ""
4048
+ "Add supports for more audio & video formats using open-source media-node. "
4049
+ "Media node comes with automated setup script for Ubuntu/Debian."
4050
+ msgstr ""
4051
+
4052
+ #: app/helper/RTMediaAddon.php:528
4053
+ msgid "Membership Add-on"
4054
+ msgstr ""
4055
+
4056
+ #: app/helper/RTMediaAddon.php:531
4057
+ msgid ""
4058
+ "rtMedia Membership add-on provides membership functionality in your site in "
4059
+ "terms of media upload."
4060
+ msgstr ""
4061
+
4062
+ #: app/helper/RTMediaAddon.php:571
4063
+ msgid "Coming Soon !!"
4064
+ msgstr ""
4065
+
4066
+ #: app/helper/RTMediaAddon.php:604
4067
+ msgid "Purchased"
4068
+ msgstr ""
4069
+
4070
+ #: app/helper/RTMediaUploadException.php:41
4071
+ msgid ""
4072
+ "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in "
4073
+ "the HTML form"
4074
+ msgstr ""
4075
+
4076
+ #: app/helper/RTMediaUploadException.php:44
4077
+ msgid "No file was uploaded"
4078
+ msgstr ""
4079
+
4080
+ #: app/helper/RTMediaUploadException.php:49
4081
+ msgid "Uploade failed due to internal server error."
4082
+ msgstr ""
4083
+
4084
+ #: app/helper/RTMediaUploadException.php:52
4085
+ msgid "File type not allowed."
4086
+ msgstr ""
4087
+
4088
+ #: app/helper/RTMediaUploadException.php:56
4089
+ msgid "Invalid Context for upload."
4090
+ msgstr ""
4091
+
4092
+ #: app/helper/RTMediaUploadException.php:59
4093
+ msgid "Unknown file upload error."
4094
+ msgstr ""
4095
+
4096
+ #: app/helper/RTMediaCommentNotification.php:60
4097
+ msgid "commented on your"
4098
+ msgstr ""
4099
+
4100
+ #: app/helper/RTMediaCommentNotification.php:62
4101
+ msgid "new comments on your"
4102
+ msgstr ""
4103
+
4104
+ #: app/helper/RTMediaFeed.php:52
4105
+ msgid "No items"
4106
+ msgstr ""
4107
+
4108
+ #: app/helper/RTMediaFeed.php:58
4109
+ msgid "Posted "
4110
+ msgstr ""
4111
+
4112
+ #: app/helper/RTMediaThemes.php:60 app/helper/RTMediaThemes.php:61
4113
+ msgid "Themes By rtCamp"
4114
+ msgstr ""
4115
+
4116
+ #: app/helper/RTMediaThemes.php:67 app/helper/RTMediaThemes.php:68
4117
+ msgid "3rd Party Themes"
4118
+ msgstr ""
4119
+
4120
+ #: app/helper/RTMediaThemes.php:105
4121
+ msgid "rtDating"
4122
+ msgstr ""
4123
+
4124
+ #: app/helper/RTMediaThemes.php:108 app/helper/RTMediaThemes.php:118
4125
+ #: app/helper/RTMediaThemes.php:128
4126
+ msgid "rtCamp"
4127
+ msgstr ""
4128
+
4129
+ #: app/helper/RTMediaThemes.php:111
4130
+ msgid ""
4131
+ "rtDating is a unique, clean and modern theme only for WordPress. This theme "
4132
+ "is mostly useful for dating sites and community websites. It can also be use "
4133
+ "for any other WordPress based website."
4134
+ msgstr ""
4135
+
4136
+ #: app/helper/RTMediaThemes.php:115
4137
+ msgid "InspireBook"
4138
+ msgstr ""
4139
+
4140
+ #: app/helper/RTMediaThemes.php:121
4141
+ msgid ""
4142
+ "InspireBook is a premium WordPress theme, designed especially for BuddyPress "
4143
+ "and rtMedia powered social-networks."
4144
+ msgstr ""
4145
+
4146
+ #: app/helper/RTMediaThemes.php:125
4147
+ msgid "Foodmania"
4148
+ msgstr ""
4149
+
4150
+ #: app/helper/RTMediaThemes.php:131
4151
+ msgid ""
4152
+ "Its premium WordPress theme, designed especially for Food, recipe and "
4153
+ "photography community sites."
4154
+ msgstr ""
4155
+
4156
+ #: app/helper/RTMediaThemes.php:149 app/helper/RTMediaThemes.php:274
4157
+ msgid "Theme Details"
4158
+ msgstr ""
4159
+
4160
+ #: app/helper/RTMediaThemes.php:161 app/helper/RTMediaThemes.php:286
4161
+ msgid "Show previous theme"
4162
+ msgstr ""
4163
+
4164
+ #: app/helper/RTMediaThemes.php:162 app/helper/RTMediaThemes.php:287
4165
+ msgid "Show next theme"
4166
+ msgstr ""
4167
+
4168
+ #: app/helper/RTMediaThemes.php:163 app/helper/RTMediaThemes.php:288
4169
+ msgid "Close overlay"
4170
+ msgstr ""
4171
+
4172
+ #: app/helper/RTMediaThemes.php:176 app/helper/RTMediaThemes.php:301
4173
+ msgid "Read More"
4174
+ msgstr ""
4175
+
4176
+ #: app/helper/RTMediaThemes.php:177 app/helper/RTMediaThemes.php:302
4177
+ msgid "Tags:"
4178
+ msgstr ""
4179
+
4180
+ #: app/helper/RTMediaThemes.php:209
4181
+ msgid "Thrive - Intranet & Community WordPress Theme"
4182
+ msgstr ""
4183
+
4184
+ #: app/helper/RTMediaThemes.php:212 app/helper/RTMediaThemes.php:232
4185
+ msgid "dunhakdis"
4186
  msgstr ""
4187
 
4188
+ #: app/helper/RTMediaThemes.php:215
4189
  msgid ""
4190
+ "Thrive is an innovative WordPress Theme designed to cater company portals, "
4191
+ "organisational websites, company intranet and extranets."
4192
  msgstr ""
4193
 
4194
+ #: app/helper/RTMediaThemes.php:219
4195
+ msgid "(M) SOCIAL NETWORK BUDDYPRESS THEME"
4196
  msgstr ""
4197
 
4198
+ #: app/helper/RTMediaThemes.php:222
4199
+ msgid "gavick"
4200
  msgstr ""
4201
 
4202
+ #: app/helper/RTMediaThemes.php:225
4203
  msgid ""
4204
+ "(M)Social is a sophisticated, vibrant community theme that offers incredible "
4205
+ "grid layouts, with full BuddyPress support so your users can interact with "
4206
+ "each other, create their own pages, and share their thoughts and images with "
4207
+ "the community."
4208
  msgstr ""
4209
 
4210
+ #: app/helper/RTMediaThemes.php:229
4211
+ msgid "Klein"
4212
  msgstr ""
4213
 
4214
+ #: app/helper/RTMediaThemes.php:235
4215
  msgid ""
4216
+ "Klein is an innovative WordPress theme built to support BuddyPress, bbPress, "
4217
+ "and WooCommerce out of the box. Perfect for websites that interacts with "
4218
+ "many users."
4219
  msgstr ""
4220
 
4221
+ #: app/helper/RTMediaThemes.php:239
4222
+ msgid "SweetDate"
4223
  msgstr ""
4224
 
4225
+ #: app/helper/RTMediaThemes.php:242 app/helper/RTMediaThemes.php:252
4226
+ msgid "SeventhQueen"
4227
  msgstr ""
4228
 
4229
+ #: app/helper/RTMediaThemes.php:245
4230
  msgid ""
4231
+ "SweetDate is a unique, clean and modern Premium Wordpress theme. It is "
4232
+ "perfect for a dating or community website but can be used as well for any "
4233
+ "other domain. They added all the things you need to create a perfect "
4234
+ "community system."
4235
  msgstr ""
4236
 
4237
+ #: app/helper/RTMediaThemes.php:249
4238
+ msgid "KLEO"
4239
  msgstr ""
4240
 
4241
+ #: app/helper/RTMediaThemes.php:255
4242
+ msgid ""
4243
+ "You no longer need to be a professional developer or designer to create an "
4244
+ "awesome website. Let your imagination run wild and create the site of your "
4245
+ "dreams. KLEO has all the tools to get you started."
4246
  msgstr ""
4247
 
4248
+ #: app/helper/RTMediaThemes.php:318
4249
+ msgid ""
4250
+ "These are the third party themes. For any issues or queries regarding these "
4251
+ "themes please contact theme developers."
4252
  msgstr ""
4253
 
4254
+ #: app/helper/RTMediaThemes.php:321
4255
+ msgid "Are you a developer?"
4256
  msgstr ""
4257
 
4258
+ #: app/helper/RTMediaThemes.php:324
4259
+ msgid ""
4260
+ "If you have developed a rtMedia compatible theme and would like it to list "
4261
+ "here, please email us at"
4262
  msgstr ""
4263
 
4264
+ #: app/helper/RTMediaThemes.php:325
4265
+ msgid "product@rtcamp.com"
4266
  msgstr ""
4267
 
4268
+ #: app/helper/rtFormInvalidArgumentsException.php:21
4269
+ #, php-format
4270
+ msgid ""
4271
+ "Error on line %s in %s : <b>The method expects an array in arguments for %s "
4272
+ "provided.</b>"
4273
  msgstr ""
4274
 
4275
+ #: app/helper/RTMediaAdminWidget.php:32
4276
+ msgid "Argument missing. id is required."
4277
  msgstr ""
4278
 
4279
+ #: app/helper/RTMediaLikeNotification.php:91
4280
+ msgid "liked your"
4281
  msgstr ""
4282
 
4283
+ #: app/helper/RTMediaLikeNotification.php:93
4284
+ msgid "and one more friend liked your"
4285
  msgstr ""
4286
 
4287
+ #: app/helper/RTMediaLikeNotification.php:96
4288
+ msgid "and"
4289
  msgstr ""
4290
 
4291
+ #: app/helper/RTMediaLikeNotification.php:96
4292
+ msgid "other friends liked your"
4293
  msgstr ""
4294
 
4295
+ #: app/helper/RTMediaLicense.php:56
4296
+ msgid "Activated"
4297
  msgstr ""
4298
 
4299
+ #: app/helper/RTMediaLicense.php:59
4300
+ msgid "Deactivated"
4301
  msgstr ""
4302
 
4303
+ #: app/helper/RTMediaLicense.php:68
4304
+ msgid "Status: "
4305
  msgstr ""
4306
 
4307
+ #: app/helper/RTMediaLicense.php:77
4308
+ msgid "License Key"
4309
  msgstr ""
4310
 
4311
+ #: app/helper/RTMediaLicense.php:88
4312
+ msgid "Activate / Deactivate License"
4313
  msgstr ""
4314
 
4315
+ #: app/helper/RTMediaLicense.php:99
4316
+ msgid "Activate License"
4317
  msgstr ""
4318
 
4319
+ #: app/helper/RTMediaSettings.php:208
4320
+ msgid "BuddyPress Media Addons for Photos"
4321
  msgstr ""
4322
 
4323
+ #: app/helper/RTMediaSettings.php:212
4324
+ msgid "rtMedia Themes"
4325
  msgstr ""
4326
 
4327
+ #: app/helper/RTMediaSettings.php:285
4328
+ #, php-format
4329
+ msgid ""
4330
+ "Currently your network allows uploading of the following file types. You can "
4331
+ "change the settings <a href=\"%s\">here</a>.<br /><code>%s</code></span>"
4332
  msgstr ""
4333
 
4334
+ #: app/helper/RTMediaSettings.php:303 app/helper/RTMediaSettings.php:305
4335
+ msgid "Recounting of media files done successfully"
4336
  msgstr ""
4337
 
4338
+ #: app/helper/RTMediaSettings.php:305
4339
+ msgid "Recount Success"
 
4340
  msgstr ""
4341
 
4342
+ #: app/helper/RTMediaSettings.php:309 app/helper/RTMediaSettings.php:311
4343
+ msgid "Recounting Failed"
4344
  msgstr ""
4345
 
4346
+ #: app/helper/RTMediaSettings.php:311
4347
+ msgid "Recount Fail"
4348
  msgstr ""
4349
 
4350
+ #: app/helper/RTMediaSettings.php:324 app/helper/RTMediaSettings.php:326
4351
+ msgid "Atleast one Media Type Must be selected"
4352
  msgstr ""
4353
 
4354
+ #: app/helper/RTMediaSettings.php:335 app/helper/RTMediaSettings.php:337
4355
+ msgid "\"Number of media\" count value should be numeric and greater than 0."
4356
  msgstr ""
4357
 
4358
+ #: app/helper/RTMediaSettings.php:337
4359
+ msgid "Default Count"
4360
  msgstr ""
4361
 
4362
+ #: app/helper/RTMediaSettings.php:342
4363
+ msgid "Settings saved."
4364
  msgstr ""
4365
 
4366
+ #: app/helper/RTMediaSettings.php:366
4367
+ #, php-format
4368
+ msgid ""
4369
+ "If you make changes to width, height or crop settings, you must use \"<a "
4370
+ "href=\"%s\">Regenerate Thumbnail Plugin</a>\" to regenerate old images.\""
4371
  msgstr ""
4372
 
4373
+ #: app/helper/RTMediaSettings.php:387
4374
+ msgid "BuddyPress Media 2.6 requires a database upgrade. "
4375
  msgstr ""
4376
 
4377
+ #: app/helper/RTMediaSettings.php:387
4378
+ msgid "Update Database"
 
 
4379
  msgstr ""
4380
 
4381
+ #: app/helper/RTMediaSettings.php:404
4382
+ msgid ""
4383
+ "If your site has some issues due to BuddyPress Media and you want one on one "
4384
+ "support then you can create a support topic on the <a target=\"_blank\" href="
4385
+ "\"http://community.rtcamp.com/c/rtmedia?"
4386
+ "utm_source=dashboard&utm_medium=plugin&utm_campaign=rtmedia\">rtCamp Support "
4387
+ "Forum</a>."
4388
  msgstr ""
4389
 
4390
+ #: app/helper/RTMediaSettings.php:405
4391
  msgid ""
4392
+ "If you have any suggestions, enhancements or bug reports, then you can open "
4393
+ "a new issue on <a target=\"_blank\" href=\"https://github.com/rtCamp/rtmedia/"
4394
+ "issues/new\">GitHub</a>."
 
 
4395
  msgstr ""
4396
 
4397
+ #: templates/media/media-single-edit.php:26
4398
+ #: templates/media/album-single-edit.php:32
4399
+ msgid "Title : "
4400
  msgstr ""
4401
 
4402
+ #: templates/media/media-single-edit.php:32
4403
+ #: templates/media/album-single-edit.php:37
4404
+ msgid "Description: "
4405
  msgstr ""
4406
 
4407
+ #: templates/media/media-single-edit.php:46
4408
+ msgid "Save"
4409
  msgstr ""
4410
 
4411
+ #: templates/media/media-single-edit.php:47
4412
+ #: templates/media/album-single-edit.php:48
4413
+ msgid "Back"
4414
  msgstr ""
4415
 
4416
+ #: templates/media/media-single-edit.php:54
4417
+ msgid "Sorry !! You do not have rights to edit this media"
4418
  msgstr ""
4419
 
4420
+ #: templates/media/media-single-edit.php:61
4421
+ #: templates/media/album-gallery.php:64 templates/media/media-single.php:146
4422
+ msgid "Sorry !! There's no media found for the request !!"
4423
  msgstr ""
4424
 
4425
  #: templates/media/album-gallery.php:14
4426
  msgid "Album List"
4427
  msgstr ""
4428
 
 
 
 
 
 
 
4429
  #: templates/media/album-single-edit.php:12
4430
  msgid "Edit Album : "
4431
  msgstr ""
4434
  msgid "Manage Media"
4435
  msgstr ""
4436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4437
  #: templates/media/album-single-edit.php:63
4438
  msgid "Move Selected media to another album."
4439
  msgstr ""
4478
  msgid "Oops !! There's no media found for the request !!"
4479
  msgstr ""
4480
 
 
 
 
 
 
 
 
 
4481
  #: templates/media/media-single.php:35
4482
  msgid "under"
4483
  msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/freemius/LICENSE.txt ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ {description}
294
+ Copyright (C) {year} {fullname}
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ {signature of Ty Coon}, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
340
+
lib/freemius/assets/css/admin/account.css ADDED
@@ -0,0 +1 @@
 
1
+ #fs_account .postbox,#fs_account .widefat{max-width:700px}#fs_account .fs-header-actions{position:absolute;top:10px;right:10px;font-size:0.9em}#fs_account .fs-header-actions ul{margin:0}#fs_account .fs-header-actions li{float:left}#fs_account .fs-header-actions li form{display:inline-block}#fs_account .fs-header-actions li a{text-decoration:none}.rtl #fs_account .fs-header-actions{left:10px;right:auto}.fs-key-value-table{width:100%}.fs-key-value-table form{display:inline-block}.fs-key-value-table td label{background:orange;color:#fff;display:inline-block;border-radius:3px;padding:5px;font-size:11px;line-height:11px;vertical-align:baseline}.fs-key-value-table tr td:first-child{text-align:right}.fs-key-value-table tr td:first-child nobr{font-weight:bold}.fs-key-value-table tr td:first-child form{display:block}.fs-key-value-table tr td.fs-right{text-align:right}.fs-key-value-table tr.fs-odd{background:#ebebeb}.fs-key-value-table td,.fs-key-value-table th{padding:10px}.fs-key-value-table var,.fs-key-value-table code{color:#0073AA;font-size:16px;background:none}#fs_addons td:first-child,#fs_addons th:first-child{text-align:left;font-weight:bold}#fs_addons td:last-child,#fs_addons th:last-child{text-align:right}#fs_addons th{font-weight:bold}
lib/freemius/assets/css/admin/add-ons.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+ #fs_addons .fs-cards-list{list-style:none}#fs_addons .fs-cards-list .fs-card{float:left;height:152px;width:310px;padding:0;margin:0 0 30px 30px;font-size:14px;list-style:none;border:1px solid #ddd;cursor:pointer;position:relative}#fs_addons .fs-cards-list .fs-card .fs-overlay{position:absolute;left:0;right:0;bottom:0;top:0;z-index:9}#fs_addons .fs-cards-list .fs-card .fs-inner{background-color:#fff;overflow:hidden;height:100%;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner ul{-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s;left:0;right:0;top:0;position:absolute}#fs_addons .fs-cards-list .fs-card .fs-inner li{list-style:none;line-height:18px;padding:0 15px;width:100%;display:block;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner{padding:0;margin:0;line-height:0;display:block;height:100px;background-repeat:repeat-x;-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-title{margin:10px 0 0 0;height:18px;overflow:hidden;color:#000;white-space:nowrap;text-overflow:ellipsis;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-offer{font-size:0.9em}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-description{background-color:#f9f9f9;padding:10px 15px 100px 15px;border-top:1px solid #eee;margin:0 0 10px 0;color:#777}@media screen and (min-width: 960px){#fs_addons .fs-cards-list .fs-card:hover .fs-overlay{border:2px solid #29abe1;margin-left:-1px;margin-top:-1px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner ul{top:-100px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-title,#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-offer{color:#29abe1}}
2
+ #TB_window,#TB_window iframe{width:772px !important}#plugin-information #section-description h2,#plugin-information #section-description h3,#plugin-information #section-description p,#plugin-information #section-description b,#plugin-information #section-description i,#plugin-information #section-description blockquote,#plugin-information #section-description li,#plugin-information #section-description ul,#plugin-information #section-description ol{clear:none}#plugin-information #section-description .fs-selling-points{padding-bottom:10px;border-bottom:1px solid #ddd}#plugin-information #section-description .fs-selling-points ul{margin:0}#plugin-information #section-description .fs-selling-points ul li{padding:0;list-style:none outside none}#plugin-information #section-description .fs-selling-points ul li i.dashicons{color:#71ae00;font-size:3em;vertical-align:middle;line-height:30px;float:left;margin:0 0 0 -15px}#plugin-information #section-description .fs-selling-points ul li h3{margin-left:30px}#plugin-information #section-description .fs-screenshots:after{content:"";display:table;clear:both}#plugin-information #section-description .fs-screenshots ul{list-style:none;margin:0}#plugin-information #section-description .fs-screenshots ul li{width:225px;height:225px;float:left;margin-bottom:20px;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}#plugin-information #section-description .fs-screenshots ul li a{display:block;width:100%;height:100%;border:1px solid;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.2);box-shadow:1px 1px 1px rgba(0,0,0,0.2);background-size:cover}#plugin-information #section-description .fs-screenshots ul li.odd{margin-right:20px}#plugin-information .plugin-information-pricing{background:#FFFEEC;margin:-16px;padding:20px 20px 50px 20px;border-bottom:1px solid #DDD}#plugin-information .plugin-information-pricing h3{margin-top:0}#plugin-information .plugin-information-pricing .button{width:100%;text-align:center;font-weight:bold;text-transform:uppercase;font-size:1.1em}#plugin-information .plugin-information-pricing label{white-space:nowrap}#plugin-information #section-features .fs-features{margin:-20px -26px}#plugin-information #section-features table{width:100%;border-spacing:0;border-collapse:separate}#plugin-information #section-features table thead th{padding:10px 0}#plugin-information #section-features table thead .fs-price{color:#71ae00;font-weight:normal;display:block;text-align:center}#plugin-information #section-features table tbody td{border-top:1px solid #ccc;padding:10px 0;text-align:center;width:100px;color:#71ae00}#plugin-information #section-features table tbody td:first-child{text-align:left;width:auto;color:inherit;padding-left:26px}#plugin-information #section-features table tbody tr.fs-odd td{background:#fefefe}#plugin-information #section-features .dashicons-yes{width:30px;height:30px;font-size:30px}@media screen and (max-width: 961px){#fs_addons .fs-cards-list .fs-card{height:265px}}
lib/freemius/assets/css/admin/common.css ADDED
@@ -0,0 +1 @@
 
1
+ .fs-notice{position:relative}.fs-notice.fs-has-title{margin-bottom:30px !important}.fs-notice.success{color:green}.fs-notice.promotion{border-color:#00a0d2 !important;background-color:#f2fcff !important}.fs-notice .fs-close{position:absolute;top:10px;right:10px;cursor:pointer;color:#ccc}.fs-notice .fs-close:hover{color:#aaa}.fs-notice label.fs-plugin-title{background:rgba(0,0,0,0.3);color:#fff;padding:2px 10px;position:absolute;bottom:-22px;top:auto;right:auto;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;left:10px;font-size:12px;font-weight:bold;cursor:auto}.rtl .fs-notice .fs-close{left:10px;right:auto}.fs-secure-notice{position:fixed;top:32px;left:160px;right:0;background:#ebfdeb;padding:10px 20px;color:green;z-index:9999;box-shadow:0px 2px 2px rgba(6,113,6,0.3);opacity:0.95;filter:alpha(opacity=95)}.fs-secure-notice:hover{opacity:1;filter:alpha(opacity=100)}@media screen and (max-width: 960px){.fs-secure-notice{left:36px}}@media screen and (max-width: 782px){.fs-secure-notice{left:0;top:46px;text-align:center}}span.fs-submenu-item.fs-sub:before{content:'\21B3';padding:0 5px}.rtl span.fs-submenu-item.fs-sub:before{content:'\21B2'}
lib/freemius/assets/css/admin/connect.css ADDED
@@ -0,0 +1 @@
 
1
+ #fs_connect{width:480px;-moz-box-shadow:0px 1px 2px rgba(0,0,0,0.3);-webkit-box-shadow:0px 1px 2px rgba(0,0,0,0.3);box-shadow:0px 1px 2px rgba(0,0,0,0.3);margin:20px 0}@media screen and (max-width: 479px){#fs_connect{-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none;width:auto;margin:0 0 0 -10px}}#fs_connect .fs-content{background:#fff;padding:15px 20px}#fs_connect .fs-content p{margin:0;padding:0;font-size:1.2em}#fs_connect .fs-actions{padding:10px 20px;background:#C0C7CA}#fs_connect .fs-actions .button{padding:0 10px 1px;line-height:35px;height:37px;font-size:16px;margin-bottom:0}#fs_connect .fs-actions .button .dashicons{font-size:37px;margin-left:-8px;margin-right:12px}#fs_connect .fs-actions .button.button-primary{padding-right:15px;padding-left:15px}#fs_connect .fs-actions .button.button-primary:after{content:' \279C'}#fs_connect .fs-actions .button.button-secondary{float:right}#fs_connect.fs-anonymous-disabled .fs-actions .button.button-primary{width:100%}#fs_connect .fs-permissions{padding:10px 20px;background:#FEFEFE;-moz-transition:background 0.5s ease;-o-transition:background 0.5s ease;-ms-transition:background 0.5s ease;-webkit-transition:background 0.5s ease;transition:background 0.5s ease}#fs_connect .fs-permissions .fs-trigger{font-size:0.9em;text-decoration:none;text-align:center;display:block}#fs_connect .fs-permissions ul{height:0;overflow:hidden;margin:0}#fs_connect .fs-permissions ul li{margin-bottom:12px}#fs_connect .fs-permissions ul li:last-child{margin-bottom:0}#fs_connect .fs-permissions ul li i.dashicons{float:left;font-size:40px;width:40px;height:40px}#fs_connect .fs-permissions ul li div{margin-left:55px}#fs_connect .fs-permissions ul li div span{font-weight:bold;text-transform:uppercase;color:#23282d}#fs_connect .fs-permissions ul li div p{margin:2px 0 0 0}#fs_connect .fs-permissions.fs-open{background:#fff}#fs_connect .fs-permissions.fs-open ul{height:auto;margin:20px 20px 10px 20px}@media screen and (max-width: 479px){#fs_connect .fs-permissions{background:#fff}#fs_connect .fs-permissions .fs-trigger{display:none}#fs_connect .fs-permissions ul{height:auto;margin:20px}}#fs_connect .fs-visual{padding:12px;line-height:0;background:#fafafa;height:80px;position:relative}#fs_connect .fs-visual .fs-site-icon{position:absolute;left:20px;top:10px}#fs_connect .fs-visual .fs-connect-logo{position:absolute;right:20px;top:10px}#fs_connect .fs-visual .fs-plugin-icon{position:absolute;top:10px;left:50%;margin-left:-40px}#fs_connect .fs-visual .fs-plugin-icon,#fs_connect .fs-visual .fs-site-icon,#fs_connect .fs-visual img,#fs_connect .fs-visual object{width:80px;height:80px}#fs_connect .fs-visual .dashicons-wordpress{font-size:64px;background:#01749a;color:#fff;width:64px;height:64px;padding:8px}#fs_connect .fs-visual .dashicons-plus{position:absolute;top:50%;font-size:30px;margin-top:-10px;color:#bbb}#fs_connect .fs-visual .dashicons-plus.fs-first{left:28%}#fs_connect .fs-visual .dashicons-plus.fs-second{left:65%}#fs_connect .fs-visual .fs-plugin-icon,#fs_connect .fs-visual .fs-connect-logo,#fs_connect .fs-visual .fs-site-icon{border:1px solid #ccc;padding:1px;background:#fff}#fs_connect .fs-terms{text-align:center;font-size:0.85em;padding:5px;background:rgba(0,0,0,0.05)}#fs_connect .fs-terms,#fs_connect .fs-terms a{color:#999}#fs_connect .fs-terms a{text-decoration:none}.rtl #fs_connect .fs-actions{padding:10px 20px;background:#C0C7CA}.rtl #fs_connect .fs-actions .button .dashicons{font-size:37px;margin-left:-8px;margin-right:12px}.rtl #fs_connect .fs-actions .button.button-primary:after{content:' \000bb'}.rtl #fs_connect .fs-actions .button.button-secondary{float:left}.rtl #fs_connect .fs-permissions ul li div{margin-right:55px;margin-left:0}.rtl #fs_connect .fs-permissions ul li i.dashicons{float:right}.rtl #fs_connect .fs-visual .fs-site-icon{right:20px;left:auto}.rtl #fs_connect .fs-visual .fs-connect-logo{right:auto;left:20px}.wp-pointer-content #fs_connect{margin:0;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}.fs-opt-in-pointer .wp-pointer-content{padding:0}.fs-opt-in-pointer.wp-pointer-top .wp-pointer-arrow{border-bottom-color:#dfdfdf}.fs-opt-in-pointer.wp-pointer-top .wp-pointer-arrow-inner{border-bottom-color:#fafafa}.fs-opt-in-pointer.wp-pointer-bottom .wp-pointer-arrow{border-top-color:#dfdfdf}.fs-opt-in-pointer.wp-pointer-bottom .wp-pointer-arrow-inner{border-top-color:#fafafa}.fs-opt-in-pointer.wp-pointer-left .wp-pointer-arrow{border-right-color:#dfdfdf}.fs-opt-in-pointer.wp-pointer-left .wp-pointer-arrow-inner{border-right-color:#fafafa}.fs-opt-in-pointer.wp-pointer-right .wp-pointer-arrow{border-left-color:#dfdfdf}.fs-opt-in-pointer.wp-pointer-right .wp-pointer-arrow-inner{border-left-color:#fafafa}
lib/freemius/assets/css/admin/deactivation-feedback.css ADDED
@@ -0,0 +1 @@
 
1
+ .fs-modal{position:fixed;overflow:auto;height:100%;width:100%;top:0;z-index:100000;display:none;background:rgba(0,0,0,0.6)}.fs-modal .fs-modal-dialog{background:transparent;position:absolute;left:50%;margin-left:-298px;padding-bottom:30px;top:-100%;z-index:100001;width:596px}@media (max-width: 650px){.fs-modal .fs-modal-dialog{margin-left:-50%;box-sizing:border-box;padding-left:10px;padding-right:10px;width:100%}.fs-modal .fs-modal-dialog .fs-modal-panel>h3>strong{font-size:1.3em}.fs-modal .fs-modal-dialog li.reason{margin-bottom:10px}.fs-modal .fs-modal-dialog li.reason .reason-input{margin-left:29px}.fs-modal .fs-modal-dialog li.reason label{display:table}.fs-modal .fs-modal-dialog li.reason label>span{display:table-cell;font-size:1.3em}}.fs-modal.active{display:block}.fs-modal.active:before{display:block}.fs-modal.active .fs-modal-dialog{top:10%}.fs-modal .fs-modal-body,.fs-modal .fs-modal-footer{border:0;background:#fefefe;padding:20px}.fs-modal .fs-modal-body{border-bottom:0}.fs-modal .fs-modal-body h2{font-size:20px}.fs-modal .fs-modal-body>div{margin-top:10px}.fs-modal .fs-modal-body>div h2{font-weight:bold;font-size:20px;margin-top:0}.fs-modal .fs-modal-footer{border-top:#eeeeee solid 1px;text-align:right}.fs-modal .fs-modal-footer>.button{margin:0 7px}.fs-modal .fs-modal-footer>.button:first-child{margin:0}.fs-modal .fs-modal-panel:not(.active){display:none}.fs-modal .reason-input{margin:3px 0 3px 22px}.fs-modal .reason-input input,.fs-modal .reason-input textarea{width:100%}body.has-fs-modal{overflow:hidden}#the-list .deactivate>.fs-slug{display:none}
lib/freemius/assets/css/common.css ADDED
@@ -0,0 +1 @@
 
1
+ .fs-notice.success{color:green;font-weight:700}
lib/freemius/assets/img/icon.png ADDED
Binary file
lib/freemius/assets/img/plugin-icon.png ADDED
Binary file
lib/freemius/assets/js/jquery.ba-postmessage.js ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery postMessage - v0.5 - 9/11/2009
3
+ * http://benalman.com/projects/jquery-postmessage-plugin/
4
+ *
5
+ * Copyright (c) 2009 "Cowboy" Ben Alman
6
+ * Dual licensed under the MIT and GPL licenses.
7
+ * http://benalman.com/about/license/
8
+ */
9
+
10
+ // Script: jQuery postMessage: Cross-domain scripting goodness
11
+ //
12
+ // *Version: 0.5, Last updated: 9/11/2009*
13
+ //
14
+ // Project Home - http://benalman.com/projects/jquery-postmessage-plugin/
15
+ // GitHub - http://github.com/cowboy/jquery-postmessage/
16
+ // Source - http://github.com/cowboy/jquery-postmessage/raw/master/jquery.ba-postmessage.js
17
+ // (Minified) - http://github.com/cowboy/jquery-postmessage/raw/master/jquery.ba-postmessage.min.js (0.9kb)
18
+ //
19
+ // About: License
20
+ //
21
+ // Copyright (c) 2009 "Cowboy" Ben Alman,
22
+ // Dual licensed under the MIT and GPL licenses.
23
+ // http://benalman.com/about/license/
24
+ //
25
+ // About: Examples
26
+ //
27
+ // This working example, complete with fully commented code, illustrates one
28
+ // way in which this plugin can be used.
29
+ //
30
+ // Iframe resizing - http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
31
+ //
32
+ // About: Support and Testing
33
+ //
34
+ // Information about what version or versions of jQuery this plugin has been
35
+ // tested with and what browsers it has been tested in.
36
+ //
37
+ // jQuery Versions - 1.3.2
38
+ // Browsers Tested - Internet Explorer 6-8, Firefox 3, Safari 3-4, Chrome, Opera 9.
39
+ //
40
+ // About: Release History
41
+ //
42
+ // 0.5 - (9/11/2009) Improved cache-busting
43
+ // 0.4 - (8/25/2009) Initial release
44
+
45
+ (function($){
46
+ '$:nomunge'; // Used by YUI compressor.
47
+
48
+ // A few vars used in non-awesome browsers.
49
+ var interval_id,
50
+ last_hash,
51
+ cache_bust = 1,
52
+
53
+ // A var used in awesome browsers.
54
+ rm_callback,
55
+
56
+ // A few convenient shortcuts.
57
+ window = this,
58
+ FALSE = !1,
59
+
60
+ // Reused internal strings.
61
+ postMessage = 'postMessage',
62
+ addEventListener = 'addEventListener',
63
+
64
+ p_receiveMessage,
65
+
66
+ // I couldn't get window.postMessage to actually work in Opera 9.64!
67
+ has_postMessage = window[postMessage] && !$.browser.opera;
68
+
69
+ // Method: jQuery.postMessage
70
+ //
71
+ // This method will call window.postMessage if available, setting the
72
+ // targetOrigin parameter to the base of the target_url parameter for maximum
73
+ // security in browsers that support it. If window.postMessage is not available,
74
+ // the target window's location.hash will be used to pass the message. If an
75
+ // object is passed as the message param, it will be serialized into a string
76
+ // using the jQuery.param method.
77
+ //
78
+ // Usage:
79
+ //
80
+ // > jQuery.postMessage( message, target_url [, target ] );
81
+ //
82
+ // Arguments:
83
+ //
84
+ // message - (String) A message to be passed to the other frame.
85
+ // message - (Object) An object to be serialized into a params string, using
86
+ // the jQuery.param method.
87
+ // target_url - (String) The URL of the other frame this window is
88
+ // attempting to communicate with. This must be the exact URL (including
89
+ // any query string) of the other window for this script to work in
90
+ // browsers that don't support window.postMessage.
91
+ // target - (Object) A reference to the other frame this window is
92
+ // attempting to communicate with. If omitted, defaults to `parent`.
93
+ //
94
+ // Returns:
95
+ //
96
+ // Nothing.
97
+
98
+ $[postMessage] = function( message, target_url, target ) {
99
+ if ( !target_url ) { return; }
100
+
101
+ // Serialize the message if not a string. Note that this is the only real
102
+ // jQuery dependency for this script. If removed, this script could be
103
+ // written as very basic JavaScript.
104
+ message = typeof message === 'string' ? message : $.param( message );
105
+
106
+ // Default to parent if unspecified.
107
+ target = target || parent;
108
+
109
+ if ( has_postMessage ) {
110
+ // The browser supports window.postMessage, so call it with a targetOrigin
111
+ // set appropriately, based on the target_url parameter.
112
+ target[postMessage]( message, target_url.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ) );
113
+
114
+ } else if ( target_url ) {
115
+ // The browser does not support window.postMessage, so set the location
116
+ // of the target to target_url#message. A bit ugly, but it works! A cache
117
+ // bust parameter is added to ensure that repeat messages trigger the
118
+ // callback.
119
+ target.location = target_url.replace( /#.*$/, '' ) + '#' + (+new Date) + (cache_bust++) + '&' + message;
120
+ }
121
+ };
122
+
123
+ // Method: jQuery.receiveMessage
124
+ //
125
+ // Register a single callback for either a window.postMessage call, if
126
+ // supported, or if unsupported, for any change in the current window
127
+ // location.hash. If window.postMessage is supported and source_origin is
128
+ // specified, the source window will be checked against this for maximum
129
+ // security. If window.postMessage is unsupported, a polling loop will be
130
+ // started to watch for changes to the location.hash.
131
+ //
132
+ // Note that for simplicity's sake, only a single callback can be registered
133
+ // at one time. Passing no params will unbind this event (or stop the polling
134
+ // loop), and calling this method a second time with another callback will
135
+ // unbind the event (or stop the polling loop) first, before binding the new
136
+ // callback.
137
+ //
138
+ // Also note that if window.postMessage is available, the optional
139
+ // source_origin param will be used to test the event.origin property. From
140
+ // the MDC window.postMessage docs: This string is the concatenation of the
141
+ // protocol and "://", the host name if one exists, and ":" followed by a port
142
+ // number if a port is present and differs from the default port for the given
143
+ // protocol. Examples of typical origins are https://example.org (implying
144
+ // port 443), http://example.net (implying port 80), and http://example.com:8080.
145
+ //
146
+ // Usage:
147
+ //
148
+ // > jQuery.receiveMessage( callback [, source_origin ] [, delay ] );
149
+ //
150
+ // Arguments:
151
+ //
152
+ // callback - (Function) This callback will execute whenever a <jQuery.postMessage>
153
+ // message is received, provided the source_origin matches. If callback is
154
+ // omitted, any existing receiveMessage event bind or polling loop will be
155
+ // canceled.
156
+ // source_origin - (String) If window.postMessage is available and this value
157
+ // is not equal to the event.origin property, the callback will not be
158
+ // called.
159
+ // source_origin - (Function) If window.postMessage is available and this
160
+ // function returns false when passed the event.origin property, the
161
+ // callback will not be called.
162
+ // delay - (Number) An optional zero-or-greater delay in milliseconds at
163
+ // which the polling loop will execute (for browser that don't support
164
+ // window.postMessage). If omitted, defaults to 100.
165
+ //
166
+ // Returns:
167
+ //
168
+ // Nothing!
169
+
170
+ $.receiveMessage = p_receiveMessage = function( callback, source_origin, delay ) {
171
+ if ( has_postMessage ) {
172
+ // Since the browser supports window.postMessage, the callback will be
173
+ // bound to the actual event associated with window.postMessage.
174
+
175
+ if ( callback ) {
176
+ // Unbind an existing callback if it exists.
177
+ rm_callback && p_receiveMessage();
178
+
179
+ // Bind the callback. A reference to the callback is stored for ease of
180
+ // unbinding.
181
+ rm_callback = function(e) {
182
+ if ( ( typeof source_origin === 'string' && e.origin !== source_origin )
183
+ || ( $.isFunction( source_origin ) && source_origin( e.origin ) === FALSE ) ) {
184
+ return FALSE;
185
+ }
186
+ callback( e );
187
+ };
188
+ }
189
+
190
+ if ( window[addEventListener] ) {
191
+ window[ callback ? addEventListener : 'removeEventListener' ]( 'message', rm_callback, FALSE );
192
+ } else {
193
+ window[ callback ? 'attachEvent' : 'detachEvent' ]( 'onmessage', rm_callback );
194
+ }
195
+
196
+ } else {
197
+ // Since the browser sucks, a polling loop will be started, and the
198
+ // callback will be called whenever the location.hash changes.
199
+
200
+ interval_id && clearInterval( interval_id );
201
+ interval_id = null;
202
+
203
+ if ( callback ) {
204
+ delay = typeof source_origin === 'number'
205
+ ? source_origin
206
+ : typeof delay === 'number'
207
+ ? delay
208
+ : 100;
209
+
210
+ interval_id = setInterval(function(){
211
+ var hash = document.location.hash,
212
+ re = /^#?\d+&/;
213
+ if ( hash !== last_hash && re.test( hash ) ) {
214
+ last_hash = hash;
215
+ callback({ data: hash.replace( re, '' ) });
216
+ }
217
+ }, delay );
218
+ }
219
+ }
220
+ };
221
+
222
+ })(jQuery);
lib/freemius/assets/js/jquery.ba-postmessage.min.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery postMessage - v0.5 - 9/11/2009
3
+ * http://benalman.com/projects/jquery-postmessage-plugin/
4
+ *
5
+ * Copyright (c) 2009 "Cowboy" Ben Alman
6
+ * Dual licensed under the MIT and GPL licenses.
7
+ * http://benalman.com/about/license/
8
+ */
9
+ (function($){var g,d,j=1,a,b=this,f=!1,h="postMessage",e="addEventListener",c,i=b[h]&&!$.browser.opera;$[h]=function(k,l,m){if(!l){return}k=typeof k==="string"?k:$.param(k);m=m||parent;if(i){m[h](k,l.replace(/([^:]+:\/\/[^\/]+).*/,"$1"))}else{if(l){m.location=l.replace(/#.*$/,"")+"#"+(+new Date)+(j++)+"&"+k}}};$.receiveMessage=c=function(l,m,k){if(i){if(l){a&&c();a=function(n){if((typeof m==="string"&&n.origin!==m)||($.isFunction(m)&&m(n.origin)===f)){return f}l(n)}}if(b[e]){b[l?e:"removeEventListener"]("message",a,f)}else{b[l?"attachEvent":"detachEvent"]("onmessage",a)}}else{g&&clearInterval(g);g=null;if(l){k=typeof m==="number"?m:typeof k==="number"?k:100;g=setInterval(function(){var o=document.location.hash,n=/^#?\d+&/;if(o!==d&&n.test(o)){d=o;l({data:o.replace(n,"")})}},k)}}}})(jQuery);
lib/freemius/assets/js/nojquery.ba-postmessage.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery postMessage - v0.5 - 9/11/2009
3
+ * http://benalman.com/projects/jquery-postmessage-plugin/
4
+ *
5
+ * Copyright (c) 2009 "Cowboy" Ben Alman
6
+ * Dual licensed under the MIT and GPL licenses.
7
+ * http://benalman.com/about/license/
8
+ *
9
+ * Non-jQuery fork by Jeff Lee
10
+ *
11
+ * This fork consists of the following changes:
12
+ * 1. Basic code cleanup and restructuring, for legibility.
13
+ * 2. The `postMessage` and `receiveMessage` functions can be bound arbitrarily,
14
+ * in terms of both function names and object scope. Scope is specified by
15
+ * the the "this" context of NoJQueryPostMessageMixin();
16
+ * 3. I've removed the check for Opera 9.64, which used `$.browser`. There were
17
+ * at least three different GitHub users requesting the removal of this
18
+ * "Opera sniff" on the original project's Issues page, so I figured this
19
+ * would be a relatively safe change.
20
+ * 4. `postMessage` no longer uses `$.param` to serialize messages that are not
21
+ * strings. I actually prefer this structure anyway. `receiveMessage` does
22
+ * not implement a corresponding deserialization step, and as such it seems
23
+ * cleaner and more symmetric to leave both data serialization and
24
+ * deserialization to the client.
25
+ * 5. The use of `$.isFunction` is replaced by a functionally-identical check.
26
+ * 6. The `$:nomunge` YUI option is no longer necessary.
27
+ */
28
+
29
+ function NoJQueryPostMessageMixin(postBinding, receiveBinding) {
30
+
31
+ var setMessageCallback, unsetMessageCallback, currentMsgCallback,
32
+ intervalId, lastHash, cacheBust = 1;
33
+
34
+ if (window.postMessage) {
35
+
36
+ if (window.addEventListener) {
37
+ setMessageCallback = function(callback) {
38
+ window.addEventListener('message', callback, false);
39
+ }
40
+
41
+ unsetMessageCallback = function(callback) {
42
+ window.removeEventListener('message', callback, false);
43
+ }
44
+ } else {
45
+ setMessageCallback = function(callback) {
46
+ window.attachEvent('onmessage', callback);
47
+ }
48
+
49
+ unsetMessageCallback = function(callback) {
50
+ window.detachEvent('onmessage', callback);
51
+ }
52
+ }
53
+
54
+ this[postBinding] = function(message, targetUrl, target) {
55
+ if (!targetUrl) {
56
+ return;
57
+ }
58
+
59
+ // The browser supports window.postMessage, so call it with a targetOrigin
60
+ // set appropriately, based on the targetUrl parameter.
61
+ target.postMessage( message, targetUrl.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ) );
62
+ }
63
+
64
+ // Since the browser supports window.postMessage, the callback will be
65
+ // bound to the actual event associated with window.postMessage.
66
+ this[receiveBinding] = function(callback, sourceOrigin, delay) {
67
+ // Unbind an existing callback if it exists.
68
+ if (currentMsgCallback) {
69
+ unsetMessageCallback(currentMsgCallback);
70
+ currentMsgCallback = null;
71
+ }
72
+
73
+ if (!callback) {
74
+ return false;
75
+ }
76
+
77
+ // Bind the callback. A reference to the callback is stored for ease of
78
+ // unbinding.
79
+ currentMsgCallback = setMessageCallback(function(e) {
80
+ switch(Object.prototype.toString.call(sourceOrigin)) {
81
+ case '[object String]':
82
+ if (sourceOrigin !== e.origin) {
83
+ return false;
84
+ }
85
+ break;
86
+ case '[object Function]':
87
+ if (sourceOrigin(e.origin)) {
88
+ return false;
89
+ }
90
+ break;
91
+ }
92
+
93
+ callback(e);
94
+ });
95
+ };
96
+
97
+ } else {
98
+
99
+ this[postBinding] = function(message, targetUrl, target) {
100
+ if (!targetUrl) {
101
+ return;
102
+ }
103
+
104
+ // The browser does not support window.postMessage, so set the location
105
+ // of the target to targetUrl#message. A bit ugly, but it works! A cache
106
+ // bust parameter is added to ensure that repeat messages trigger the
107
+ // callback.
108
+ target.location = targetUrl.replace( /#.*$/, '' ) + '#' + (+new Date) + (cacheBust++) + '&' + message;
109
+ }
110
+
111
+ // Since the browser sucks, a polling loop will be started, and the
112
+ // callback will be called whenever the location.hash changes.
113
+ this[receiveBinding] = function(callback, sourceOrigin, delay) {
114
+ if (intervalId) {
115
+ clearInterval(intervalId);
116
+ intervalId = null;
117
+ }
118
+
119
+ if (callback) {
120
+ delay = typeof sourceOrigin === 'number'
121
+ ? sourceOrigin
122
+ : typeof delay === 'number'
123
+ ? delay
124
+ : 100;
125
+
126
+ intervalId = setInterval(function(){
127
+ var hash = document.location.hash,
128
+ re = /^#?\d+&/;
129
+ if ( hash !== lastHash && re.test( hash ) ) {
130
+ lastHash = hash;
131
+ callback({ data: hash.replace( re, '' ) });
132
+ }
133
+ }, delay );
134
+ }
135
+ };
136
+
137
+ }
138
+
139
+ return this;
140
+ }
lib/freemius/assets/js/nojquery.ba-postmessage.min.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * nojquery-postmessage by Jeff Lee
3
+ * a non-jQuery fork of:
4
+ *
5
+ * jQuery postMessage - v0.5 - 9/11/2009
6
+ * http://benalman.com/projects/jquery-postmessage-plugin/
7
+ *
8
+ * Copyright (c) 2009 "Cowboy" Ben Alman
9
+ * Dual licensed under the MIT and GPL licenses.
10
+ * http://benalman.com/about/license/
11
+ */
12
+ function NoJQueryPostMessageMixin(g,a){var b,h,e,d,f,c=1;if(window.postMessage){if(window.addEventListener){b=function(i){window.addEventListener("message",i,false)};h=function(i){window.removeEventListener("message",i,false)}}else{b=function(i){window.attachEvent("onmessage",i)};h=function(i){window.detachEvent("onmessage",i)}}this[g]=function(i,k,j){if(!k){return}j.postMessage(i,k.replace(/([^:]+:\/\/[^\/]+).*/,"$1"))};this[a]=function(k,j,i){if(e){h(e);e=null}if(!k){return false}e=b(function(l){switch(Object.prototype.toString.call(j)){case"[object String]":if(j!==l.origin){return false}break;case"[object Function]":if(j(l.origin)){return false}break}k(l)})}}else{this[g]=function(i,k,j){if(!k){return}j.location=k.replace(/#.*$/,"")+"#"+(+new Date)+(c++)+"&"+i};this[a]=function(k,j,i){if(d){clearInterval(d);d=null}if(k){i=typeof j==="number"?j:typeof i==="number"?i:100;d=setInterval(function(){var m=document.location.hash,l=/^#?\d+&/;if(m!==f&&l.test(m)){f=m;k({data:m.replace(l,"")})}},i)}}}return this};
lib/freemius/assets/js/postmessage.js ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, undef) {
2
+ var global = this;
3
+
4
+ // Namespace.
5
+ global.FS = global.FS || {};
6
+
7
+ global.FS.PostMessage = function ()
8
+ {
9
+ var
10
+ _is_child = false,
11
+ _postman = new NoJQueryPostMessageMixin('postMessage', 'receiveMessage'),
12
+ _callbacks = {},
13
+ _base_url,
14
+ _parent_url = decodeURIComponent(document.location.hash.replace(/^#/, '')),
15
+ _parent_subdomain = _parent_url.substring(0, _parent_url.indexOf('/', ('https://' === _parent_url.substring(0, ('https://').length)) ? 8 : 7)),
16
+ _init = function () {
17
+ _postman.receiveMessage(function (e) {
18
+ var data = JSON.parse(e.data);
19
+
20
+ if (_callbacks[data.type]) {
21
+ for (var i = 0; i < _callbacks[data.type].length; i++) {
22
+ // Execute type callbacks.
23
+ _callbacks[data.type][i](data.data);
24
+ }
25
+ }
26
+ }, _base_url);
27
+ };
28
+
29
+ return {
30
+ init : function (url)
31
+ {
32
+ _base_url = url;
33
+ _init();
34
+
35
+ // Automatically receive forward messages.
36
+ FS.PostMessage.receiveOnce('forward', function (data){
37
+ window.location = data.url;
38
+ });
39
+ },
40
+ init_child : function ()
41
+ {
42
+ this.init(_parent_subdomain);
43
+
44
+ _is_child = true;
45
+
46
+ // Post height of a child right after window is loaded.
47
+ $(window).bind('load', function () {
48
+ FS.PostMessage.postHeight();
49
+ });
50
+
51
+ },
52
+ postHeight : function (diff, wrapper) {
53
+ diff = diff || 0;
54
+ wrapper = wrapper || '#wrap_section';
55
+ this.post('height', {
56
+ height: diff + $(wrapper).outerHeight(true)
57
+ });
58
+ },
59
+ post : function (type, data, iframe)
60
+ {
61
+ console.debug('PostMessage.post', type);
62
+
63
+ if (iframe)
64
+ {
65
+ // Post to iframe.
66
+ _postman.postMessage(JSON.stringify({
67
+ type: type,
68
+ data: data
69
+ }), iframe.src, iframe.contentWindow);
70
+ }
71
+ else {
72
+ // Post to parent.
73
+ _postman.postMessage(JSON.stringify({
74
+ type: type,
75
+ data: data
76
+ }), _parent_url, window.parent);
77
+ }
78
+ },
79
+ receive: function (type, callback)
80
+ {
81
+ console.debug('PostMessage.receive', type);
82
+
83
+ if (undef === _callbacks[type])
84
+ _callbacks[type] = [];
85
+
86
+ _callbacks[type].push(callback);
87
+ },
88
+ receiveOnce: function (type, callback)
89
+ {
90
+ if (this.is_set(type))
91
+ return;
92
+
93
+ this.receive(type, callback);
94
+ },
95
+ // Check if any callbacks assigned to a specified message type.
96
+ is_set: function (type)
97
+ {
98
+ return (undef != _callbacks[type]);
99
+ },
100
+ parent_url: function ()
101
+ {
102
+ return _parent_url;
103
+ },
104
+ parent_subdomain: function ()
105
+ {
106
+ return _parent_subdomain;
107
+ }
108
+ };
109
+ }();
110
+ })(jQuery);
lib/freemius/assets/scss/_colors.scss ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $menu-hover-color: #333;
2
+ $darkest-color: #000;
3
+ $fms-live-color: #71ae00;
4
+ $fms-test-color: #f7941d;
5
+ $fms-link-color: #29abe1;
6
+ $fms-link-hover-color: darken(#29abe1, 10%);
7
+ $body-bkg: #111;
8
+ $special-color: #d3135a;
9
+ $body-color: #f1f1f1;
10
+ $fms-white: #f1f1f1;
11
+ $container-bkg: #222;
12
+ $container-bkg-odd: #262626;
13
+ $container-border-color: #333;
14
+ $table-head-bkg: #333;
15
+ $table-head-color: #999;
16
+ $info-color: #999;
17
+ $error-color: #ff0000;
18
+
19
+ $fs-logo-blue-color: #29abe1;
20
+ $fs-logo-green-color: #71ae00;
21
+ $fs-logo-magenta-color: #d3135a;
22
+
23
+ $fs-notice-promotion-border-color: #00a0d2;
24
+ $fs-notice-promotion-bkg: #f2fcff;
25
+
26
+ // WordPress colors.
27
+ $page-header-bkg: #333;
28
+ $page-header-color: $fms-white;
29
+ $text-dark-color: #333;
30
+ $text-light-color: #666;
31
+ $text-lightest-color: #999;
32
+
33
+ // WP Buttons.
34
+ $button-primary-bkg: #6bc406;
35
+ $button-primary-color: $fms-white;
36
+ $button-secondary-bkg: #333;
37
+ $button-secondary-color: $fms-white;
38
+ $featured-color: #6bc406;
39
+ $wp-selected-color: #0074a3;
40
+
41
+ $wordpress_color: #01749A;
42
+ $blogger_color: #ff8100;
43
+ $wix_color: #fac102;
44
+ $shopify_color: #80d100;
45
+ $addthis_color: #fe6d4e;
46
+ $tumblr_color: #34506b;
47
+ $zepo_color: #00baf2;
48
+ $jquery_color: #000919;
49
+ $javascript_color: #00baf2;
50
+ $squarespace_color: #000;
51
+
52
+ $blog_color: #ff6600;
53
+ $facebook_color: #3b5998;
54
+ $twitter_color: #4099ff;
55
+ $linkedin_color: #4875b4;
56
+ $youtube_color: #ff3333;
57
+ $gplus_color: #c63d2d;
58
+
lib/freemius/assets/scss/_functions.scss ADDED
File without changes
lib/freemius/assets/scss/_load.scss ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ @import 'mixins';
2
+ @import "vars";
3
+ @import "functions";
4
+ @import "colors";
lib/freemius/assets/scss/_mixins.scss ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ---- CSS3 SASS MIXINS ----
2
+ // https://github.com/madr/css3-sass-mixins
3
+ //
4
+ // Copyright (C) 2011 by Anders Ytterström
5
+ //
6
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ // of this software and associated documentation files (the "Software"), to deal
8
+ // in the Software without restriction, including without limitation the rights
9
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ // copies of the Software, and to permit persons to whom the Software is
11
+ // furnished to do so, subject to the following conditions:
12
+ //
13
+ // The above copyright notice and this permission notice shall be included in
14
+ // all copies or substantial portions of the Software.
15
+ //
16
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ // THE SOFTWARE.
23
+ //
24
+
25
+ // ---- LEGACY IE SUPPORT USING FILTERS ----
26
+ // Should IE filters be used or not?
27
+ // PROS: gradients, drop shadows etc will be handled by css.
28
+ // CONS: will harm the site performance badly,
29
+ // especially on sites with heavy rendering and scripting.
30
+ $useIEFilters: 0;
31
+ // might be 0 or 1. disabled by default.
32
+ // ---- /LEGACY IE SUPPORT USING FILTERS ----
33
+
34
+
35
+ @mixin background-size ($value) {
36
+ -webkit-background-size: $value;
37
+ background-size: $value;
38
+ }
39
+
40
+ @mixin border-image ($path, $offsets, $repeats) {
41
+ -moz-border-image: $path $offsets $repeats;
42
+ -o-border-image: $path $offsets $repeats;
43
+ -webkit-border-image: $path $offsets $repeats;
44
+ border-image: $path $offsets $repeats;
45
+ }
46
+
47
+ @mixin border-radius ($values...) {
48
+ -moz-border-radius: $values;
49
+ -webkit-border-radius: $values;
50
+ border-radius: $values;
51
+ /*-moz-background-clip: padding;
52
+ -webkit-background-clip: padding-box;
53
+ background-clip: padding-box;*/
54
+ }
55
+
56
+ @mixin box-shadow ($values...) {
57
+ -moz-box-shadow: $values;
58
+ -webkit-box-shadow: $values;
59
+ box-shadow: $values;
60
+ }
61
+
62
+ //@mixin box-shadow ($x, $y, $offset, $hex, $ie: $useIEFilters, $inset: null, $spread:null) {
63
+ // -moz-box-shadow: $x $y $offset $spread $hex $inset;
64
+ // -webkit-box-shadow: $x $y $offset $spread $hex $inset;
65
+ // box-shadow: $x $y $offset $spread $hex $inset;
66
+ //
67
+ // @if $ie == 1 {
68
+ // $iecolor: '#' + red($hex) + green($hex) + blue($hex);
69
+ // filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=#{$x}, OffY=#{$y}, Color='#{$iecolor}');
70
+ // -ms-filter: quote(progid:DXImageTransform.Microsoft.dropshadow(OffX=#{$x}, OffY=#{$y}, Color='#{$iecolor}'));
71
+ // }
72
+ //}
73
+
74
+ @mixin box-sizing($value) {
75
+ -moz-box-sizing: $value;
76
+ -webkit-box-sizing: $value;
77
+ box-sizing: $value;
78
+ }
79
+
80
+ // requires sass 3.2
81
+ //@mixin keyframes {
82
+ // @-moz-keyframes { @content; }
83
+ // @-ms-keyframes { @content; }
84
+ // @-o-keyframes { @content; }
85
+ // @-webkit-keyframes { @content; }
86
+ // @keyframes { @content; }
87
+ //}
88
+
89
+ @mixin linear-gradient($from, $to, $ie: $useIEFilters) {
90
+ @if $ie != 1 { background-color: $to; }
91
+
92
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, $from),color-stop(1, $to));
93
+ background-image: -webkit-linear-gradient(top, $from, $to);
94
+ background-image: -moz-linear-gradient(top, $from, $to);
95
+ background-image: -ms-linear-gradient(top, $from, $to);
96
+ background-image: -o-linear-gradient(top, $from, $to);
97
+ background-image: linear-gradient(top, bottom, $from, $to);
98
+
99
+ @if $ie == 1 {
100
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$from}', endColorstr='#{$to}');
101
+ }
102
+ }
103
+
104
+ @mixin horizontal-gradient($startColor: #555, $endColor: #333, $ie: $useIEFilters) {
105
+ @if $ie != 1 { background-color: $endColor; }
106
+
107
+ background-color: $endColor;
108
+ background-image: -webkit-gradient(linear, 0 0, 100% 0, from($startColor), to($endColor)); // Safari 4+, Chrome 2+
109
+ background-image: -webkit-linear-gradient(left, $startColor, $endColor); // Safari 5.1+, Chrome 10+
110
+ background-image: -moz-linear-gradient(left, $startColor, $endColor); // FF 3.6+
111
+ background-image: -o-linear-gradient(left, $startColor, $endColor); // Opera 11.10
112
+ background-image: linear-gradient(to right, $startColor, $endColor); // Standard, IE10
113
+ background-repeat: repeat-x;
114
+ @if $ie == 1 {
115
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$startColor}', endColorstr='#{$endColor}', GradientType=1);
116
+ }
117
+ }
118
+
119
+ @mixin radial-gradient($from, $to, $ie: $useIEFilters) {
120
+ @if $ie != 1 { background-color: $to; }
121
+
122
+ background: -moz-radial-gradient(center, circle cover, $from 0%, $to 100%);
123
+ background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, $from), color-stop(100%, $to));
124
+ background: -webkit-radial-gradient(center, circle cover, $from 0%, $to 100%);
125
+ background: -o-radial-gradient(center, circle cover, $from 0%, $to 100%);
126
+ background: -ms-radial-gradient(center, circle cover, $from 0%, $to 100%);
127
+ background: radial-gradient(center, circle cover, $from 0%, $to 100%);
128
+ background-color: $from;
129
+
130
+ @if $ie == 1 {
131
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$from}', endColorstr='#{$to}', GradientType=1); /* IE6-9 fallback on horizontal gradient */
132
+ }
133
+ }
134
+
135
+ /*@mixin rgba-bg ($hex, $alpha, $ie: $useIEFilters) {
136
+ @if $ie == 1 {
137
+ background-color: none;
138
+ $hexopac: ie-hex-str(rgba($hex, $alpha));
139
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#{$hexopac}',EndColorStr='#{$hexopac}}');
140
+ -ms-filter: quote(progid:DXImageTransform.Microsoft.gradient(startColorStr='#{$hexopac}',EndColorStr='#{$hexopac}'));
141
+ }
142
+ @else {
143
+ background-color: $hex;
144
+ background-color: rgba($hex, $alpha);
145
+ }
146
+ }*/
147
+
148
+ @mixin perspective($perspective) {
149
+ -moz-perspective: $perspective;
150
+ -ms-perspective: $perspective;
151
+ -webkit-perspective: $perspective;
152
+ perspective: $perspective;
153
+ -moz-transform-style: preserve-3d;
154
+ -ms-transform-style: preserve-3d;
155
+ -webkit-transform-style: preserve-3d;
156
+ transform-style: preserve-3d;
157
+ }
158
+
159
+ @mixin transform ($transforms) {
160
+ -moz-transform: $transforms;
161
+ -o-transform: $transforms;
162
+ -ms-transform: $transforms;
163
+ -webkit-transform: $transforms;
164
+ transform: $transforms;
165
+ }
166
+
167
+ @mixin matrix ($a, $b, $c, $d, $e, $f) {
168
+ -moz-transform: matrix($a, $b, $c, $d, #{$e}px, #{$f}px);
169
+ -o-transform: matrix($a, $b, $c, $d, $e, $f);
170
+ -ms-transform: matrix($a, $b, $c, $d, $e, $f);
171
+ -webkit-transform: matrix($a, $b, $c, $d, $e, $f);
172
+ transform: matrix($a, $b, $c, $d, $e, $f);
173
+ }
174
+
175
+ @mixin rotate ($deg) {
176
+ @include transform(rotate(#{$deg}deg));
177
+ }
178
+
179
+ @mixin scale ($size) {
180
+ @include transform(scale(#{$size}));
181
+ }
182
+
183
+ @mixin translate ($x, $y) {
184
+ @include transform(translate($x, $y));
185
+ }
186
+
187
+ @mixin transition ($value...) {
188
+ -moz-transition: $value;
189
+ -o-transition: $value;
190
+ -ms-transition: $value;
191
+ -webkit-transition: $value;
192
+ transition: $value;
193
+ }
194
+
195
+ // ==== /CSS3 SASS MIXINS ====
196
+
197
+ @mixin opacity($opacity) {
198
+ opacity: $opacity;
199
+ $opacity-ie: $opacity * 100;
200
+ filter: alpha(opacity=$opacity-ie); //IE8
201
+ }
202
+
203
+ @mixin sprite($img, $width, $height: $width, $display: block)
204
+ {
205
+ display: $display;
206
+ background-image: url('#{$img}');
207
+
208
+ @include size($width, $height);
209
+ }
210
+
211
+ @mixin size($width, $height: $width)
212
+ {
213
+ width: $width;
214
+ height: $height;
215
+ }
216
+
217
+ @mixin clearfix
218
+ {
219
+ &:after {
220
+ content: "";
221
+ display: table;
222
+ clear: both;
223
+ }
224
+ }
lib/freemius/assets/scss/_start.scss ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ @import "vars";
2
+ @import "colors";
3
+ @import "mixins";
4
+ @import "functions";
lib/freemius/assets/scss/_vars.scss ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ $is_production: true;
2
+
3
+ $img_common: if($is_production == true, '//img.freemius.com', 'http://img.freemius:8080');
4
+
5
+ $layout_width: 960px;
lib/freemius/assets/scss/admin/account.scss ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #fs_account
2
+ {
3
+ .postbox,
4
+ .widefat
5
+ {
6
+ max-width: 700px;
7
+ }
8
+
9
+ .fs-header-actions
10
+ {
11
+ position: absolute;
12
+ top: 10px;
13
+ right: 10px;
14
+ font-size: 0.9em;
15
+
16
+ ul
17
+ {
18
+ margin: 0;
19
+ }
20
+
21
+ li
22
+ {
23
+ form
24
+ {
25
+ display: inline-block;
26
+ }
27
+
28
+ float: left;
29
+ a
30
+ {
31
+ text-decoration: none;
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ .rtl #fs_account .fs-header-actions
38
+ {
39
+ left: 10px;
40
+ right: auto;
41
+ }
42
+
43
+ .fs-key-value-table
44
+ {
45
+ width: 100%;
46
+
47
+ form
48
+ {
49
+ display: inline-block;
50
+ }
51
+
52
+ td label
53
+ {
54
+ background: orange;
55
+ color: #fff;
56
+ display: inline-block;
57
+ border-radius: 3px;
58
+ padding: 5px;
59
+ font-size: 11px;
60
+ line-height: 11px;
61
+ vertical-align: baseline;
62
+ }
63
+
64
+ tr
65
+ {
66
+ td:first-child
67
+ {
68
+ nobr
69
+ {
70
+ font-weight: bold;
71
+ }
72
+
73
+ text-align: right;
74
+
75
+ form
76
+ {
77
+ display: block;
78
+ }
79
+ }
80
+
81
+ td.fs-right
82
+ {
83
+ text-align: right;
84
+ }
85
+
86
+ &.fs-odd
87
+ {
88
+ background: #ebebeb;
89
+ }
90
+ }
91
+
92
+ td, th
93
+ {
94
+ padding: 10px;
95
+ }
96
+
97
+ var, code
98
+ {
99
+ color: #0073AA;
100
+ font-size: 16px;
101
+ background: none;
102
+ }
103
+ }
104
+
105
+ #fs_addons
106
+ {
107
+ td:first-child,
108
+ th:first-child
109
+ {
110
+ text-align: left;
111
+ font-weight: bold;
112
+ }
113
+ td:last-child,
114
+ th:last-child
115
+ {
116
+ text-align: right;
117
+ }
118
+ th
119
+ {
120
+ font-weight: bold;
121
+ }
122
+ }
lib/freemius/assets/scss/admin/add-ons.scss ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../start";
2
+
3
+ #fs_addons
4
+ {
5
+ .fs-cards-list
6
+ {
7
+ list-style: none;
8
+
9
+ .fs-card
10
+ {
11
+ float: left;
12
+ // height: 185px; // With reviews/ratings
13
+ height: 152px;
14
+ width: 310px;
15
+ padding: 0;
16
+ margin: 0 0 30px 30px;
17
+ font-size: 14px;
18
+ list-style: none;
19
+ border: 1px solid #ddd;
20
+ cursor: pointer;
21
+ position: relative;
22
+
23
+ .fs-overlay
24
+ {
25
+ position: absolute;
26
+ left: 0;
27
+ right: 0;
28
+ bottom: 0;
29
+ top: 0;
30
+ z-index: 9;
31
+ }
32
+
33
+ .fs-inner
34
+ {
35
+ background-color: #fff;
36
+ overflow: hidden;
37
+ height: 100%;
38
+ position: relative;
39
+
40
+ ul
41
+ {
42
+ @include transition(all, 0.15s);
43
+ left: 0;
44
+ right: 0;
45
+ top: 0;
46
+ position: absolute;
47
+
48
+ }
49
+
50
+ li
51
+ {
52
+ list-style: none;
53
+ line-height: 18px;
54
+ padding: 0 15px;
55
+ width: 100%;
56
+ display: block;
57
+ @include box-sizing(border-box);
58
+ }
59
+
60
+ .fs-card-banner
61
+ {
62
+ padding: 0;
63
+ margin: 0;
64
+ line-height: 0;
65
+ display: block;
66
+ height: 100px;
67
+ background-repeat: repeat-x;
68
+ background-size: 100% 100%;
69
+ @include transition(all, 0.15s);
70
+ }
71
+
72
+ .fs-title
73
+ {
74
+ margin: 10px 0 0 0;
75
+ height: 18px;
76
+ overflow: hidden;
77
+ color: #000;
78
+ white-space: nowrap;
79
+ text-overflow: ellipsis;
80
+ font-weight: bold;
81
+ }
82
+
83
+ .fs-offer
84
+ {
85
+ font-size: 0.9em;
86
+ }
87
+
88
+ .fs-description
89
+ {
90
+ background-color: #f9f9f9;
91
+ padding: 10px 15px 100px 15px;
92
+ border-top: 1px solid #eee;
93
+ margin: 0 0 10px 0;
94
+ color: #777;
95
+ }
96
+ }
97
+
98
+ @media screen and (min-width: 960px) {
99
+ &:hover
100
+ {
101
+ .fs-overlay
102
+ {
103
+ border: 2px solid $fms-link-color;
104
+ margin-left: -1px;
105
+ margin-top: -1px;
106
+ }
107
+
108
+ .fs-inner
109
+ {
110
+ ul
111
+ {
112
+ top: -100px;
113
+ }
114
+
115
+ .fs-card-banner
116
+ {
117
+ // background-position: 50% -100px;
118
+ }
119
+
120
+ .fs-title,
121
+ .fs-offer
122
+ {
123
+ color: $fms-link-color;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ #TB_window
133
+ {
134
+ &, iframe
135
+ {
136
+ width: 772px !important;
137
+ }
138
+ }
139
+
140
+ #plugin-information
141
+ {
142
+ #section-description
143
+ {
144
+ h2, h3, p, b, i, blockquote, li, ul, ol
145
+ {
146
+ clear: none;
147
+ }
148
+
149
+ .fs-selling-points
150
+ {
151
+ padding-bottom: 10px;
152
+ border-bottom: 1px solid #ddd;
153
+
154
+ ul
155
+ {
156
+ margin: 0;
157
+
158
+ li
159
+ {
160
+ padding: 0;
161
+ list-style: none outside none;
162
+
163
+ i.dashicons
164
+ {
165
+ color: $fs-logo-green-color;
166
+ font-size: 3em;
167
+ vertical-align: middle;
168
+ line-height: 30px;
169
+ float: left;
170
+ margin: 0 0 0 -15px;
171
+ }
172
+
173
+ h3
174
+ {
175
+ margin-left: 30px;
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ .fs-screenshots
182
+ {
183
+ @include clearfix();
184
+ ul
185
+ {
186
+ list-style: none;
187
+ margin: 0;
188
+
189
+ li
190
+ {
191
+ width: 225px;
192
+ height: 225px;
193
+ float: left;
194
+ margin-bottom: 20px;
195
+ @include box-sizing(content-box);
196
+
197
+ a
198
+ {
199
+ display: block;
200
+ width: 100%;
201
+ height: 100%;
202
+ border: 1px solid;
203
+ @include box-shadow(1px 1px 1px rgba(0,0,0,0.2));
204
+ background-size: cover;
205
+ }
206
+
207
+ &.odd
208
+ {
209
+ margin-right: 20px;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ .plugin-information-pricing
217
+ {
218
+ background: #FFFEEC;
219
+ margin: -16px;
220
+ padding: 20px 20px 50px 20px;
221
+ border-bottom: 1px solid #DDD;
222
+
223
+ h3
224
+ {
225
+ margin-top: 0;
226
+ }
227
+
228
+ .button
229
+ {
230
+ width: 100%;
231
+ text-align: center;
232
+ font-weight: bold;
233
+ text-transform: uppercase;
234
+ font-size: 1.1em;
235
+ }
236
+
237
+ label
238
+ {
239
+ white-space: nowrap;
240
+ }
241
+ }
242
+
243
+ #section-features
244
+ {
245
+ .fs-features
246
+ {
247
+ margin: -20px -26px;
248
+ }
249
+
250
+ table {
251
+ width: 100%;
252
+ border-spacing: 0;
253
+ border-collapse: separate;
254
+
255
+ thead {
256
+ th
257
+ {
258
+ padding: 10px 0;
259
+ }
260
+
261
+ .fs-price
262
+ {
263
+ color: $fs-logo-green-color;
264
+ font-weight: normal;
265
+ display: block;
266
+ text-align: center;
267
+ }
268
+ }
269
+
270
+ tbody
271
+ {
272
+ td
273
+ {
274
+ border-top: 1px solid #ccc;
275
+ padding: 10px 0;
276
+ text-align: center;
277
+ width: 100px;
278
+ color: $fs-logo-green-color;
279
+
280
+ &:first-child
281
+ {
282
+ text-align: left;
283
+ width: auto;
284
+ color: inherit;
285
+ padding-left: 26px;
286
+ }
287
+ }
288
+ tr.fs-odd
289
+ {
290
+ td
291
+ {
292
+ background: #fefefe;
293
+ }
294
+ }
295
+ }
296
+ }
297
+
298
+ .dashicons-yes
299
+ {
300
+ width: 30px;
301
+ height: 30px;
302
+ font-size: 30px;
303
+ }
304
+ }
305
+ }
306
+
307
+ @media screen and (max-width: 961px)
308
+ {
309
+ #fs_addons
310
+ {
311
+ .fs-cards-list
312
+ {
313
+ .fs-card
314
+ {
315
+ height: 265px;
316
+ }
317
+ }
318
+ }
319
+ }
lib/freemius/assets/scss/admin/common.scss ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../start";
2
+
3
+ .fs-notice
4
+ {
5
+ position: relative;
6
+
7
+ &.fs-has-title
8
+ {
9
+ margin-bottom: 30px !important;
10
+ }
11
+
12
+ &.success
13
+ {
14
+ color: green;
15
+ // font-weight: normal;
16
+ }
17
+
18
+ &.promotion
19
+ {
20
+ border-color: $fs-notice-promotion-border-color !important;
21
+ background-color: $fs-notice-promotion-bkg !important;
22
+ }
23
+
24
+ .fs-close
25
+ {
26
+ position: absolute;
27
+ top: 10px;
28
+ right: 10px;
29
+ cursor: pointer;
30
+ color: #ccc;
31
+
32
+ &:hover
33
+ {
34
+ color: #aaa;
35
+ }
36
+ }
37
+
38
+ label.fs-plugin-title
39
+ {
40
+ background: rgba(0, 0, 0, 0.3);
41
+ color: #fff;
42
+ padding: 2px 10px;
43
+ position: absolute;
44
+ bottom: -22px;
45
+ top: auto;
46
+ right: auto;
47
+ @include border-radius(0 0 3px 3px);
48
+ left: 10px;
49
+ font-size: 12px;
50
+ font-weight: bold;
51
+ cursor: auto;
52
+ }
53
+ }
54
+
55
+ .rtl .fs-notice .fs-close
56
+ {
57
+ left: 10px;
58
+ right: auto;
59
+ }
60
+
61
+ .fs-secure-notice
62
+ {
63
+ position: fixed;
64
+ top: 32px;
65
+ left: 160px;
66
+ right: 0;
67
+ background: rgb(235, 253, 235);
68
+ padding: 10px 20px;
69
+ color: green;
70
+ z-index: 9999;
71
+ box-shadow: 0px 2px 2px rgba(6, 113, 6, 0.3);
72
+ @include opacity(0.95);
73
+
74
+ &:hover
75
+ {
76
+ @include opacity(1);
77
+ }
78
+ }
79
+
80
+ @media screen and (max-width: 960px)
81
+ {
82
+ .fs-secure-notice
83
+ {
84
+ left: 36px;
85
+ }
86
+ }
87
+
88
+ @media screen and (max-width: 782px)
89
+ {
90
+ .fs-secure-notice
91
+ {
92
+ left: 0;
93
+ top: 46px;
94
+ text-align: center;
95
+ }
96
+ }
97
+
98
+ span.fs-submenu-item.fs-sub:before {
99
+ // Add small arrow.
100
+ content: '\21B3';
101
+ padding: 0 5px;
102
+ }
103
+
104
+ .rtl {
105
+ span.fs-submenu-item.fs-sub:before {
106
+ // Add small RTL arrow.
107
+ content: '\21B2';
108
+ }
109
+ }
lib/freemius/assets/scss/admin/connect.scss ADDED
@@ -0,0 +1,405 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../start";
2
+
3
+ $form_width: 480px;
4
+
5
+ #fs_connect
6
+ {
7
+ width: $form_width;
8
+ @include box-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));
9
+ margin: 20px 0;
10
+
11
+ @media screen and (max-width: ($form_width - 1)) {
12
+ @include box-shadow(none);
13
+ width: auto;
14
+ margin: 0 0 0 -10px;
15
+ }
16
+
17
+ .fs-content
18
+ {
19
+ background: #fff;
20
+ padding: 15px 20px;
21
+
22
+ p
23
+ {
24
+ margin: 0;
25
+ padding: 0;
26
+ font-size: 1.2em;
27
+ }
28
+ }
29
+
30
+ .fs-actions
31
+ {
32
+ padding: 10px 20px;
33
+ background: #C0C7CA;
34
+
35
+ .button
36
+ {
37
+ padding: 0 10px 1px;
38
+ line-height: 35px;
39
+ height: 37px;
40
+ font-size: 16px;
41
+ margin-bottom: 0;
42
+
43
+ .dashicons
44
+ {
45
+ font-size: 37px;
46
+ margin-left: -8px;
47
+ margin-right: 12px;
48
+ }
49
+
50
+ &.button-primary
51
+ {
52
+ padding-right: 15px;
53
+ padding-left: 15px;
54
+
55
+ &:after
56
+ {
57
+ content: ' \279C';
58
+ }
59
+ }
60
+
61
+ &.button-secondary
62
+ {
63
+ float: right;
64
+ }
65
+ }
66
+
67
+ // .fs-skip
68
+ // {
69
+ // line-height: 38px;
70
+ // vertical-align: middle;
71
+ // text-decoration: none;
72
+ // margin-left: 10px;
73
+ // }
74
+ }
75
+
76
+ &.fs-anonymous-disabled
77
+ {
78
+ .fs-actions
79
+ {
80
+ .button.button-primary
81
+ {
82
+ width: 100%;
83
+ }
84
+ }
85
+ }
86
+
87
+ .fs-permissions
88
+ {
89
+ padding: 10px 20px;
90
+ background: #FEFEFE;
91
+ // background: #F1F1F1;
92
+ @include transition(background 0.5s ease);
93
+
94
+ .fs-trigger
95
+ {
96
+ font-size: 0.9em;
97
+ text-decoration: none;
98
+ text-align: center;
99
+ display: block;
100
+ }
101
+
102
+ ul
103
+ {
104
+ height: 0;
105
+ overflow: hidden;
106
+ margin: 0;
107
+
108
+ li
109
+ {
110
+ margin-bottom: 12px;
111
+
112
+ &:last-child
113
+ {
114
+ margin-bottom: 0;
115
+ }
116
+
117
+ i.dashicons
118
+ {
119
+ float: left;
120
+ font-size: 40px;
121
+ width: 40px;
122
+ height: 40px;
123
+ }
124
+
125
+ div
126
+ {
127
+ margin-left: 55px;
128
+
129
+ span
130
+ {
131
+ font-weight: bold;
132
+ text-transform: uppercase;
133
+ color: #23282d;
134
+ }
135
+
136
+ p
137
+ {
138
+ margin: 2px 0 0 0;
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ &.fs-open
145
+ {
146
+ background: #fff;
147
+
148
+ ul
149
+ {
150
+ height: auto;
151
+ margin: 20px 20px 10px 20px;
152
+ }
153
+ }
154
+
155
+ @media screen and (max-width: ($form_width - 1)) {
156
+ background: #fff;
157
+
158
+ .fs-trigger
159
+ {
160
+ display: none;
161
+ }
162
+
163
+ ul
164
+ {
165
+ height: auto;
166
+ margin: 20px;
167
+ }
168
+ }
169
+ }
170
+
171
+ $icon_size: 80px;
172
+ $wp_logo_padding: $icon_size / 10;
173
+ $icons_top: 10px;
174
+
175
+ .fs-visual
176
+ {
177
+ padding: 12px;
178
+ line-height: 0;
179
+ background: #fafafa;
180
+ height: $icon_size;
181
+ position: relative;
182
+
183
+ .fs-site-icon
184
+ {
185
+ position: absolute;
186
+ left: 20px;
187
+ top: $icons_top;
188
+ }
189
+
190
+ .fs-connect-logo
191
+ {
192
+ position: absolute;
193
+ right: 20px;
194
+ top: $icons_top;
195
+ }
196
+
197
+ .fs-plugin-icon
198
+ {
199
+ position: absolute;
200
+ top: $icons_top;
201
+ left: 50%;
202
+ margin-left: - ($icon_size / 2);
203
+ }
204
+
205
+ .fs-plugin-icon,
206
+ .fs-site-icon,
207
+ img,
208
+ object
209
+ {
210
+ width: $icon_size;
211
+ height: $icon_size;
212
+ }
213
+
214
+ .dashicons-wordpress
215
+ {
216
+ font-size: $icon_size - ($wp_logo_padding * 2);
217
+ background: $wordpress_color;
218
+ color: #fff;
219
+ width: $icon_size - ($wp_logo_padding * 2);
220
+ height: $icon_size - ($wp_logo_padding * 2);
221
+ padding: $wp_logo_padding;
222
+ }
223
+
224
+ .dashicons-plus
225
+ {
226
+ position: absolute;
227
+ top: 50%;
228
+ font-size: 30px;
229
+ margin-top: -10px;
230
+ color: #bbb;
231
+
232
+ &.fs-first
233
+ {
234
+ left: 28%;
235
+ }
236
+ &.fs-second
237
+ {
238
+ left: 65%;
239
+ }
240
+ }
241
+
242
+ .fs-plugin-icon,
243
+ .fs-connect-logo,
244
+ .fs-site-icon
245
+ {
246
+ border: 1px solid #ccc;
247
+ padding: 1px;
248
+ background: #fff;
249
+ }
250
+ }
251
+
252
+ .fs-terms
253
+ {
254
+ text-align: center;
255
+ font-size: 0.85em;
256
+ padding: 5px;
257
+ background: rgba(0, 0, 0, 0.05);
258
+
259
+ &, a
260
+ {
261
+ color: #999;
262
+ }
263
+
264
+ a
265
+ {
266
+ text-decoration: none;
267
+ }
268
+ }
269
+ }
270
+
271
+ .rtl
272
+ {
273
+ #fs_connect
274
+ {
275
+ .fs-actions
276
+ {
277
+ padding: 10px 20px;
278
+ background: #C0C7CA;
279
+
280
+ .button
281
+ {
282
+ .dashicons
283
+ {
284
+ font-size: 37px;
285
+ margin-left: -8px;
286
+ margin-right: 12px;
287
+ }
288
+
289
+ &.button-primary
290
+ {
291
+ &:after
292
+ {
293
+ content: ' \000bb';
294
+ }
295
+ }
296
+
297
+ &.button-secondary
298
+ {
299
+ float: left;
300
+ }
301
+ }
302
+ }
303
+
304
+ .fs-permissions
305
+ {
306
+ ul
307
+ {
308
+ li
309
+ {
310
+ div
311
+ {
312
+ margin-right: 55px;
313
+ margin-left: 0;
314
+ }
315
+
316
+ i.dashicons
317
+ {
318
+ float: right;
319
+ }
320
+
321
+ }
322
+ }
323
+ }
324
+
325
+ .fs-visual
326
+ {
327
+ .fs-site-icon
328
+ {
329
+ right: 20px;
330
+ left: auto;
331
+ }
332
+
333
+ .fs-connect-logo
334
+ {
335
+ right: auto;
336
+ left: 20px;
337
+ }
338
+ }
339
+ }
340
+ }
341
+
342
+ .wp-pointer-content
343
+ {
344
+ #fs_connect
345
+ {
346
+ margin: 0;
347
+ @include box-shadow(none);
348
+ }
349
+ }
350
+
351
+ .fs-opt-in-pointer
352
+ {
353
+ .wp-pointer-content
354
+ {
355
+ padding: 0;
356
+ }
357
+
358
+ &.wp-pointer-top
359
+ {
360
+ .wp-pointer-arrow
361
+ {
362
+ border-bottom-color: #dfdfdf;
363
+ }
364
+ .wp-pointer-arrow-inner
365
+ {
366
+ border-bottom-color: #fafafa;
367
+ }
368
+ }
369
+
370
+ &.wp-pointer-bottom
371
+ {
372
+ .wp-pointer-arrow
373
+ {
374
+ border-top-color: #dfdfdf;
375
+ }
376
+ .wp-pointer-arrow-inner
377
+ {
378
+ border-top-color: #fafafa;
379
+ }
380
+ }
381
+
382
+ &.wp-pointer-left
383
+ {
384
+ .wp-pointer-arrow
385
+ {
386
+ border-right-color: #dfdfdf;
387
+ }
388
+ .wp-pointer-arrow-inner
389
+ {
390
+ border-right-color: #fafafa;
391
+ }
392
+ }
393
+
394
+ &.wp-pointer-right
395
+ {
396
+ .wp-pointer-arrow
397
+ {
398
+ border-left-color: #dfdfdf;
399
+ }
400
+ .wp-pointer-arrow-inner
401
+ {
402
+ border-left-color: #fafafa;
403
+ }
404
+ }
405
+ }
lib/freemius/assets/scss/admin/deactivation-feedback.scss ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .fs-modal {
2
+ position: fixed;
3
+ overflow: auto;
4
+ height: 100%;
5
+ width: 100%;
6
+ top: 0;
7
+ z-index: 100000;
8
+ display: none;
9
+ background: rgba(0, 0, 0, 0.6);
10
+
11
+ .fs-modal-dialog {
12
+ background: transparent;
13
+ position: absolute;
14
+ left: 50%;
15
+ margin-left: -298px;
16
+ padding-bottom: 30px;
17
+ top: -100%;
18
+ z-index: 100001;
19
+ width: 596px;
20
+
21
+ @media (max-width: 650px) {
22
+ margin-left: -50%;
23
+ box-sizing: border-box;
24
+ padding-left: 10px;
25
+ padding-right: 10px;
26
+ width: 100%;
27
+
28
+ .fs-modal-panel > h3 > strong {
29
+ font-size: 1.3em;
30
+ }
31
+
32
+ li.reason {
33
+ margin-bottom: 10px;
34
+
35
+ .reason-input {
36
+ margin-left: 29px;
37
+ }
38
+
39
+ label {
40
+ display: table;
41
+
42
+ > span {
43
+ display: table-cell;
44
+ font-size: 1.3em;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ &.active {
52
+ display: block;
53
+
54
+ &:before {
55
+ display: block;
56
+ }
57
+
58
+ .fs-modal-dialog {
59
+ top: 10%;
60
+ }
61
+ }
62
+
63
+ .fs-modal-body,
64
+ .fs-modal-footer {
65
+ border: 0;
66
+ background: #fefefe;
67
+ padding: 20px;
68
+ }
69
+
70
+ .fs-modal-body {
71
+ border-bottom: 0;
72
+
73
+ h2 {
74
+ font-size: 20px;
75
+ }
76
+
77
+ > div {
78
+ margin-top: 10px;
79
+
80
+ h2 {
81
+ font-weight: bold;
82
+ font-size: 20px;
83
+ margin-top: 0;
84
+ }
85
+ }
86
+ }
87
+
88
+ .fs-modal-footer {
89
+ border-top: #eeeeee solid 1px;
90
+ text-align: right;
91
+
92
+ > .button {
93
+ margin: 0 7px;
94
+
95
+ &:first-child {
96
+ margin: 0;
97
+ }
98
+ }
99
+ }
100
+
101
+ .fs-modal-panel:not(.active) {
102
+ display: none;
103
+ }
104
+
105
+ .reason-input {
106
+ margin: 3px 0 3px 22px;
107
+
108
+ input, textarea {
109
+ width: 100%;
110
+ }
111
+ }
112
+ }
113
+
114
+ body.has-fs-modal {
115
+ overflow: hidden;
116
+ }
117
+
118
+ #the-list .deactivate > .fs-slug {
119
+ display: none;
120
+ }
lib/freemius/config.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.4
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ define( 'WP_FS__SLUG', 'freemius' );
14
+ if ( ! defined( 'WP_FS__DEV_MODE' ) ) {
15
+ define( 'WP_FS__DEV_MODE', false );
16
+ }
17
+
18
+ /**
19
+ * API Connectivity Simulation
20
+ */
21
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY', false && WP_FS__DEV_MODE );
22
+ define( 'WP_FS__SIMULATE_NO_CURL', false && WP_FS__DEV_MODE );
23
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false && WP_FS__DEV_MODE );
24
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false && WP_FS__DEV_MODE );
25
+ if ( WP_FS__SIMULATE_NO_CURL ) {
26
+ define( 'FS_SDK__SIMULATE_NO_CURL', true );
27
+ }
28
+ if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE ) {
29
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', true );
30
+ }
31
+ if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL ) {
32
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', true );
33
+ }
34
+
35
+ /**
36
+ * If your dev environment supports custom public network IP setup
37
+ * like VVV, please update WP_FS__LOCALHOST_IP with your public IP
38
+ * and uncomment it during dev.
39
+ */
40
+ if ( ! defined( 'WP_FS__LOCALHOST_IP' ) ) {
41
+ // VVV default public network IP.
42
+ define( 'WP_FS__VVV_DEFAULT_PUBLIC_IP', '192.168.50.1' );
43
+
44
+ // define( 'WP_FS__LOCALHOST_IP', WP_FS__VVV_DEFAULT_PUBLIC_IP );
45
+ }
46
+
47
+ /**
48
+ * If true and running with secret key, the opt-in process
49
+ * will skip the email activation process which is invoked
50
+ * when the email of the context user already exist in Freemius
51
+ * database (as a security precaution, to prevent sharing user
52
+ * secret with unauthorized entity).
53
+ *
54
+ * IMPORTANT:
55
+ * AS A SECURITY PRECAUTION, WE VALIDATE THE TIMESTAMP OF THE OPT-IN REQUEST.
56
+ * THEREFORE, MAKE SURE THAT WHEN USING THIS PARAMETER,YOUR TESTING ENVIRONMENT'S
57
+ * CLOCK IS SYNCED.
58
+ */
59
+ define( 'WP_FS__SKIP_EMAIL_ACTIVATION', false );
60
+
61
+
62
+ /**
63
+ * Directories
64
+ */
65
+ define( 'WP_FS__DIR', dirname( __FILE__ ) );
66
+ define( 'WP_FS__DIR_INCLUDES', WP_FS__DIR . '/includes' );
67
+ define( 'WP_FS__DIR_TEMPLATES', WP_FS__DIR . '/templates' );
68
+ define( 'WP_FS__DIR_ASSETS', WP_FS__DIR . '/assets' );
69
+ define( 'WP_FS__DIR_CSS', WP_FS__DIR_ASSETS . '/css' );
70
+ define( 'WP_FS__DIR_JS', WP_FS__DIR_ASSETS . '/js' );
71
+ define( 'WP_FS__DIR_IMG', WP_FS__DIR_ASSETS . '/img' );
72
+ define( 'WP_FS__DIR_SDK', WP_FS__DIR_INCLUDES . '/sdk' );
73
+
74
+
75
+ /**
76
+ * Domain / URL / Address
77
+ */
78
+ define( 'WP_FS__TESTING_DOMAIN', 'fswp:8080' );
79
+ define( 'WP_FS__DOMAIN_PRODUCTION', 'wp.freemius.com' );
80
+ define( 'WP_FS__DOMAIN_LOCALHOST', 'wp.freemius' );
81
+ define( 'WP_FS__ADDRESS_LOCALHOST', 'http://' . WP_FS__DOMAIN_LOCALHOST . ':8080' );
82
+ define( 'WP_FS__ADDRESS_PRODUCTION', 'https://' . WP_FS__DOMAIN_PRODUCTION );
83
+
84
+ define( 'WP_FS__IS_PRODUCTION_MODE', ! defined( 'WP_FS__DEV_MODE' ) || ! WP_FS__DEV_MODE || ( WP_FS__TESTING_DOMAIN !== $_SERVER['HTTP_HOST'] ) );
85
+
86
+ define( 'WP_FS__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? WP_FS__ADDRESS_PRODUCTION : WP_FS__ADDRESS_LOCALHOST ) );
87
+
88
+ if ( defined( 'WP_FS__LOCALHOST_IP' ) ) {
89
+ define( 'WP_FS__IS_LOCALHOST', ( WP_FS__LOCALHOST_IP == $_SERVER['REMOTE_ADDR'] ) );
90
+ } else {
91
+ define( 'WP_FS__IS_LOCALHOST', ( substr( $_SERVER['REMOTE_ADDR'], 0, 4 ) == '127.' || $_SERVER['REMOTE_ADDR'] == '::1' ) );
92
+ }
93
+
94
+ define( 'WP_FS__IS_LOCALHOST_FOR_SERVER', ( false !== strpos( $_SERVER['HTTP_HOST'], 'localhost' ) ) );
95
+
96
+ // Set API address for local testing.
97
+ if ( ! WP_FS__IS_PRODUCTION_MODE ) {
98
+ define( 'FS_API__ADDRESS', 'http://api.freemius:8080' );
99
+ define( 'FS_API__SANDBOX_ADDRESS', 'http://sandbox-api.freemius:8080' );
100
+ }
101
+
102
+ define( 'WP_FS___OPTION_PREFIX', 'fs' . ( WP_FS__IS_PRODUCTION_MODE ? '' : '_dbg' ) . '_' );
103
+
104
+ if ( ! defined( 'WP_FS__ACCOUNTS_OPTION_NAME' ) ) {
105
+ define( 'WP_FS__ACCOUNTS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'accounts' );
106
+ }
107
+ if ( ! defined( 'WP_FS__API_CACHE_OPTION_NAME' ) ) {
108
+ define( 'WP_FS__API_CACHE_OPTION_NAME', WP_FS___OPTION_PREFIX . 'api_cache' );
109
+ }
110
+ define( 'WP_FS__OPTIONS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'options' );
111
+
112
+ define( 'WP_FS__IS_HTTPS', (
113
+ // Checks if CloudFlare's HTTPS (Flexible SSL support)
114
+ isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) ||
115
+ // Check if HTTPS request.
116
+ ( isset( $_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) ||
117
+ ( isset( $_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] )
118
+ );
119
+
120
+ define( 'WP_FS__IS_POST_REQUEST', ( strtoupper( $_SERVER['REQUEST_METHOD'] ) == 'POST' ) );
121
+
122
+ /**
123
+ * Billing Frequencies
124
+ */
125
+ define( 'WP_FS__PERIOD_ANNUALLY', 'annual' );
126
+ define( 'WP_FS__PERIOD_MONTHLY', 'monthly' );
127
+ define( 'WP_FS__PERIOD_LIFETIME', 'lifetime' );
128
+
129
+ /**
130
+ * Plans
131
+ */
132
+ define( 'WP_FS__PLAN_DEFAULT_PAID', false );
133
+ define( 'WP_FS__PLAN_FREE', 'free' );
134
+ define( 'WP_FS__PLAN_TRIAL', 'trial' );
135
+
136
+ /**
137
+ * Times in seconds
138
+ */
139
+ // define( 'WP_FS__TIME_5_MIN_IN_SEC', 300 );
140
+ define( 'WP_FS__TIME_10_MIN_IN_SEC', 600 );
141
+ // define( 'WP_FS__TIME_15_MIN_IN_SEC', 900 );
142
+ define( 'WP_FS__TIME_24_HOURS_IN_SEC', 86400 );
143
+
144
+ /**
145
+ * Debugging
146
+ */
147
+ define( 'WP_FS__DEBUG_SDK', ! empty( $_GET['fs_dbg'] ) );
148
+ define( 'WP_FS__ECHO_DEBUG_SDK', ! empty( $_GET['fs_dbg_echo'] ) );
149
+ define( 'WP_FS__LOG_DATETIME_FORMAT', 'Y-n-d H:i:s' );
150
+
151
+ if ( WP_FS__ECHO_DEBUG_SDK ) {
152
+ error_reporting( E_ALL );
153
+ ini_set( 'error_reporting', E_ALL );
154
+ ini_set( 'display_errors', true );
155
+ ini_set( 'html_errors', true );
156
+ }
157
+
158
+
159
+ define( 'WP_FS__SCRIPT_START_TIME', time() );
160
+ define( 'WP_FS__DEFAULT_PRIORITY', 10 );
161
+ define( 'WP_FS__LOWEST_PRIORITY', 999999999 );
lib/freemius/includes/class-freemius-abstract.php ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.7
7
+ */
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+
13
+ /**
14
+ * - Each instance of Freemius class represents a single plugin
15
+ * install by a single user (the installer of the plugin).
16
+ *
17
+ * - Each website can only have one install of the same plugin.
18
+ *
19
+ * - Install entity is only created after a user connects his account with Freemius.
20
+ *
21
+ * Class Freemius_Abstract
22
+ */
23
+ abstract class Freemius_Abstract {
24
+
25
+ #region Identity ------------------------------------------------------------------
26
+
27
+ /**
28
+ * Check if user registered with Freemius by connecting his account.
29
+ *
30
+ * @since 1.0.1
31
+ * @return bool
32
+ */
33
+ abstract function is_registered();
34
+
35
+ /**
36
+ * Check if the user skipped connecting the account with Freemius.
37
+ *
38
+ * @since 1.0.7
39
+ *
40
+ * @return bool
41
+ */
42
+ abstract function is_anonymous();
43
+
44
+ /**
45
+ * Check if the user currently in activation mode.
46
+ *
47
+ * @since 1.0.7
48
+ *
49
+ * @return bool
50
+ */
51
+ abstract function is_activation_mode();
52
+
53
+ #endregion Identity ------------------------------------------------------------------
54
+
55
+ #region Permissions ------------------------------------------------------------------
56
+
57
+ /**
58
+ * Check if plugin must be WordPress.org compliant.
59
+ *
60
+ * @since 1.0.7
61
+ *
62
+ * @return bool
63
+ */
64
+ abstract function is_org_repo_compliant();
65
+
66
+ /**
67
+ * Check if plugin is allowed to install executable files.
68
+ *
69
+ * @author Vova Feldman (@svovaf)
70
+ * @since 1.0.5
71
+ *
72
+ * @return bool
73
+ */
74
+ function is_allowed_to_install() {
75
+ return ( $this->is_premium() || ! $this->is_org_repo_compliant() );
76
+ }
77
+
78
+ #endregion Permissions ------------------------------------------------------------------
79
+
80
+ /**
81
+ * Check if user in trial or in free plan (not paying).
82
+ *
83
+ * @author Vova Feldman (@svovaf)
84
+ * @since 1.0.4
85
+ *
86
+ * @return bool
87
+ */
88
+ function is_not_paying() {
89
+ return ( $this->is_trial() || $this->is_free_plan() );
90
+ }
91
+
92
+ /**
93
+ * Check if the user has an activated and valid paid license on current plugin's install.
94
+ *
95
+ * @since 1.0.9
96
+ *
97
+ * @return bool
98
+ */
99
+ abstract function is_paying();
100
+
101
+ /**
102
+ * Check if the user is paying or in trial.
103
+ *
104
+ * @since 1.0.9
105
+ *
106
+ * @return bool
107
+ */
108
+ function is_paying_or_trial() {
109
+ return ( $this->is_paying() || $this->is_trial() );
110
+ }
111
+
112
+ #region Premium Only ------------------------------------------------------------------
113
+
114
+ /**
115
+ * All logic wrapped in methods with "__premium_only()" suffix will be only
116
+ * included in the premium code.
117
+ *
118
+ * Example:
119
+ * if ( freemius()->is__premium_only() ) {
120
+ * ...
121
+ * }
122
+ */
123
+
124
+ /**
125
+ * Returns true when running premium plugin code.
126
+ *
127
+ * @since 1.0.9
128
+ *
129
+ * @return bool
130
+ */
131
+ function is__premium_only() {
132
+ return $this->is_premium();
133
+ }
134
+
135
+ /**
136
+ * Check if the user has an activated and valid paid license on current plugin's install.
137
+ *
138
+ * @since 1.0.9
139
+ *
140
+ * @return bool
141
+ *
142
+ */
143
+ function is_paying__premium_only() {
144
+ return ( $this->is__premium_only() && $this->is_paying() );
145
+ }
146
+
147
+ /**
148
+ * All code wrapped in this statement will be only included in the premium code.
149
+ *
150
+ * @since 1.0.9
151
+ *
152
+ * @param string $plan Plan name
153
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
154
+ *
155
+ * @return bool
156
+ */
157
+ function is_plan__premium_only( $plan, $exact = false ) {
158
+ return ( $this->is_premium() && $this->is_plan( $plan, $exact ) );
159
+ }
160
+
161
+ /**
162
+ * Check if plan matches active license' plan or active trial license' plan.
163
+ *
164
+ * All code wrapped in this statement will be only included in the premium code.
165
+ *
166
+ * @since 1.0.9
167
+ *
168
+ * @param string $plan Plan name
169
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
170
+ *
171
+ * @return bool
172
+ */
173
+ function is_plan_or_trial__premium_only( $plan, $exact = false ) {
174
+ return ( $this->is_premium() && $this->is_plan_or_trial( $plan, $exact ) );
175
+ }
176
+
177
+ /**
178
+ * Check if the user is paying or in trial.
179
+ *
180
+ * All code wrapped in this statement will be only included in the premium code.
181
+ *
182
+ * @since 1.0.9
183
+ *
184
+ * @return bool
185
+ */
186
+ function is_paying_or_trial__premium_only() {
187
+ return $this->is_premium() && $this->is_paying_or_trial();
188
+ }
189
+
190
+ /**
191
+ * Check if the user has an activated and valid paid license on current plugin's install.
192
+ *
193
+ * @since 1.0.4
194
+ *
195
+ * @return bool
196
+ *
197
+ * @deprecated Method name is confusing since it's not clear from the name the code will be removed.
198
+ * @using Alias to is_paying__premium_only()
199
+ */
200
+ function is_paying__fs__() {
201
+ return $this->is_paying__premium_only();
202
+ }
203
+
204
+ #endregion Premium Only ------------------------------------------------------------------
205
+
206
+ #region Trial ------------------------------------------------------------------
207
+
208
+ /**
209
+ * Check if the user in a trial.
210
+ *
211
+ * @since 1.0.3
212
+ *
213
+ * @return bool
214
+ */
215
+ abstract function is_trial();
216
+
217
+ /**
218
+ * Check if trial already utilized.
219
+ *
220
+ * @since 1.0.9
221
+ *
222
+ * @return bool
223
+ */
224
+ abstract function is_trial_utilized();
225
+
226
+ #endregion Trial ------------------------------------------------------------------
227
+
228
+ #region Plans ------------------------------------------------------------------
229
+
230
+ /**
231
+ * Check if plugin using the free plan.
232
+ *
233
+ * @since 1.0.4
234
+ *
235
+ * @return bool
236
+ */
237
+ abstract function is_free_plan();
238
+
239
+ /**
240
+ * @since 1.0.2
241
+ *
242
+ * @param string $plan Plan name
243
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
244
+ *
245
+ * @return bool
246
+ */
247
+ abstract function is_plan( $plan, $exact = false );
248
+
249
+ /**
250
+ * Check if plan based on trial. If not in trial mode, should return false.
251
+ *
252
+ * @since 1.0.9
253
+ *
254
+ * @param string $plan Plan name
255
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
256
+ *
257
+ * @return bool
258
+ */
259
+ abstract function is_trial_plan( $plan, $exact = false );
260
+
261
+ /**
262
+ * Check if plan matches active license' plan or active trial license' plan.
263
+ *
264
+ * @since 1.0.9
265
+ *
266
+ * @param string $plan Plan name
267
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
268
+ *
269
+ * @return bool
270
+ */
271
+ function is_plan_or_trial( $plan, $exact = false ) {
272
+ return $this->is_plan( $plan, $exact ) ||
273
+ $this->is_trial_plan( $plan, $exact );
274
+ }
275
+
276
+ /**
277
+ * Check if plugin has any paid plans.
278
+ *
279
+ * @author Vova Feldman (@svovaf)
280
+ * @since 1.0.7
281
+ *
282
+ * @return bool
283
+ */
284
+ abstract function has_paid_plan();
285
+
286
+ /**
287
+ * Check if plugin has any free plan, or is it premium only.
288
+ *
289
+ * Note: If no plans configured, assume plugin is free.
290
+ *
291
+ * @author Vova Feldman (@svovaf)
292
+ * @since 1.0.7
293
+ *
294
+ * @return bool
295
+ */
296
+ abstract function has_free_plan();
297
+
298
+ #endregion Plans ------------------------------------------------------------------
299
+
300
+ /**
301
+ * Check if running payments in sandbox mode.
302
+ *
303
+ * @since 1.0.4
304
+ *
305
+ * @return bool
306
+ */
307
+ abstract function is_payments_sandbox();
308
+
309
+ /**
310
+ * Check if running test vs. live plugin.
311
+ *
312
+ * @since 1.0.5
313
+ *
314
+ * @return bool
315
+ */
316
+ abstract function is_live();
317
+
318
+ /**
319
+ * Check if running premium plugin code.
320
+ *
321
+ * @since 1.0.5
322
+ *
323
+ * @return bool
324
+ */
325
+ abstract function is_premium();
326
+
327
+ /**
328
+ * Get upgrade URL.
329
+ *
330
+ * @author Vova Feldman (@svovaf)
331
+ * @since 1.0.2
332
+ *
333
+ * @param string $period Billing cycle
334
+ *
335
+ * @return string
336
+ */
337
+ abstract function get_upgrade_url( $period = WP_FS__PERIOD_ANNUALLY );
338
+
339
+ #region Marketing ------------------------------------------------------------------
340
+
341
+ /**
342
+ * Check if current user purchased any other plugins before.
343
+ *
344
+ * @author Vova Feldman (@svovaf)
345
+ * @since 1.0.9
346
+ *
347
+ * @return bool
348
+ */
349
+ abstract function has_purchased_before();
350
+
351
+ /**
352
+ * Check if current user classified as an agency.
353
+ *
354
+ * @author Vova Feldman (@svovaf)
355
+ * @since 1.0.9
356
+ *
357
+ * @return bool
358
+ */
359
+ abstract function is_agency();
360
+
361
+ /**
362
+ * Check if current user classified as a developer.
363
+ *
364
+ * @author Vova Feldman (@svovaf)
365
+ * @since 1.0.9
366
+ *
367
+ * @return bool
368
+ */
369
+ abstract function is_developer();
370
+
371
+ /**
372
+ * Check if current user classified as a business.
373
+ *
374
+ * @author Vova Feldman (@svovaf)
375
+ * @since 1.0.9
376
+ *
377
+ * @return bool
378
+ */
379
+ abstract function is_business();
380
+
381
+ #endregion ------------------------------------------------------------------
382
+ }
lib/freemius/includes/class-freemius.php ADDED
@@ -0,0 +1,7698 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ // "final class"
13
+ class Freemius extends Freemius_Abstract {
14
+ /**
15
+ * SDK Version
16
+ *
17
+ * @var string
18
+ */
19
+ public $version = '1.1.5';
20
+
21
+ #region Plugin Info
22
+
23
+ /**
24
+ * @since 1.0.1
25
+ *
26
+ * @var string
27
+ */
28
+ private $_slug;
29
+
30
+ /**
31
+ * @since 1.0.0
32
+ *
33
+ * @var string
34
+ */
35
+ private $_plugin_basename;
36
+ /**
37
+ * @since 1.0.0
38
+ *
39
+ * @var string
40
+ */
41
+ private $_free_plugin_basename;
42
+ /**
43
+ * @since 1.0.0
44
+ *
45
+ * @var string
46
+ */
47
+ private $_plugin_dir_path;
48
+ /**
49
+ * @since 1.0.0
50
+ *
51
+ * @var string
52
+ */
53
+ private $_plugin_dir_name;
54
+ /**
55
+ * @since 1.0.0
56
+ *
57
+ * @var string
58
+ */
59
+ private $_plugin_main_file_path;
60
+ /**
61
+ * @var string[]
62
+ */
63
+ private $_plugin_data;
64
+ /**
65
+ * @since 1.0.9
66
+ *
67
+ * @var string
68
+ */
69
+ private $_plugin_name;
70
+
71
+ #endregion Plugin Info
72
+
73
+ /**
74
+ * @since 1.0.9
75
+ *
76
+ * @var bool If false, don't turn Freemius on.
77
+ */
78
+ private $_is_on;
79
+
80
+ /**
81
+ * @since 1.1.3
82
+ *
83
+ * @var bool If false, don't turn Freemius on.
84
+ */
85
+ private $_is_anonymous;
86
+
87
+ /**
88
+ * @since 1.0.9
89
+ * @var bool If false, issues with connectivity to Freemius API.
90
+ */
91
+ private $_has_api_connection;
92
+
93
+ /**
94
+ * @since 1.0.9
95
+ * @var bool Hints the SDK if plugin can support anonymous mode (if skip connect is visible).
96
+ */
97
+ private $_enable_anonymous;
98
+
99
+ /**
100
+ * @since 1.0.8
101
+ * @var bool Hints the SDK if the plugin has any paid plans.
102
+ */
103
+ private $_has_paid_plans;
104
+
105
+ /**
106
+ * @since 1.0.7
107
+ * @var bool Hints the SDK if the plugin is WordPress.org compliant.
108
+ */
109
+ private $_is_org_compliant;
110
+
111
+ /**
112
+ * @since 1.0.7
113
+ * @var bool Hints the SDK if the plugin is has add-ons.
114
+ */
115
+ private $_has_addons;
116
+
117
+ /**
118
+ * @var FS_Key_Value_Storage
119
+ */
120
+ private $_storage;
121
+
122
+ /**
123
+ * @since 1.0.0
124
+ *
125
+ * @var FS_Logger
126
+ */
127
+ private $_logger;
128
+ /**
129
+ * @since 1.0.4
130
+ *
131
+ * @var FS_Plugin
132
+ */
133
+ private $_plugin = false;
134
+ /**
135
+ * @since 1.0.4
136
+ *
137
+ * @var FS_Plugin
138
+ */
139
+ private $_parent_plugin = false;
140
+ /**
141
+ * @since 1.1.1
142
+ *
143
+ * @var Freemius
144
+ */
145
+ private $_parent = false;
146
+ /**
147
+ * @since 1.0.1
148
+ *
149
+ * @var FS_User
150
+ */
151
+ private $_user = false;
152
+ /**
153
+ * @since 1.0.1
154
+ *
155
+ * @var FS_Site
156
+ */
157
+ private $_site = false;
158
+ /**
159
+ * @since 1.0.1
160
+ *
161
+ * @var FS_Plugin_License
162
+ */
163
+ private $_license;
164
+ /**
165
+ * @since 1.0.2
166
+ *
167
+ * @var FS_Plugin_Plan[]
168
+ */
169
+ private $_plans = false;
170
+ /**
171
+ * @var FS_Plugin_License[]
172
+ * @since 1.0.5
173
+ */
174
+ private $_licenses = false;
175
+
176
+ /**
177
+ * @since 1.0.1
178
+ *
179
+ * @var FS_Admin_Menu_Manager
180
+ */
181
+ private $_menu;
182
+
183
+ /**
184
+ * @var FS_Admin_Notice_Manager
185
+ */
186
+ private $_admin_notices;
187
+
188
+ /**
189
+ * @var FS_Logger
190
+ * @since 1.0.0
191
+ */
192
+ private static $_static_logger;
193
+
194
+ /**
195
+ * @var FS_Option_Manager
196
+ * @since 1.0.2
197
+ */
198
+ private static $_accounts;
199
+
200
+ /**
201
+ * @var Freemius[]
202
+ */
203
+ private static $_instances = array();
204
+
205
+
206
+ /* Ctor
207
+ ------------------------------------------------------------------------------------------------------------------*/
208
+
209
+ private function __construct( $slug ) {
210
+ $this->_slug = $slug;
211
+
212
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
213
+
214
+ $this->_storage = FS_Key_Value_Storage::instance( 'plugin_data', $this->_slug );
215
+
216
+ $this->_plugin_main_file_path = $this->_find_caller_plugin_file();
217
+ $this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
218
+ $this->_plugin_basename = plugin_basename( $this->_plugin_main_file_path );
219
+ $this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
220
+
221
+ $base_name_split = explode( '/', $this->_plugin_basename );
222
+ $this->_plugin_dir_name = $base_name_split[0];
223
+
224
+ if ( $this->_logger->is_on() ) {
225
+ $this->_logger->info( 'plugin_main_file_path = ' . $this->_plugin_main_file_path );
226
+ $this->_logger->info( 'plugin_dir_path = ' . $this->_plugin_dir_path );
227
+ $this->_logger->info( 'plugin_basename = ' . $this->_plugin_basename );
228
+ $this->_logger->info( 'free_plugin_basename = ' . $this->_free_plugin_basename );
229
+ $this->_logger->info( 'plugin_dir_name = ' . $this->_plugin_dir_name );
230
+ }
231
+
232
+ // Remember link between file to slug.
233
+ $this->store_file_slug_map();
234
+
235
+ // Store plugin's initial install timestamp.
236
+ if ( ! isset( $this->_storage->install_timestamp ) ) {
237
+ $this->_storage->install_timestamp = WP_FS__SCRIPT_START_TIME;
238
+ }
239
+
240
+ $this->_plugin = FS_Plugin_Manager::instance( $this->_slug )->get();
241
+
242
+ $this->_admin_notices = FS_Admin_Notice_Manager::instance(
243
+ $slug,
244
+ is_object( $this->_plugin ) ? $this->_plugin->title : ''
245
+ );
246
+
247
+ if ( 'true' === fs_request_get( 'fs_clear_api_cache' ) ) {
248
+ FS_Api::clear_cache();
249
+ }
250
+
251
+ $this->_register_hooks();
252
+
253
+ $this->_load_account();
254
+
255
+ $this->_version_updates_handler();
256
+ }
257
+
258
+ /**
259
+ * @author Vova Feldman (@svovaf)
260
+ * @since 1.0.9
261
+ */
262
+ private function _version_updates_handler() {
263
+ if ( ! isset( $this->_storage->sdk_version ) || $this->_storage->sdk_version != $this->version ) {
264
+ // Freemius version upgrade mode.
265
+ $this->_storage->sdk_last_version = $this->_storage->sdk_version;
266
+ $this->_storage->sdk_version = $this->version;
267
+
268
+ if ( empty( $this->_storage->sdk_last_version ) ||
269
+ version_compare( $this->_storage->sdk_last_version, $this->version, '<' )
270
+ ) {
271
+ $this->_storage->sdk_upgrade_mode = true;
272
+ $this->_storage->sdk_downgrade_mode = false;
273
+ } else {
274
+ $this->_storage->sdk_downgrade_mode = true;
275
+ $this->_storage->sdk_upgrade_mode = false;
276
+
277
+ }
278
+
279
+ $this->do_action( 'sdk_version_update', $this->_storage->sdk_last_version, $this->version );
280
+ }
281
+
282
+ $plugin_version = $this->get_plugin_version();
283
+ if ( ! isset( $this->_storage->plugin_version ) || $this->_storage->plugin_version != $plugin_version ) {
284
+ // Plugin version upgrade mode.
285
+ $this->_storage->plugin_last_version = $this->_storage->plugin_version;
286
+ $this->_storage->plugin_version = $plugin_version;
287
+
288
+ if ( empty( $this->_storage->plugin_last_version ) ||
289
+ version_compare( $this->_storage->plugin_last_version, $plugin_version, '<' )
290
+ ) {
291
+ $this->_storage->plugin_upgrade_mode = true;
292
+ $this->_storage->plugin_downgrade_mode = false;
293
+ } else {
294
+ $this->_storage->plugin_downgrade_mode = true;
295
+ $this->_storage->plugin_upgrade_mode = false;
296
+ }
297
+
298
+ if ( ! empty( $this->_storage->plugin_last_version ) ) {
299
+ // Different version of the plugin was installed before, therefore it's an update.
300
+ $this->_storage->is_plugin_new_install = false;
301
+ }
302
+
303
+ $this->do_action( 'plugin_version_update', $this->_storage->plugin_last_version, $plugin_version );
304
+ }
305
+ }
306
+
307
+ /**
308
+ * @author Vova Feldman (@svovaf)
309
+ * @since 1.1.5
310
+ *
311
+ * @param string $sdk_prev_version
312
+ * @param string $sdk_version
313
+ */
314
+ function _data_migration($sdk_prev_version, $sdk_version) {
315
+ if ( version_compare($sdk_prev_version, '1.1.5', '<' ) &&
316
+ version_compare($sdk_version, '1.1.5', '>=')
317
+ ) {
318
+ // On version 1.1.5 merged connectivity and is_on data.
319
+ if ( isset( $this->_storage->connectivity_test ) ) {
320
+ if ( ! isset( $this->_storage->is_on ) ) {
321
+ unset( $this->_storage->connectivity_test );
322
+ } else {
323
+ $connectivity_data = $this->_storage->connectivity_test;
324
+ $connectivity_data['is_active'] = $this->_storage->is_on['is_active'];
325
+ $connectivity_data['timestamp'] = $this->_storage->is_on['timestamp'];
326
+
327
+ // Override.
328
+ $this->_storage->connectivity_test = $connectivity_data;
329
+
330
+ // Remove previous structure.
331
+ unset( $this->_storage->is_on );
332
+ }
333
+
334
+ }
335
+ }
336
+ }
337
+
338
+ /**
339
+ * @author Vova Feldman (@svovaf)
340
+ * @since 1.0.9
341
+ */
342
+ private function _register_hooks() {
343
+ if ( is_admin() ) {
344
+ // Hook to plugin activation
345
+ register_activation_hook( $this->_plugin_main_file_path, array(
346
+ &$this,
347
+ '_activate_plugin_event_hook'
348
+ ) );
349
+
350
+ // Hook to plugin uninstall.
351
+ register_uninstall_hook( $this->_plugin_main_file_path, array( 'Freemius', '_uninstall_plugin_hook' ) );
352
+
353
+ if ( ! $this->is_ajax() ) {
354
+ if ( ! $this->is_addon() ) {
355
+ add_action( 'init', array( &$this, '_add_default_submenu_items' ), WP_FS__LOWEST_PRIORITY );
356
+ add_action( 'admin_menu', array( &$this, '_prepare_admin_menu' ), WP_FS__LOWEST_PRIORITY );
357
+ }
358
+ }
359
+ }
360
+
361
+ register_deactivation_hook( $this->_plugin_main_file_path, array( &$this, '_deactivate_plugin_hook' ) );
362
+
363
+ add_action( 'init', array( &$this, '_redirect_on_clicked_menu_link' ), WP_FS__LOWEST_PRIORITY );
364
+
365
+ $this->add_action( 'after_plans_sync', array( &$this, '_check_for_trial_plans' ) );
366
+
367
+ $this->add_action('sdk_version_update', array(&$this, '_data_migration'), WP_FS__DEFAULT_PRIORITY, 2);
368
+ }
369
+
370
+ /**
371
+ * @author Vova Feldman (@svovaf)
372
+ * @since 1.0.9
373
+ */
374
+ private function _register_account_hooks() {
375
+ if ( is_admin() ) {
376
+ if ( ! $this->is_ajax() ) {
377
+ if ( $this->has_trial_plan() ) {
378
+ $last_time_trial_promotion_shown = $this->_storage->get( 'trial_promotion_shown', false );
379
+ if ( ! $this->_site->is_trial_utilized() &&
380
+ (
381
+ // Show promotion if never shown it yet and 24 hours after initial activation.
382
+ ( false === $last_time_trial_promotion_shown && $this->_storage->activation_timestamp < ( time() - WP_FS__TIME_24_HOURS_IN_SEC ) ) ||
383
+ // Show promotion in every 30 days.
384
+ ( is_numeric( $last_time_trial_promotion_shown ) && 30 * WP_FS__TIME_24_HOURS_IN_SEC < time() - $last_time_trial_promotion_shown ) )
385
+ ) {
386
+ $this->add_action( 'after_init_plugin_registered', array( &$this, '_add_trial_notice' ) );
387
+ }
388
+ }
389
+ }
390
+
391
+ // If user is paying or in trial and have the free version installed,
392
+ // assume that the deactivation is for the upgrade process.
393
+ if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
394
+ add_action( 'wp_ajax_submit-uninstall-reason', array( &$this, '_submit_uninstall_reason_action' ) );
395
+
396
+ global $pagenow;
397
+ if ( 'plugins.php' === $pagenow ) {
398
+ add_action( 'admin_footer', array( &$this, '_add_deactivation_feedback_dialog_box' ) );
399
+ }
400
+ }
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Displays a confirmation and feedback dialog box when the user clicks on the "Deactivate" link on the plugins
406
+ * page.
407
+ *
408
+ * @author Vova Feldman (@svovaf)
409
+ * @author Leo Fajardo (@leorw)
410
+ * @since 1.1.2
411
+ */
412
+ function _add_deactivation_feedback_dialog_box() {
413
+ fs_enqueue_local_style( 'fs_deactivation_feedback', '/admin/deactivation-feedback.css' );
414
+
415
+ /* Check the type of user:
416
+ * 1. Long-term (long-term)
417
+ * 2. Non-registered and non-anonymous short-term (non-registered-and-non-anonymous-short-term).
418
+ * 3. Short-term (short-term)
419
+ */
420
+ $is_long_term_user = true;
421
+
422
+ // Check if the site is at least 2 days old.
423
+ $time_installed = $this->_storage->install_timestamp;
424
+
425
+ // Difference in seconds.
426
+ $date_diff = time() - $time_installed;
427
+
428
+ // Convert seconds to days.
429
+ $date_diff_days = floor( $date_diff / ( 60 * 60 * 24 ) );
430
+
431
+ if ( $date_diff_days < 2 ) {
432
+ $is_long_term_user = false;
433
+ }
434
+
435
+ $is_long_term_user = $this->apply_filters( 'is_long_term_user', $is_long_term_user );
436
+
437
+ if ( $is_long_term_user ) {
438
+ $user_type = 'long-term';
439
+ } else {
440
+ if ( ! $this->is_registered() && ! $this->is_anonymous() ) {
441
+ $user_type = 'non-registered-and-non-anonymous-short-term';
442
+ } else {
443
+ $user_type = 'short-term';
444
+ }
445
+ }
446
+
447
+ $uninstall_reasons = $this->_get_uninstall_reasons( $user_type );
448
+
449
+ // Load the HTML template for the deactivation feedback dialog box.
450
+ $vars = array(
451
+ 'reasons' => $uninstall_reasons,
452
+ 'slug' => $this->_slug
453
+ );
454
+
455
+ fs_require_once_template( 'deactivation-feedback-modal.php', $vars );
456
+ }
457
+
458
+ /**
459
+ * @author Leo Fajardo (leorw)
460
+ * @since 1.1.2
461
+ *
462
+ * @param string $user_type
463
+ *
464
+ * @return array The uninstall reasons for the specified user type.
465
+ */
466
+ function _get_uninstall_reasons( $user_type = 'long-term' ) {
467
+ $reason_found_better_plugin = array(
468
+ 'id' => 2,
469
+ 'text' => __fs( 'reason-found-a-better-plugin' ),
470
+ 'input_type' => 'textfield',
471
+ 'input_placeholder' => __fs( 'placeholder-plugin-name' )
472
+ );
473
+
474
+ $reason_other = array(
475
+ 'id' => 7,
476
+ 'text' => __fs( 'reason-other' ),
477
+ 'input_type' => 'textfield',
478
+ 'input_placeholder' => ''
479
+ );
480
+
481
+ $long_term_user_reasons = array(
482
+ array(
483
+ 'id' => 1,
484
+ 'text' => __fs( 'reason-no-longer-needed' ),
485
+ 'input_type' => '',
486
+ 'input_placeholder' => ''
487
+ ),
488
+ $reason_found_better_plugin,
489
+ array(
490
+ 'id' => 3,
491
+ 'text' => __fs( 'reason-needed-for-a-short-period' ),
492
+ 'input_type' => '',
493
+ 'input_placeholder' => ''
494
+ ),
495
+ array(
496
+ 'id' => 4,
497
+ 'text' => __fs( 'reason-broke-my-site' ),
498
+ 'input_type' => '',
499
+ 'input_placeholder' => ''
500
+ ),
501
+ array(
502
+ 'id' => 5,
503
+ 'text' => __fs( 'reason-suddenly-stopped-working' ),
504
+ 'input_type' => '',
505
+ 'input_placeholder' => ''
506
+ )
507
+ );
508
+
509
+ if ( $this->is_paying() ) {
510
+ $long_term_user_reasons[] = array(
511
+ 'id' => 6,
512
+ 'text' => __fs( 'reason-cant-pay-anymore' ),
513
+ 'input_type' => 'textfield',
514
+ 'input_placeholder' => __fs( 'placeholder-comfortable-price' )
515
+ );
516
+ }
517
+
518
+ $long_term_user_reasons[] = $reason_other;
519
+
520
+ $uninstall_reasons = array(
521
+ 'long-term' => $long_term_user_reasons,
522
+ 'non-registered-and-non-anonymous-short-term' => array(
523
+ array(
524
+ 'id' => 8,
525
+ 'text' => __fs( 'reason-didnt-work' ),
526
+ 'input_type' => '',
527
+ 'input_placeholder' => ''
528
+ ),
529
+ array(
530
+ 'id' => 9,
531
+ 'text' => __fs( 'reason-dont-like-to-share-my-information' ),
532
+ 'input_type' => '',
533
+ 'input_placeholder' => ''
534
+ ),
535
+ $reason_found_better_plugin,
536
+ $reason_other
537
+ ),
538
+ 'short-term' => array(
539
+ array(
540
+ 'id' => 10,
541
+ 'text' => __fs( 'reason-couldnt-make-it-work' ),
542
+ 'input_type' => '',
543
+ 'input_placeholder' => ''
544
+ ),
545
+ $reason_found_better_plugin,
546
+ array(
547
+ 'id' => 11,
548
+ 'text' => __fs( 'reason-great-but-need-specific-feature' ),
549
+ 'input_type' => 'textarea',
550
+ 'input_placeholder' => __fs( 'placeholder-feature' )
551
+ ),
552
+ array(
553
+ 'id' => 12,
554
+ 'text' => __fs( 'reason-not-working' ),
555
+ 'input_type' => 'textarea',
556
+ 'input_placeholder' => __fs( 'placeholder-share-what-didnt-work' )
557
+ ),
558
+ array(
559
+ 'id' => 13,
560
+ 'text' => __fs( 'reason-not-what-i-was-looking-for' ),
561
+ 'input_type' => 'textarea',
562
+ 'input_placeholder' => __fs( 'placeholder-what-youve-been-looking-for' )
563
+ ),
564
+ array(
565
+ 'id' => 14,
566
+ 'text' => __fs( 'reason-didnt-work-as-expected' ),
567
+ 'input_type' => 'textarea',
568
+ 'input_placeholder' => __fs( 'placeholder-what-did-you-expect' )
569
+ ),
570
+ $reason_other
571
+ )
572
+ );
573
+
574
+ $uninstall_reasons = $this->apply_filters( 'uninstall_reasons', $uninstall_reasons );
575
+
576
+ return $uninstall_reasons[ $user_type ];
577
+ }
578
+
579
+ /**
580
+ * Called after the user has submitted his reason for deactivating the plugin.
581
+ *
582
+ * @author Leo Fajardo (@leorw)
583
+ * @since 1.1.2
584
+ */
585
+ function _submit_uninstall_reason_action() {
586
+ if ( ! isset( $_POST['reason_id'] ) ) {
587
+ exit;
588
+ }
589
+
590
+ $reason_info = isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '';
591
+
592
+ $reason = (object) array(
593
+ 'id' => $_POST['reason_id'],
594
+ 'info' => substr( $reason_info, 0, 128 )
595
+ );
596
+
597
+ $this->_storage->store( 'uninstall_reason', $reason );
598
+
599
+ // Print '1' for successful operation.
600
+ echo 1;
601
+ exit;
602
+ }
603
+
604
+ /**
605
+ * Leverage backtrace to find caller plugin file path.
606
+ *
607
+ * @author Vova Feldman (@svovaf)
608
+ * @since 1.0.6
609
+ *
610
+ * @return string
611
+ */
612
+ private function _find_caller_plugin_file() {
613
+ $bt = debug_backtrace();
614
+ $backtrace_entries_count = count( $bt );
615
+
616
+ // Try to load the cached value of the file path.
617
+ if ( isset( $this->_storage->plugin_main_file ) ) {
618
+ if ( file_exists( $this->_storage->plugin_main_file->path ) ) {
619
+ return $this->_storage->plugin_main_file->path;
620
+ }
621
+ }
622
+
623
+ /**
624
+ * All the code below will be executed once on activation.
625
+ * If the user changes the main plugin's file name, the file_exists()
626
+ * will catch it.
627
+ */
628
+ self::require_plugin_essentials();
629
+
630
+ $all_plugins = get_plugins();
631
+ $all_plugins_paths = array();
632
+
633
+ // Get active plugin's main files real full names (might be symlinks).
634
+ foreach ( $all_plugins as $relative_path => &$data ) {
635
+ $all_plugins_paths[] = fs_normalize_path( realpath( WP_PLUGIN_DIR . '/' . $relative_path ) );
636
+ }
637
+
638
+ $plugin_file = null;
639
+ for ( $i = 1; $i < $backtrace_entries_count; $i ++ ) {
640
+ if ( in_array( fs_normalize_path( $bt[ $i ]['file'] ), $all_plugins_paths ) ) {
641
+ $plugin_file = $bt[ $i ]['file'];
642
+ break;
643
+ }
644
+ }
645
+
646
+ if ( is_null( $plugin_file ) ) {
647
+ // Throw an error to the developer in case of some edge case dev environment.
648
+ wp_die( __fs( 'failed-finding-main-path' ), __fs( 'error' ), array( 'back_link' => true ) );
649
+ }
650
+
651
+ $this->_storage->plugin_main_file = (object) array(
652
+ 'path' => fs_normalize_path( $plugin_file ),
653
+ );
654
+
655
+ return $plugin_file;
656
+ }
657
+
658
+ #region Instance ------------------------------------------------------------------
659
+
660
+ /**
661
+ * Main singleton instance.
662
+ *
663
+ * @author Vova Feldman (@svovaf)
664
+ * @since 1.0.0
665
+ *
666
+ * @param $slug
667
+ *
668
+ * @return Freemius
669
+ */
670
+ static function instance( $slug ) {
671
+ $slug = strtolower( $slug );
672
+
673
+ if ( ! isset( self::$_instances[ $slug ] ) ) {
674
+ if ( 0 === count( self::$_instances ) ) {
675
+ self::_load_required_static();
676
+ }
677
+
678
+ self::$_instances[ $slug ] = new Freemius( $slug );
679
+ }
680
+
681
+ return self::$_instances[ $slug ];
682
+ }
683
+
684
+ /**
685
+ * @author Vova Feldman (@svovaf)
686
+ * @since 1.0.6
687
+ *
688
+ * @param string|number $slug_or_id
689
+ *
690
+ * @return bool
691
+ */
692
+ private static function has_instance( $slug_or_id ) {
693
+ return ! is_numeric( $slug_or_id ) ?
694
+ isset( self::$_instances[ strtolower( $slug_or_id ) ] ) :
695
+ ( false !== self::get_instance_by_id( $slug_or_id ) );
696
+ }
697
+
698
+ /**
699
+ * @author Vova Feldman (@svovaf)
700
+ * @since 1.0.6
701
+ *
702
+ * @param $id
703
+ *
704
+ * @return false|Freemius
705
+ */
706
+ static function get_instance_by_id( $id ) {
707
+ foreach ( self::$_instances as $slug => $instance ) {
708
+ if ( $id == $instance->get_id() ) {
709
+ return $instance;
710
+ }
711
+ }
712
+
713
+ return false;
714
+ }
715
+
716
+ /**
717
+ *
718
+ * @author Vova Feldman (@svovaf)
719
+ * @since 1.0.1
720
+ *
721
+ * @param $plugin_file
722
+ *
723
+ * @return false|Freemius
724
+ */
725
+ static function get_instance_by_file( $plugin_file ) {
726
+ $slug = self::find_slug_by_basename( $plugin_file );
727
+
728
+ return ( false !== $slug ) ?
729
+ self::instance( $slug ) :
730
+ false;
731
+ }
732
+
733
+ /**
734
+ * @author Vova Feldman (@svovaf)
735
+ * @since 1.0.6
736
+ *
737
+ * @return false|Freemius
738
+ */
739
+ function get_parent_instance() {
740
+ return self::get_instance_by_id( $this->_plugin->parent_plugin_id );
741
+ }
742
+
743
+ /**
744
+ * @author Vova Feldman (@svovaf)
745
+ * @since 1.0.6
746
+ *
747
+ * @param $slug_or_id
748
+ *
749
+ * @return bool|Freemius
750
+ */
751
+ function get_addon_instance( $slug_or_id ) {
752
+ return ! is_numeric( $slug_or_id ) ?
753
+ self::instance( strtolower( $slug_or_id ) ) :
754
+ self::get_instance_by_id( $slug_or_id );
755
+ }
756
+
757
+ #endregion ------------------------------------------------------------------
758
+
759
+ /**
760
+ * @author Vova Feldman (@svovaf)
761
+ * @since 1.0.6
762
+ *
763
+ * @return bool
764
+ */
765
+ function is_parent_plugin_installed() {
766
+ return self::has_instance( $this->_plugin->parent_plugin_id );
767
+ }
768
+
769
+ /**
770
+ * Check if add-on parent plugin in activation mode.
771
+ *
772
+ * @author Vova Feldman (@svovaf)
773
+ * @since 1.0.7
774
+ *
775
+ * @return bool
776
+ */
777
+ function is_parent_in_activation() {
778
+ $parent_fs = $this->get_parent_instance();
779
+ if ( ! is_object( $parent_fs ) ) {
780
+ return false;
781
+ }
782
+
783
+ return ( $parent_fs->is_activation_mode() );
784
+ }
785
+
786
+ /**
787
+ * Is plugin in activation mode.
788
+ *
789
+ * @author Vova Feldman (@svovaf)
790
+ * @since 1.0.7
791
+ *
792
+ * @return bool
793
+ */
794
+ function is_activation_mode() {
795
+ return (
796
+ ! $this->is_registered() &&
797
+ ( ! $this->enable_anonymous() ||
798
+ ( ! $this->is_anonymous() && ! $this->is_pending_activation() ) )
799
+ );
800
+ }
801
+
802
+ private static $_statics_loaded = false;
803
+
804
+ /**
805
+ * Load static resources.
806
+ *
807
+ * @author Vova Feldman (@svovaf)
808
+ * @since 1.0.1
809
+ */
810
+ private static function _load_required_static() {
811
+ if ( self::$_statics_loaded ) {
812
+ return;
813
+ }
814
+
815
+ self::$_static_logger = FS_Logger::get_logger( WP_FS__SLUG, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
816
+
817
+ self::$_static_logger->entrance();
818
+
819
+ self::$_accounts = FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
820
+
821
+ // Configure which Freemius powered plugins should be auto updated.
822
+ // add_filter( 'auto_update_plugin', '_include_plugins_in_auto_update', 10, 2 );
823
+
824
+ if ( WP_FS__DEV_MODE ) {
825
+ add_action( 'admin_menu', array( 'Freemius', 'add_debug_page' ) );
826
+ }
827
+
828
+ self::$_statics_loaded = true;
829
+ }
830
+
831
+ #region Debugging ------------------------------------------------------------------
832
+
833
+ /**
834
+ * @author Vova Feldman (@svovaf)
835
+ * @since 1.0.8
836
+ */
837
+ static function add_debug_page() {
838
+ self::$_static_logger->entrance();
839
+
840
+ $hook = add_object_page(
841
+ __fs( 'freemius-debug' ),
842
+ __fs( 'freemius-debug' ),
843
+ 'manage_options',
844
+ 'freemius',
845
+ array( 'Freemius', '_debug_page_render' )
846
+ );
847
+
848
+ add_action( "load-$hook", array( 'Freemius', '_debug_page_actions' ) );
849
+ }
850
+
851
+ /**
852
+ * @author Vova Feldman (@svovaf)
853
+ * @since 1.0.8
854
+ */
855
+ static function _debug_page_actions() {
856
+ if ( fs_request_is_action( 'delete_all_accounts' ) ) {
857
+ check_admin_referer( 'delete_all_accounts' );
858
+
859
+ self::$_accounts->clear( true );
860
+
861
+ return;
862
+ }
863
+ }
864
+
865
+ /**
866
+ * @author Vova Feldman (@svovaf)
867
+ * @since 1.0.8
868
+ */
869
+ static function _debug_page_render() {
870
+ self::$_static_logger->entrance();
871
+
872
+ $sites = self::get_all_sites();
873
+ $users = self::get_all_users();
874
+ $addons = self::get_all_addons();
875
+ $account_addons = self::get_all_account_addons();
876
+
877
+ // $plans = self::get_all_plans();
878
+ // $licenses = self::get_all_licenses();
879
+
880
+ $vars = array(
881
+ 'sites' => $sites,
882
+ 'users' => $users,
883
+ 'addons' => $addons,
884
+ 'account_addons' => $account_addons,
885
+ );
886
+ fs_require_once_template( 'debug.php', $vars );
887
+ }
888
+
889
+ #endregion ------------------------------------------------------------------
890
+
891
+ #region Connectivity Issues ------------------------------------------------------------------
892
+
893
+ /**
894
+ * Check if Freemius should be turned on for the current plugin install.
895
+ *
896
+ * @author Vova Feldman (@svovaf)
897
+ * @since 1.0.9
898
+ *
899
+ * @return bool
900
+ */
901
+ private function is_on() {
902
+ self::$_static_logger->entrance();
903
+
904
+ if ( isset( $this->_is_on ) ) {
905
+ return $this->_is_on;
906
+ }
907
+
908
+ // If already installed or pending then sure it's on :)
909
+ if ( $this->is_registered() || $this->is_pending_activation() ) {
910
+ $this->_is_on = true;
911
+
912
+ return $this->_is_on;
913
+ }
914
+ }
915
+
916
+ /**
917
+ * Check if there's any connectivity issue to Freemius API.
918
+ *
919
+ * @author Vova Feldman (@svovaf)
920
+ * @since 1.0.9
921
+ *
922
+ * @param bool $flush
923
+ *
924
+ * @return bool
925
+ */
926
+ private function has_api_connectivity($flush = false) {
927
+ if (!$flush && isset( $this->_has_api_connection ) ) {
928
+ return $this->_has_api_connection;
929
+ }
930
+
931
+ $version = $this->get_plugin_version();
932
+
933
+ if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY &&
934
+ isset( $this->_storage->connectivity_test ) &&
935
+ true === $this->_storage->connectivity_test['is_connected']
936
+ ) {
937
+ unset( $this->_storage->connectivity_test );
938
+ }
939
+
940
+ if (isset( $this->_storage->connectivity_test ) ) {
941
+ if ( $_SERVER['HTTP_HOST'] == $this->_storage->connectivity_test['host'] &&
942
+ $_SERVER['SERVER_ADDR'] == $this->_storage->connectivity_test['server_ip']
943
+ ) {
944
+ if ( ( $this->_storage->connectivity_test['is_connected'] &&
945
+ $this->_storage->connectivity_test['is_active'] ) ||
946
+ (!$flush &&
947
+ $version == $this->_storage->connectivity_test['version'])
948
+ ) {
949
+ $this->_has_api_connection = $this->_storage->connectivity_test['is_connected'];
950
+ $this->_is_on = $this->_storage->connectivity_test['is_active'];
951
+
952
+ return $this->_has_api_connection;
953
+ }
954
+ }
955
+ }
956
+
957
+ $is_update = $this->apply_filters( 'is_plugin_update', !$this->is_plugin_new_install() );
958
+
959
+ if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY ) {
960
+ $is_connected = false;
961
+ } else {
962
+ $pong = $this->get_api_plugin_scope()->ping( $this->get_anonymous_id(), $is_update );
963
+ $is_connected = $this->get_api_plugin_scope()->is_valid_ping( $pong );
964
+ }
965
+
966
+ if ( ! $is_connected ) {
967
+ // 2nd try of connectivity.
968
+ $pong = $this->get_api_plugin_scope()->ping( $this->get_anonymous_id(), $is_update );
969
+
970
+ if ( $this->get_api_plugin_scope()->is_valid_ping( $pong ) ) {
971
+ $is_connected = true;
972
+ } else {
973
+ // Another API failure.
974
+ $this->_add_connectivity_issue_message( $pong );
975
+ }
976
+ }
977
+
978
+ $is_active = ( ! $is_connected ) ?
979
+ false :
980
+ ( isset( $pong->is_active ) && true == $pong->is_active );
981
+
982
+ $this->_storage->connectivity_test = array(
983
+ 'is_connected' => $is_connected,
984
+ 'host' => $_SERVER['HTTP_HOST'],
985
+ 'server_ip' => $_SERVER['SERVER_ADDR'],
986
+ 'is_active' => $is_active,
987
+ 'timestamp' => WP_FS__SCRIPT_START_TIME,
988
+ // Last version with connectivity attempt.
989
+ 'version' => $version,
990
+ );
991
+
992
+ $this->_has_api_connection = $is_connected;
993
+ $this->_is_on = $is_active;
994
+
995
+ return $this->_has_api_connection;
996
+ }
997
+
998
+ /**
999
+ * Anonymous and unique site identifier (Hash).
1000
+ *
1001
+ * @author Vova Feldman (@svovaf)
1002
+ * @since 1.1.0
1003
+ *
1004
+ * @return string
1005
+ */
1006
+ function get_anonymous_id() {
1007
+ if ( ! self::$_accounts->has_option( 'unique_id' ) ) {
1008
+ $key = get_site_url();
1009
+
1010
+ // If localhost, assign microtime instead of domain.
1011
+ if ( WP_FS__IS_LOCALHOST || false !== strpos( $key, 'localhost' ) ) {
1012
+ $key = microtime();
1013
+ }
1014
+
1015
+ self::$_accounts->set_option( 'unique_id', md5( $key ), true );
1016
+ }
1017
+
1018
+ return self::$_accounts->get_option( 'unique_id' );
1019
+ }
1020
+
1021
+ /**
1022
+ * Generate API connectivity issue message.
1023
+ *
1024
+ * @author Vova Feldman (@svovaf)
1025
+ * @since 1.0.9
1026
+ *
1027
+ * @param mixed $api_result
1028
+ */
1029
+ function _add_connectivity_issue_message( $api_result ) {
1030
+ if ( $this->_enable_anonymous ) {
1031
+ // Don't add message if can run anonymously.
1032
+ return;
1033
+ }
1034
+
1035
+ if ( ! function_exists( 'wp_nonce_url' ) ) {
1036
+ require_once( ABSPATH . 'wp-includes/functions.php' );
1037
+ }
1038
+
1039
+ self::require_pluggable_essentials();
1040
+
1041
+ $current_user = wp_get_current_user();
1042
+ // $admin_email = get_option( 'admin_email' );
1043
+ $admin_email = $current_user->user_email;
1044
+
1045
+ $message = false;
1046
+ if ( is_object( $api_result ) &&
1047
+ isset( $api_result->error )
1048
+ ) {
1049
+ switch ( $api_result->error->code ) {
1050
+ case 'curl_missing':
1051
+ $message = sprintf(
1052
+ __fs( 'x-requires-access-to-api', 'freemius' ) . ' ' .
1053
+ __fs( 'curl-missing-message' ) . ' ' .
1054
+ ' %s',
1055
+ '<b>' . $this->get_plugin_name() . '</b>',
1056
+ sprintf(
1057
+ '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1058
+ sprintf(
1059
+ '<a class="fs-resolve" data-type="curl" href="#"><b>%s</b></a>%s',
1060
+ __fs( 'curl-missing-no-clue-title' ),
1061
+ ' - ' . sprintf(
1062
+ __fs( 'curl-missing-no-clue-desc' ),
1063
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1064
+ )
1065
+ ),
1066
+ sprintf(
1067
+ '<b>%s</b> - %s',
1068
+ __fs( 'sysadmin-title' ),
1069
+ __fs( 'curl-missing-sysadmin-desc' )
1070
+ ),
1071
+ sprintf(
1072
+ '<a href="%s"><b>%s</b></a>%s',
1073
+ wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $this->_plugin_basename . '&amp;plugin_status=' . 'all' . '&amp;paged=' . '1' . '&amp;s=' . '', 'deactivate-plugin_' . $this->_plugin_basename ),
1074
+ __fs( 'deactivate-plugin-title' ),
1075
+ ' - ' . __fs( 'deactivate-plugin-desc', 'freemius' )
1076
+ )
1077
+ )
1078
+ );
1079
+ break;
1080
+ case 'cloudflare_ddos_protection':
1081
+ $message = sprintf(
1082
+ __fs( 'x-requires-access-to-api', 'freemius' ) . ' ' .
1083
+ __fs( 'cloudflare-blocks-connection-message' ) . ' ' .
1084
+ __fs( 'happy-to-resolve-issue-asap' ) .
1085
+ ' %s',
1086
+ '<b>' . $this->get_plugin_name() . '</b>',
1087
+ sprintf(
1088
+ '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1089
+ sprintf(
1090
+ '<a class="fs-resolve" data-type="cloudflare" href="#"><b>%s</b></a>%s',
1091
+ __fs( 'fix-issue-title' ),
1092
+ ' - ' . sprintf(
1093
+ __fs( 'fix-issue-desc' ),
1094
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1095
+ )
1096
+ ),
1097
+ sprintf(
1098
+ '<a href="%s" target="_blank"><b>%s</b></a>%s',
1099
+ sprintf( 'https://wordpress.org/plugins/%s/download/', $this->_slug ),
1100
+ __fs( 'install-previous-title' ),
1101
+ ' - ' . __fs( 'install-previous-desc' )
1102
+ ),
1103
+ sprintf(
1104
+ '<a href="%s"><b>%s</b></a>%s',
1105
+ wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $this->_plugin_basename . '&amp;plugin_status=' . 'all' . '&amp;paged=' . '1' . '&amp;s=' . '', 'deactivate-plugin_' . $this->_plugin_basename ),
1106
+ __fs( 'deactivate-plugin-title' ),
1107
+ ' - ' . __fs( 'deactivate-plugin-desc', 'freemius' )
1108
+ )
1109
+ )
1110
+ );
1111
+ break;
1112
+ case 'squid_cache_block':
1113
+ $message = sprintf(
1114
+ __fs( 'x-requires-access-to-api', 'freemius' ) . ' ' .
1115
+ __fs( 'squid-blocks-connection-message' ) .
1116
+ ' %s',
1117
+ '<b>' . $this->get_plugin_name() . '</b>',
1118
+ sprintf(
1119
+ '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1120
+ sprintf(
1121
+ '<a class="fs-resolve" data-type="squid" href="#"><b>%s</b></a>%s',
1122
+ __fs( 'squid-no-clue-title' ),
1123
+ ' - ' . sprintf(
1124
+ __fs( 'squid-no-clue-desc' ),
1125
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1126
+ )
1127
+ ),
1128
+ sprintf(
1129
+ '<b>%s</b> - %s',
1130
+ __fs( 'sysadmin-title' ),
1131
+ sprintf(
1132
+ __fs( 'squid-sysadmin-desc' ),
1133
+ // We use a filter since the plugin might require additional API connectivity.
1134
+ '<b>' . implode( ', ', $this->apply_filters( 'api_domains', array( 'api.freemius.com' ) ) ) . '</b>' )
1135
+ ),
1136
+ sprintf(
1137
+ '<a href="%s"><b>%s</b></a>%s',
1138
+ wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $this->_plugin_basename . '&amp;plugin_status=' . 'all' . '&amp;paged=' . '1' . '&amp;s=' . '', 'deactivate-plugin_' . $this->_plugin_basename ),
1139
+ __fs( 'deactivate-plugin-title' ),
1140
+ ' - ' . __fs( 'deactivate-plugin-desc', 'freemius' )
1141
+ )
1142
+ )
1143
+ );
1144
+ break;
1145
+ default:
1146
+ $message = __fs( 'connectivity-test-fails-message' );
1147
+ break;
1148
+ }
1149
+ }
1150
+
1151
+ if ( false === $message ) {
1152
+ $message = sprintf(
1153
+ __fs( 'x-requires-access-to-api', 'freemius' ) . ' ' .
1154
+ __fs( 'connectivity-test-fails-message' ) . ' ' .
1155
+ __fs( 'happy-to-resolve-issue-asap' ) .
1156
+ ' %s',
1157
+ '<b>' . $this->get_plugin_name() . '</b>',
1158
+ sprintf(
1159
+ '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1160
+ sprintf(
1161
+ '<a class="fs-resolve" data-type="general" href="#"><b>%s</b></a>%s',
1162
+ __fs( 'fix-issue-title' ),
1163
+ ' - ' . sprintf(
1164
+ __fs( 'fix-issue-desc' ),
1165
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1166
+ )
1167
+ ),
1168
+ sprintf(
1169
+ '<a href="%s" target="_blank"><b>%s</b></a>%s',
1170
+ sprintf( 'https://wordpress.org/plugins/%s/download/', $this->_slug ),
1171
+ __fs( 'install-previous-title' ),
1172
+ ' - ' . __fs( 'install-previous-desc' )
1173
+ ),
1174
+ sprintf(
1175
+ '<a href="%s"><b>%s</b></a>%s',
1176
+ wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $this->_plugin_basename . '&amp;plugin_status=' . 'all' . '&amp;paged=' . '1' . '&amp;s=' . '', 'deactivate-plugin_' . $this->_plugin_basename ),
1177
+ __fs( 'deactivate-plugin-title' ),
1178
+ ' - ' . __fs( 'deactivate-plugin-desc', 'freemius' )
1179
+ )
1180
+ )
1181
+ );
1182
+ }
1183
+
1184
+ $this->_admin_notices->add_sticky(
1185
+ $message,
1186
+ 'failed_connect_api',
1187
+ __fs( 'oops' ) . '...',
1188
+ 'error'
1189
+ );
1190
+ }
1191
+
1192
+ /**
1193
+ * Get collection of all active plugins.
1194
+ *
1195
+ * @author Vova Feldman (@svovaf)
1196
+ * @since 1.0.9
1197
+ *
1198
+ * @return array[string]array
1199
+ */
1200
+ private function get_active_plugins() {
1201
+ self::require_plugin_essentials();
1202
+
1203
+ $active_plugin = array();
1204
+ $all_plugins = get_plugins();
1205
+ $active_plugins_basenames = get_option( 'active_plugins' );
1206
+
1207
+ foreach ( $active_plugins_basenames as $plugin_basename ) {
1208
+ $active_plugin[ $plugin_basename ] = $all_plugins[ $plugin_basename ];
1209
+ }
1210
+
1211
+ return $active_plugin;
1212
+ }
1213
+
1214
+ /**
1215
+ * Handle user request to resolve connectivity issue.
1216
+ * This method will send an email to Freemius API technical staff for resolution.
1217
+ * The email will contain server's info and installed plugins (might be caching issue).
1218
+ *
1219
+ * @author Vova Feldman (@svovaf)
1220
+ * @since 1.0.9
1221
+ */
1222
+ function _email_about_firewall_issue() {
1223
+ $this->_admin_notices->remove_sticky( 'failed_connect_api' );
1224
+
1225
+ self::require_pluggable_essentials();
1226
+
1227
+ $current_user = wp_get_current_user();
1228
+ $admin_email = $current_user->user_email;
1229
+
1230
+ $ping = $this->get_api_plugin_scope()->ping();
1231
+
1232
+ $error_type = fs_request_get( 'error_type', 'general' );
1233
+
1234
+ switch ( $error_type ) {
1235
+ case 'squid':
1236
+ $title = 'Squid ACL Blocking Issue';
1237
+ break;
1238
+ case 'cloudflare':
1239
+ $title = 'CloudFlare Blocking Issue';
1240
+ break;
1241
+ default:
1242
+ $title = 'API Connectivity Issue';
1243
+ break;
1244
+ }
1245
+
1246
+ $custom_email_sections = array();
1247
+
1248
+ if ( 'squid' === $error_type ) {
1249
+ // Override the 'Site' email section.
1250
+ $custom_email_sections['site'] = array(
1251
+ 'rows' => array(
1252
+ 'hosting_company' => array( 'Hosting Company', fs_request_get( 'hosting_company' ) )
1253
+ )
1254
+ );
1255
+ }
1256
+
1257
+ // Add 'API Error' custom email section.
1258
+ $custom_email_sections['api_error'] = array(
1259
+ 'title' => 'API Error',
1260
+ 'rows' => array(
1261
+ 'ping' => array( is_string( $ping ) ? htmlentities( $ping ) : json_encode( $ping ) )
1262
+ )
1263
+ );
1264
+
1265
+ // Send email with technical details to resolve CloudFlare's firewall unnecessary protection.
1266
+ $this->send_email(
1267
+ 'api@freemius.com', // recipient
1268
+ $title . ' [' . $this->get_plugin_name() . ']', // subject
1269
+ $custom_email_sections,
1270
+ array( "Reply-To: $admin_email <$admin_email>" ) // headers
1271
+ );
1272
+
1273
+ $this->_admin_notices->add_sticky(
1274
+ sprintf(
1275
+ __fs( 'fix-request-sent-message' ),
1276
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1277
+ ),
1278
+ 'server_details_sent'
1279
+ );
1280
+
1281
+ // Action was taken, tell that API connectivity troubleshooting should be off now.
1282
+
1283
+ echo "1";
1284
+ exit;
1285
+ }
1286
+
1287
+ static function _add_firewall_issues_javascript() {
1288
+ $params = array();
1289
+ fs_require_once_template( 'firewall-issues-js.php', $params );
1290
+ }
1291
+
1292
+ #endregion Connectivity Issues ------------------------------------------------------------------
1293
+
1294
+ #region Email ------------------------------------------------------------------
1295
+
1296
+ /**
1297
+ * Generates and sends an HTML email with customizable sections.
1298
+ *
1299
+ * @author Leo Fajardo (@leorw)
1300
+ * @since 1.1.2
1301
+ *
1302
+ * @param string $to_address
1303
+ * @param string $subject
1304
+ * @param array $sections
1305
+ * @param array $headers
1306
+ *
1307
+ * @return bool Whether the email contents were sent successfully.
1308
+ */
1309
+ private function send_email(
1310
+ $to_address,
1311
+ $subject,
1312
+ $sections = array(),
1313
+ $headers = array()
1314
+ ) {
1315
+ $default_sections = $this->get_email_sections();
1316
+
1317
+ // Insert new sections or replace the default email sections.
1318
+ if ( is_array( $sections ) && ! empty( $sections ) ) {
1319
+ foreach ( $sections as $section_id => $custom_section ) {
1320
+ if ( ! isset( $default_sections[ $section_id ] ) ) {
1321
+ // If the section does not exist, add it.
1322
+ $default_sections[ $section_id ] = $custom_section;
1323
+ } else {
1324
+ // If the section already exists, override it.
1325
+ $current_section = $default_sections[ $section_id ];
1326
+
1327
+ // Replace the current section's title if a custom section title exists.
1328
+ if ( isset( $custom_section['title'] ) ) {
1329
+ $current_section['title'] = $custom_section['title'];
1330
+ }
1331
+
1332
+ // Insert new rows under the current section or replace the default rows.
1333
+ if ( isset( $custom_section['rows'] ) && is_array( $custom_section['rows'] ) && ! empty( $custom_section['rows'] ) ) {
1334
+ foreach ( $custom_section['rows'] as $row_id => $row ) {
1335
+ $current_section['rows'][ $row_id ] = $row;
1336
+ }
1337
+ }
1338
+
1339
+ $default_sections[ $section_id ] = $current_section;
1340
+ }
1341
+ }
1342
+ }
1343
+
1344
+ $vars = array( 'sections' => $default_sections );
1345
+ $message = fs_get_template( 'email.php', $vars );
1346
+
1347
+ // Set the type of email to HTML.
1348
+ $headers[] = 'Content-type: text/html';
1349
+
1350
+ $header_string = implode( "\r\n", $headers );
1351
+
1352
+ return wp_mail(
1353
+ $to_address,
1354
+ $subject,
1355
+ $message,
1356
+ $header_string
1357
+ );
1358
+ }
1359
+
1360
+ /**
1361
+ * Generates the data for the sections of the email content.
1362
+ *
1363
+ * @author Leo Fajardo (@leorw)
1364
+ * @since 1.1.2
1365
+ *
1366
+ * @return array
1367
+ */
1368
+ private function get_email_sections() {
1369
+ self::require_pluggable_essentials();
1370
+
1371
+ // Retrieve the current user's information so that we can get the user's email, first name, and last name below.
1372
+ $current_user = wp_get_current_user();
1373
+
1374
+ // Retrieve the cURL version information so that we can get the version number below.
1375
+ $curl_version_information = curl_version();
1376
+
1377
+ $active_plugin = $this->get_active_plugins();
1378
+
1379
+ // Generate the list of active plugins separated by new line.
1380
+ $active_plugin_string = '';
1381
+ foreach ( $active_plugin as $plugin ) {
1382
+ $active_plugin_string .= sprintf(
1383
+ '<a href="%s">%s</a> [v%s]<br>',
1384
+ $plugin['PluginURI'],
1385
+ $plugin['Name'],
1386
+ $plugin['Version']
1387
+ );
1388
+ }
1389
+
1390
+ // Generate the default email sections.
1391
+ $sections = array(
1392
+ 'sdk' => array(
1393
+ 'title' => 'SDK',
1394
+ 'rows' => array(
1395
+ 'fs_version' => array( 'FS Version', $this->version ),
1396
+ 'curl_version' => array( 'cURL Version', $curl_version_information['version'] )
1397
+ )
1398
+ ),
1399
+ 'plugin' => array(
1400
+ 'title' => 'Plugin',
1401
+ 'rows' => array(
1402
+ 'name' => array( 'Name', $this->get_plugin_name() ),
1403
+ 'version' => array( 'Version', $this->get_plugin_version() )
1404
+ )
1405
+ ),
1406
+ 'site' => array(
1407
+ 'title' => 'Site',
1408
+ 'rows' => array(
1409
+ 'address' => array( 'Address', site_url() ),
1410
+ 'host' => array(
1411
+ 'HTTP_HOST',
1412
+ ( ! empty( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '' )
1413
+ ),
1414
+ 'server_addr' => array(
1415
+ 'SERVER_ADDR',
1416
+ ( ! empty( $_SERVER['SERVER_ADDR'] ) ? '<a href="http://www.projecthoneypot.org/ip_' . $_SERVER['SERVER_ADDR'] . '">' . $_SERVER['SERVER_ADDR'] . '</a>' : '' )
1417
+ )
1418
+ )
1419
+ ),
1420
+ 'user' => array(
1421
+ 'title' => 'User',
1422
+ 'rows' => array(
1423
+ 'email' => array( 'Email', $current_user->user_email ),
1424
+ 'first' => array( 'First', $current_user->user_firstname ),
1425
+ 'last' => array( 'Last', $current_user->user_lastname )
1426
+ )
1427
+ ),
1428
+ 'plugins' => array(
1429
+ 'title' => 'Plugins',
1430
+ 'rows' => array(
1431
+ 'active_plugins' => array( 'Active Plugins', $active_plugin_string )
1432
+ )
1433
+ ),
1434
+ );
1435
+
1436
+ // Allow the sections to be modified by other code.
1437
+ $sections = $this->apply_filters( 'email_template_sections', $sections );
1438
+
1439
+ return $sections;
1440
+ }
1441
+
1442
+ #endregion Email ------------------------------------------------------------------
1443
+
1444
+ #region Initialization ------------------------------------------------------------------
1445
+
1446
+ /**
1447
+ * Init plugin's Freemius instance.
1448
+ *
1449
+ * @author Vova Feldman (@svovaf)
1450
+ * @since 1.0.1
1451
+ *
1452
+ * @param number $id
1453
+ * @param string $public_key
1454
+ * @param bool $is_live
1455
+ * @param bool $is_premium
1456
+ */
1457
+ function init( $id, $public_key, $is_live = true, $is_premium = true ) {
1458
+ $this->_logger->entrance();
1459
+
1460
+ $this->dynamic_init( array(
1461
+ 'id' => $id,
1462
+ 'public_key' => $public_key,
1463
+ 'is_live' => $is_live,
1464
+ 'is_premium' => $is_premium,
1465
+ ) );
1466
+ }
1467
+
1468
+ private function _get_option( &$options, $key, $default = false ) {
1469
+ return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
1470
+ }
1471
+
1472
+ private function _get_bool_option( &$options, $key, $default = false ) {
1473
+ return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
1474
+ }
1475
+
1476
+ private function _get_numeric_option( &$options, $key, $default = false ) {
1477
+ return isset( $options[ $key ] ) && is_numeric( $options[ $key ] ) ? $options[ $key ] : $default;
1478
+ }
1479
+
1480
+ /**
1481
+ * Dynamic initiator, originally created to support initiation
1482
+ * with parent_id for add-ons.
1483
+ *
1484
+ * @author Vova Feldman (@svovaf)
1485
+ * @since 1.0.6
1486
+ *
1487
+ * @param array $plugin_info
1488
+ *
1489
+ * @throws Freemius_Exception
1490
+ */
1491
+ function dynamic_init( array $plugin_info ) {
1492
+ $this->_logger->entrance();
1493
+
1494
+ $id = $this->_get_numeric_option( $plugin_info, 'id', false );
1495
+ $public_key = $this->_get_option( $plugin_info, 'public_key', false );
1496
+ $secret_key = $this->_get_option( $plugin_info, 'secret_key', null );
1497
+ $parent_id = $this->_get_numeric_option( $plugin_info, 'parent_id', null );
1498
+ $parent_name = $this->_get_option( $plugin_info, 'parent_name', null );
1499
+
1500
+ if ( isset( $plugin_info['parent'] ) ) {
1501
+ $parent_id = $this->_get_numeric_option( $plugin_info['parent'], 'id', null );
1502
+ // $parent_slug = $this->get_option( $plugin_info['parent'], 'slug', null );
1503
+ // $parent_public_key = $this->get_option( $plugin_info['parent'], 'public_key', null );
1504
+ $parent_name = $this->_get_option( $plugin_info['parent'], 'name', null );
1505
+ }
1506
+
1507
+ if ( false === $id ) {
1508
+ throw new Freemius_Exception( 'Plugin id parameter is not set.' );
1509
+ }
1510
+ if ( false === $public_key ) {
1511
+ throw new Freemius_Exception( 'Plugin public_key parameter is not set.' );
1512
+ }
1513
+
1514
+ $plugin = ( $this->_plugin instanceof FS_Plugin ) ?
1515
+ $this->_plugin :
1516
+ new FS_Plugin();
1517
+
1518
+ $plugin->update( array(
1519
+ 'id' => $id,
1520
+ 'public_key' => $public_key,
1521
+ 'slug' => $this->_slug,
1522
+ 'parent_plugin_id' => $parent_id,
1523
+ 'version' => $this->get_plugin_version(),
1524
+ 'title' => $this->get_plugin_name(),
1525
+ 'file' => $this->_free_plugin_basename,
1526
+ 'is_premium' => $this->_get_bool_option( $plugin_info, 'is_premium', true ),
1527
+ 'is_live' => $this->_get_bool_option( $plugin_info, 'is_live', true ),
1528
+ // 'secret_key' => $secret_key,
1529
+ ) );
1530
+
1531
+ if ( $plugin->is_updated() ) {
1532
+ // Update plugin details.
1533
+ $this->_plugin = FS_Plugin_Manager::instance( $this->_slug )->store( $plugin );
1534
+ }
1535
+ $this->_plugin->secret_key = $secret_key;
1536
+
1537
+ if ( ! isset( $plugin_info['menu'] ) ) {
1538
+ // Back compatibility to 1.1.2
1539
+ $plugin_info['menu'] = array(
1540
+ 'slug' => isset( $plugin_info['menu_slug'] ) ?
1541
+ $plugin_info['menu_slug'] :
1542
+ $this->_slug
1543
+ );
1544
+ }
1545
+
1546
+ $this->_menu = FS_Admin_Menu_Manager::instance( $this->_slug );
1547
+ $this->_menu->init( $plugin_info['menu'], $this->is_addon() );
1548
+
1549
+ $this->_has_addons = $this->_get_bool_option( $plugin_info, 'has_addons', false );
1550
+ $this->_has_paid_plans = $this->_get_bool_option( $plugin_info, 'has_paid_plans', true );
1551
+ $this->_is_org_compliant = $this->_get_bool_option( $plugin_info, 'is_org_compliant', true );
1552
+ $this->_enable_anonymous = $this->_get_bool_option( $plugin_info, 'enable_anonymous', true );
1553
+
1554
+ if ( ! $this->is_registered() ) {
1555
+ if ( ! $this->has_api_connectivity() ) {
1556
+ if ( is_admin() && $this->_admin_notices->has_sticky( 'failed_connect_api' ) ) {
1557
+ if ( ! $this->_enable_anonymous ) {
1558
+ // If anonymous mode is disabled, add firewall admin-notice message.
1559
+ add_action( 'admin_footer', array( 'Freemius', '_add_firewall_issues_javascript' ) );
1560
+
1561
+ add_action( "wp_ajax_{$this->_slug}_resolve_firewall_issues", array(
1562
+ &$this,
1563
+ '_email_about_firewall_issue'
1564
+ ) );
1565
+ }
1566
+ }
1567
+
1568
+ return;
1569
+ }
1570
+
1571
+ // Check if Freemius is on for the current plugin.
1572
+ // This MUST be executed after all the plugin variables has been loaded.
1573
+ if ( ! $this->is_on() ) {
1574
+ return;
1575
+ }
1576
+ }
1577
+
1578
+ if ( false === $this->_background_sync() ) {
1579
+ // If background sync wasn't executed,
1580
+ // and if the plugin declared it has add-ons but
1581
+ // no add-ons found in the local data, then try to sync add-ons.
1582
+ if ( $this->_has_addons &&
1583
+ ! $this->is_addon() &&
1584
+ ( false === $this->get_addons() )
1585
+ ) {
1586
+ $this->_sync_addons();
1587
+ }
1588
+ }
1589
+
1590
+ if ( $this->is_addon() ) {
1591
+ if ( $this->is_parent_plugin_installed() ) {
1592
+ // Link to parent FS.
1593
+ $this->_parent = self::get_instance_by_id( $parent_id );
1594
+
1595
+ // Get parent plugin reference.
1596
+ $this->_parent_plugin = $this->_parent->get_plugin();
1597
+ }
1598
+ }
1599
+
1600
+ if ( is_admin() ) {
1601
+ global $pagenow;
1602
+ if ( 'plugins.php' === $pagenow ) {
1603
+ $this->hook_plugin_action_links();
1604
+ }
1605
+
1606
+ if ( $this->is_addon() ) {
1607
+ if ( ! $this->is_parent_plugin_installed() ) {
1608
+ $this->_admin_notices->add(
1609
+ ( is_string( $parent_name ) ?
1610
+ sprintf( __fs( 'addon-cannot-run-without-x' ), $this->get_plugin_name(), $parent_name ) :
1611
+ sprintf( __fs( 'addon-x-cannot-run-without-parent' ), $this->get_plugin_name() )
1612
+ ),
1613
+ __fs( 'oops' ) . '...',
1614
+ 'error'
1615
+ );
1616
+
1617
+ return;
1618
+ } else {
1619
+ if ( $this->_parent->is_registered() && ! $this->is_registered() ) {
1620
+ // If parent plugin activated, automatically install add-on for the user.
1621
+ $this->_activate_addon_account( $this->_parent );
1622
+ }
1623
+
1624
+ // @todo This should be only executed on activation. It should be migrated to register_activation_hook() together with other activation related logic.
1625
+ if ( $this->is_premium() ) {
1626
+ // Remove add-on download admin-notice.
1627
+ $this->_parent->_admin_notices->remove_sticky( 'addon_plan_upgraded_' . $this->_slug );
1628
+ }
1629
+ }
1630
+ } else {
1631
+ add_action( 'admin_init', array( &$this, '_admin_init_action' ) );
1632
+
1633
+ if ( $this->_has_addons() &&
1634
+ 'plugin-information' === fs_request_get( 'tab', false ) &&
1635
+ $this->get_id() == fs_request_get( 'parent_plugin_id', false )
1636
+ ) {
1637
+ // Remove default plugin information action.
1638
+ remove_all_actions( 'install_plugins_pre_plugin-information' );
1639
+
1640
+ require_once WP_FS__DIR_INCLUDES . '/fs-plugin-functions.php';
1641
+
1642
+ // Override action with custom plugins function for add-ons.
1643
+ add_action( 'install_plugins_pre_plugin-information', 'fs_install_plugin_information' );
1644
+
1645
+ // Override request for plugin information for Add-ons.
1646
+ add_filter( 'fs_plugins_api', array( &$this, '_get_addon_info_filter' ), WP_FS__DEFAULT_PRIORITY, 3 );
1647
+ } else {
1648
+ if ( $this->is_paying() || $this->_has_addons() ) {
1649
+ new FS_Plugin_Updater( $this );
1650
+ }
1651
+ }
1652
+ }
1653
+
1654
+ // if ( $this->is_registered() ||
1655
+ // $this->is_anonymous() ||
1656
+ // $this->is_pending_activation()
1657
+ // ) {
1658
+ // $this->_init_admin();
1659
+ // }
1660
+ }
1661
+
1662
+ $this->do_action( 'initiated' );
1663
+
1664
+ if ( ! $this->is_addon() ) {
1665
+ if ( $this->is_registered() ) {
1666
+ // Fix for upgrade from versions < 1.0.9.
1667
+ if ( ! isset( $this->_storage->activation_timestamp ) ) {
1668
+ $this->_storage->activation_timestamp = WP_FS__SCRIPT_START_TIME;
1669
+ }
1670
+ if ( $this->_storage->prev_is_premium !== $this->_plugin->is_premium ) {
1671
+ if ( isset( $this->_storage->prev_is_premium ) ) {
1672
+ add_action( is_admin() ? 'admin_init' : 'init', array(
1673
+ &$this,
1674
+ '_plugin_code_type_changed'
1675
+ ) );
1676
+ } else {
1677
+ // Set for code type for the first time.
1678
+ $this->_storage->prev_is_premium = $this->_plugin->is_premium;
1679
+ }
1680
+ }
1681
+
1682
+ $this->do_action( 'after_init_plugin_registered' );
1683
+ } else if ( $this->is_anonymous() ) {
1684
+ $this->do_action( 'after_init_plugin_anonymous' );
1685
+ } else if ( $this->is_pending_activation() ) {
1686
+ $this->do_action( 'after_init_plugin_pending_activations' );
1687
+ }
1688
+ } else {
1689
+ if ( $this->is_registered() ) {
1690
+ $this->do_action( 'after_init_addon_registered' );
1691
+ } else if ( $this->is_anonymous() ) {
1692
+ $this->do_action( 'after_init_addon_anonymous' );
1693
+ } else if ( $this->is_pending_activation() ) {
1694
+ $this->do_action( 'after_init_addon_pending_activations' );
1695
+ }
1696
+ }
1697
+ }
1698
+
1699
+ /**
1700
+ * Handles plugin's code type change (free <--> premium).
1701
+ *
1702
+ * @author Vova Feldman (@svovaf)
1703
+ * @since 1.0.9
1704
+ */
1705
+ function _plugin_code_type_changed() {
1706
+ // Send code type changes event.
1707
+ $this->sync_install();
1708
+
1709
+ if ( $this->is_premium() ) {
1710
+ // Activated premium code.
1711
+ $this->do_action( 'after_premium_version_activation' );
1712
+
1713
+ // Remove all sticky messages related to download of the premium version.
1714
+ $this->_admin_notices->remove_sticky( array(
1715
+ 'trial_started',
1716
+ 'plan_upgraded',
1717
+ 'plan_changed',
1718
+ ) );
1719
+
1720
+ $this->_admin_notices->add_sticky(
1721
+ __fs( 'premium-activated-message' ),
1722
+ 'premium_activated',
1723
+ __fs( 'woot' ) . '!'
1724
+ );
1725
+ } else {
1726
+ // Activated free code (after had the premium before).
1727
+ $this->do_action( 'after_free_version_reactivation' );
1728
+
1729
+ if ( $this->is_paying() && ! $this->is_premium() ) {
1730
+ $this->_admin_notices->add_sticky(
1731
+ sprintf(
1732
+ __fs( 'you-have-x-license' ),
1733
+ $this->_site->plan->title
1734
+ ) . ' ' . $this->_get_latest_download_link( sprintf(
1735
+ __fs( 'download-x-version-now' ),
1736
+ $this->_site->plan->title
1737
+ ) ),
1738
+ 'plan_upgraded',
1739
+ __fs( 'yee-haw' ) . '!'
1740
+ );
1741
+ }
1742
+ }
1743
+
1744
+ // Update is_premium of latest version.
1745
+ $this->_storage->prev_is_premium = $this->_plugin->is_premium;
1746
+ }
1747
+
1748
+ #endregion Initialization ------------------------------------------------------------------
1749
+
1750
+ #region Add-ons -------------------------------------------------------------------------
1751
+
1752
+ /**
1753
+ * Generate add-on plugin information.
1754
+ *
1755
+ * @author Vova Feldman (@svovaf)
1756
+ * @since 1.0.6
1757
+ *
1758
+ * @param array $data
1759
+ * @param string $action
1760
+ * @param object|null $args
1761
+ *
1762
+ * @return array|null
1763
+ */
1764
+ function _get_addon_info_filter( $data, $action = '', $args = null ) {
1765
+ $this->_logger->entrance();
1766
+
1767
+ $parent_plugin_id = fs_request_get( 'parent_plugin_id', false );
1768
+
1769
+ if ( $this->get_id() != $parent_plugin_id ||
1770
+ ( 'plugin_information' !== $action ) ||
1771
+ ! isset( $args->slug )
1772
+ ) {
1773
+ return $data;
1774
+ }
1775
+
1776
+ // Find add-on by slug.
1777
+ $addons = $this->get_addons();
1778
+ $selected_addon = false;
1779
+ foreach ( $addons as $addon ) {
1780
+ if ( $addon->slug == $args->slug ) {
1781
+ $selected_addon = $addon;
1782
+ break;
1783
+ }
1784
+ }
1785
+
1786
+ if ( false === $selected_addon ) {
1787
+ return $data;
1788
+ }
1789
+
1790
+ if ( ! isset( $selected_addon->info ) ) {
1791
+ // Setup some default info.
1792
+ $selected_addon->info = new stdClass();
1793
+ $selected_addon->info->selling_point_0 = 'Selling Point 1';
1794
+ $selected_addon->info->selling_point_1 = 'Selling Point 2';
1795
+ $selected_addon->info->selling_point_2 = 'Selling Point 3';
1796
+ $selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
1797
+ }
1798
+
1799
+ fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
1800
+
1801
+ $data = $args;
1802
+
1803
+ // Fetch as much as possible info from local files.
1804
+ $plugin_local_data = $this->get_plugin_data();
1805
+ $data->name = $selected_addon->title;
1806
+ $data->author = $plugin_local_data['Author'];
1807
+ $view_vars = array( 'plugin' => $selected_addon );
1808
+ $data->sections = array(
1809
+ 'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
1810
+ );
1811
+
1812
+ if ( ! empty( $selected_addon->info->banner_url ) ) {
1813
+ $data->banners = array(
1814
+ 'low' => $selected_addon->info->banner_url,
1815
+ );
1816
+ }
1817
+
1818
+ if ( ! empty( $selected_addon->info->screenshots ) ) {
1819
+ $view_vars = array( 'screenshots' => $selected_addon->info->screenshots );
1820
+ $data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
1821
+ }
1822
+
1823
+ // Load add-on pricing.
1824
+ $has_pricing = false;
1825
+ $has_features = false;
1826
+ $plans = false;
1827
+ $plans_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans.json" );
1828
+ if ( ! isset( $plans_result->error ) ) {
1829
+ $plans = $plans_result->plans;
1830
+ if ( is_array( $plans ) ) {
1831
+ foreach ( $plans as &$plan ) {
1832
+ $pricing_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/pricing.json" );
1833
+ if ( ! isset( $pricing_result->error ) ) {
1834
+ // Update plan's pricing.
1835
+ $plan->pricing = $pricing_result->pricing;
1836
+
1837
+ $has_pricing = true;
1838
+ }
1839
+
1840
+ $features_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/features.json" );
1841
+ if ( ! isset( $features_result->error ) &&
1842
+ is_array( $features_result->features ) &&
1843
+ 0 < count( $features_result->features )
1844
+ ) {
1845
+ // Update plan's pricing.
1846
+ $plan->features = $features_result->features;
1847
+
1848
+ $has_features = true;
1849
+ }
1850
+ }
1851
+ }
1852
+ }
1853
+
1854
+ // Get latest add-on version.
1855
+ $latest = $this->_fetch_latest_version( $selected_addon->id );
1856
+
1857
+ if ( is_object( $latest ) ) {
1858
+ $data->version = $latest->version;
1859
+ $data->last_updated = ! is_null( $latest->updated ) ? $latest->updated : $latest->created;
1860
+ $data->requires = $latest->requires_platform_version;
1861
+ $data->tested = $latest->tested_up_to_version;
1862
+ } else {
1863
+ // Add dummy version.
1864
+ $data->version = '1.0.0';
1865
+
1866
+ // Add message to developer to deploy the plugin through Freemius.
1867
+ }
1868
+
1869
+ $data->checkout_link = $this->checkout_url();
1870
+ $data->download_link = 'https://dummy.com';
1871
+
1872
+ if ( $has_pricing ) {
1873
+ // Add plans to data.
1874
+ $data->plans = $plans;
1875
+
1876
+ if ( $has_features ) {
1877
+ $view_vars = array( 'plans' => $plans );
1878
+ $data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
1879
+ }
1880
+ }
1881
+
1882
+ return $data;
1883
+ }
1884
+
1885
+ /**
1886
+ * Check if add-on installed and activated on site.
1887
+ *
1888
+ * @author Vova Feldman (@svovaf)
1889
+ * @since 1.0.6
1890
+ *
1891
+ * @param string|number $slug_or_id
1892
+ *
1893
+ * @return bool
1894
+ */
1895
+ function is_addon_activated( $slug_or_id ) {
1896
+ return self::has_instance( $slug_or_id );
1897
+ }
1898
+
1899
+ /**
1900
+ * Determines if add-on installed.
1901
+ *
1902
+ * NOTE: This is a heuristic and only works if the folder/file named as the slug.
1903
+ *
1904
+ * @author Vova Feldman (@svovaf)
1905
+ * @since 1.0.6
1906
+ *
1907
+ * @param string $slug
1908
+ *
1909
+ * @return bool
1910
+ */
1911
+ function is_addon_installed( $slug ) {
1912
+ return file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this->get_addon_basename( $slug ) ) );
1913
+ }
1914
+
1915
+ /**
1916
+ * Get add-on basename.
1917
+ *
1918
+ * @author Vova Feldman (@svovaf)
1919
+ * @since 1.0.6
1920
+ *
1921
+ * @param string $slug
1922
+ *
1923
+ * @return string
1924
+ */
1925
+ function get_addon_basename( $slug ) {
1926
+ if ( $this->is_addon_activated( $slug ) ) {
1927
+ self::instance( $slug )->get_plugin_basename();
1928
+ }
1929
+
1930
+ return $slug . '/' . $slug . '.php';
1931
+ }
1932
+
1933
+ /**
1934
+ * Get installed add-ons instances.
1935
+ *
1936
+ * @author Vova Feldman (@svovaf)
1937
+ * @since 1.0.6
1938
+ *
1939
+ * @return Freemius[]
1940
+ */
1941
+ function get_installed_addons() {
1942
+ $installed_addons = array();
1943
+ foreach ( self::$_instances as $slug => $instance ) {
1944
+ if ( $instance->is_addon() && is_object( $instance->_parent_plugin ) ) {
1945
+ if ( $this->_plugin->id == $instance->_parent_plugin->id ) {
1946
+ $installed_addons[] = $instance;
1947
+ }
1948
+ }
1949
+ }
1950
+
1951
+ return $installed_addons;
1952
+ }
1953
+
1954
+ /**
1955
+ * Check if any add-ons of the plugin are installed.
1956
+ *
1957
+ * @author Leo Fajardo (@leorw)
1958
+ * @since 1.1.1
1959
+ *
1960
+ * @return bool
1961
+ */
1962
+ function has_installed_addons() {
1963
+ if ( ! $this->_has_addons() ) {
1964
+ return false;
1965
+ }
1966
+
1967
+ foreach ( self::$_instances as $slug => $instance ) {
1968
+ if ( $instance->is_addon() && is_object( $instance->_parent_plugin ) ) {
1969
+ if ( $this->_plugin->id == $instance->_parent_plugin->id ) {
1970
+ return true;
1971
+ }
1972
+ }
1973
+ }
1974
+
1975
+ return false;
1976
+ }
1977
+
1978
+ /**
1979
+ * Tell Freemius that the current plugin is an add-on.
1980
+ *
1981
+ * @author Vova Feldman (@svovaf)
1982
+ * @since 1.0.6
1983
+ *
1984
+ * @param number $parent_plugin_id The parent plugin ID
1985
+ */
1986
+ function init_addon( $parent_plugin_id ) {
1987
+ $this->_plugin->parent_plugin_id = $parent_plugin_id;
1988
+ }
1989
+
1990
+ /**
1991
+ * @author Vova Feldman (@svovaf)
1992
+ * @since 1.0.6
1993
+ *
1994
+ * @return bool
1995
+ */
1996
+ function is_addon() {
1997
+ return isset( $this->_plugin->parent_plugin_id ) && is_numeric( $this->_plugin->parent_plugin_id );
1998
+ }
1999
+
2000
+ #endregion ------------------------------------------------------------------
2001
+
2002
+ #region Sandbox ------------------------------------------------------------------
2003
+
2004
+ /**
2005
+ * Set Freemius into sandbox mode for debugging.
2006
+ *
2007
+ * @author Vova Feldman (@svovaf)
2008
+ * @since 1.0.4
2009
+ *
2010
+ * @param string $secret_key
2011
+ */
2012
+ function init_sandbox( $secret_key ) {
2013
+ $this->_plugin->secret_key = $secret_key;
2014
+
2015
+ // Update plugin details.
2016
+ FS_Plugin_Manager::instance( $this->_slug )->update( $this->_plugin, true );
2017
+ }
2018
+
2019
+ /**
2020
+ * Check if running payments in sandbox mode.
2021
+ *
2022
+ * @author Vova Feldman (@svovaf)
2023
+ * @since 1.0.4
2024
+ *
2025
+ * @return bool
2026
+ */
2027
+ function is_payments_sandbox() {
2028
+ return ( ! $this->is_live() ) || isset( $this->_plugin->secret_key );
2029
+ }
2030
+
2031
+ #endregion Sandbox ------------------------------------------------------------------
2032
+
2033
+ /**
2034
+ * Check if running test vs. live plugin.
2035
+ *
2036
+ * @author Vova Feldman (@svovaf)
2037
+ * @since 1.0.5
2038
+ *
2039
+ * @return bool
2040
+ */
2041
+ function is_live() {
2042
+ return $this->_plugin->is_live;
2043
+ }
2044
+
2045
+ /**
2046
+ * Check if the user skipped connecting the account with Freemius.
2047
+ *
2048
+ * @author Vova Feldman (@svovaf)
2049
+ * @since 1.0.7
2050
+ *
2051
+ * @return bool
2052
+ */
2053
+ function is_anonymous() {
2054
+ if ( ! isset( $this->_is_anonymous ) ) {
2055
+ if ( ! isset( $this->_storage->is_anonymous ) ) {
2056
+ // Not skipped.
2057
+ $this->_is_anonymous = false;
2058
+ } else if ( is_bool( $this->_storage->is_anonymous ) ) {
2059
+ // For back compatibility, since the variable was boolean before.
2060
+ $this->_is_anonymous = $this->_storage->is_anonymous;
2061
+
2062
+ // Upgrade stored data format to 1.1.3 format.
2063
+ $this->set_anonymous_mode( $this->_storage->is_anonymous );
2064
+ } else {
2065
+ // Version 1.1.3 and higher.
2066
+ $this->_is_anonymous = $this->_storage->is_anonymous['is'];
2067
+ }
2068
+ }
2069
+
2070
+ return $this->_is_anonymous;
2071
+ }
2072
+
2073
+ /**
2074
+ * Check if user connected his account and install pending email activation.
2075
+ *
2076
+ * @author Vova Feldman (@svovaf)
2077
+ * @since 1.0.7
2078
+ *
2079
+ * @return bool
2080
+ */
2081
+ function is_pending_activation() {
2082
+ return $this->_storage->get( 'is_pending_activation', false );
2083
+ }
2084
+
2085
+ /**
2086
+ * Check if plugin must be WordPress.org compliant.
2087
+ *
2088
+ * @since 1.0.7
2089
+ *
2090
+ * @return bool
2091
+ */
2092
+ function is_org_repo_compliant() {
2093
+ return $this->_is_org_compliant;
2094
+ }
2095
+
2096
+ /**
2097
+ * Background sync every 24 hours.
2098
+ *
2099
+ * @author Vova Feldman (@svovaf)
2100
+ * @since 1.0.4
2101
+ *
2102
+ * @return bool If function actually executed the sync in this iteration.
2103
+ */
2104
+ private function _background_sync() {
2105
+ $this->_logger->entrance();
2106
+
2107
+ // Don't sync license on AJAX calls.
2108
+ if ( $this->is_ajax() ) {
2109
+ return false;
2110
+ }
2111
+
2112
+ // Asked to sync explicitly, no need for background sync.
2113
+ if ( fs_request_is_action( $this->_slug . '_sync_license' ) ) {
2114
+ return false;
2115
+ }
2116
+
2117
+ $sync_timestamp = $this->_storage->get( 'sync_timestamp' );
2118
+
2119
+ if ( ! is_numeric( $sync_timestamp ) || $sync_timestamp >= time() ) {
2120
+ // If updated not set or happens to be in the future, set as if was 24 hours earlier.
2121
+ $sync_timestamp = time() - WP_FS__TIME_24_HOURS_IN_SEC;
2122
+ $this->_storage->sync_timestamp = $sync_timestamp;
2123
+ }
2124
+
2125
+ if ( ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE && fs_request_has( 'background_sync' ) ) ||
2126
+ ( $sync_timestamp <= time() - WP_FS__TIME_24_HOURS_IN_SEC )
2127
+ ) {
2128
+
2129
+ if ( $this->is_registered() ) {
2130
+ // Initiate background plan sync.
2131
+ $this->_sync_license( true );
2132
+
2133
+ // Check for plugin updates.
2134
+ $this->_check_updates( true );
2135
+ }
2136
+
2137
+ if ( ! $this->is_addon() ) {
2138
+ if ( $this->is_registered() || $this->_has_addons ) {
2139
+ // Try to fetch add-ons if registered or if plugin
2140
+ // declared that it has add-ons.
2141
+ $this->_sync_addons();
2142
+ }
2143
+ }
2144
+
2145
+ // Update last sync timestamp.
2146
+ $this->_storage->sync_timestamp = time();
2147
+
2148
+ return true;
2149
+ }
2150
+
2151
+ return false;
2152
+ }
2153
+
2154
+ /**
2155
+ * Show a notice that activation is currently pending.
2156
+ *
2157
+ * @author Vova Feldman (@svovaf)
2158
+ * @since 1.0.7
2159
+ *
2160
+ * @param bool|string $email
2161
+ */
2162
+ function _add_pending_activation_notice( $email = false ) {
2163
+ if ( ! is_string( $email ) ) {
2164
+ $current_user = wp_get_current_user();
2165
+ $email = $current_user->user_email;
2166
+ }
2167
+
2168
+ $this->_admin_notices->add_sticky(
2169
+ sprintf(
2170
+ __fs( 'pending-activation-message' ),
2171
+ '<b>' . $this->get_plugin_name() . '</b>',
2172
+ '<b>' . $email . '</b>'
2173
+ ),
2174
+ 'activation_pending',
2175
+ 'Thanks!'
2176
+ );
2177
+ }
2178
+
2179
+ /**
2180
+ * Check if currently in plugin activation.
2181
+ *
2182
+ * @author Vova Feldman (@svovaf)
2183
+ * @since 1.1.4
2184
+ *
2185
+ * @return bool
2186
+ */
2187
+ function is_plugin_activation() {
2188
+ return get_option( "fs_{$this->_slug}_activated", false );
2189
+ }
2190
+
2191
+ /**
2192
+ *
2193
+ * NOTE: admin_menu action executed before admin_init.
2194
+ *
2195
+ * @author Vova Feldman (@svovaf)
2196
+ * @since 1.0.7
2197
+ */
2198
+ function _admin_init_action() {
2199
+ // Automatically redirect to connect/activation page after plugin activation.
2200
+ if ( $this->is_plugin_activation() ) {
2201
+ delete_option( "fs_{$this->_slug}_activated" );
2202
+ $this->_redirect_on_activation_hook();
2203
+
2204
+ return;
2205
+ }
2206
+
2207
+ if ( fs_request_is_action( $this->_slug . '_skip_activation' ) ) {
2208
+ check_admin_referer( $this->_slug . '_skip_activation' );
2209
+
2210
+ $this->skip_connection();
2211
+
2212
+ if ( fs_redirect( $this->get_after_activation_url( 'after_skip_url' ) ) ) {
2213
+ exit();
2214
+ }
2215
+ }
2216
+
2217
+ if ( ! $this->is_addon() && ! $this->is_registered() && ! $this->is_anonymous() ) {
2218
+ if ( ! $this->is_pending_activation() ) {
2219
+ if ( ! $this->_menu->is_activation_page() ) {
2220
+ if ( $this->is_plugin_new_install() ) {
2221
+ // Show notice for new plugin installations.
2222
+ $this->_admin_notices->add(
2223
+ sprintf(
2224
+ __fs( 'you-are-step-away' ),
2225
+ sprintf( '<b><a href="%s">%s</a></b>',
2226
+ $this->get_activation_url(),
2227
+ sprintf( __fs( 'activate-x-now' ), $this->get_plugin_name() )
2228
+ )
2229
+ ),
2230
+ '',
2231
+ 'update-nag'
2232
+ );
2233
+ } else {
2234
+ if ( ! isset( $this->_storage->sticky_optin_added ) ) {
2235
+ $this->_storage->sticky_optin_added = true;
2236
+
2237
+ // Show notice for new plugin installations.
2238
+ $this->_admin_notices->add_sticky(
2239
+ sprintf(
2240
+ __fs( 'few-plugin-tweaks' ),
2241
+ sprintf( '<b><a href="%s">%s</a></b>',
2242
+ $this->get_activation_url(),
2243
+ sprintf( __fs( 'optin-x-now' ), $this->get_plugin_name() )
2244
+ )
2245
+ ),
2246
+ 'connect_account',
2247
+ '',
2248
+ 'update-nag'
2249
+ );
2250
+ }
2251
+
2252
+ if ( $this->has_filter( 'optin_pointer_element' ) ) {
2253
+ // Don't show admin nag if plugin update.
2254
+ wp_enqueue_script( 'wp-pointer' );
2255
+ wp_enqueue_style( 'wp-pointer' );
2256
+
2257
+ $this->_enqueue_connect_essentials();
2258
+
2259
+ add_action( 'admin_print_footer_scripts', array(
2260
+ $this,
2261
+ '_add_connect_pointer_script'
2262
+ ) );
2263
+ }
2264
+
2265
+ }
2266
+ }
2267
+ }
2268
+ }
2269
+
2270
+ $this->_add_upgrade_action_link();
2271
+ }
2272
+
2273
+ /**
2274
+ * Enqueue connect requires scripts and styles.
2275
+ *
2276
+ * @author Vova Feldman (@svovaf)
2277
+ * @since 1.1.4
2278
+ */
2279
+ function _enqueue_connect_essentials() {
2280
+ wp_enqueue_script( 'jquery' );
2281
+ wp_enqueue_script( 'json2' );
2282
+
2283
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
2284
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
2285
+
2286
+ fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
2287
+ }
2288
+
2289
+ /**
2290
+ * Add connect / opt-in pointer.
2291
+ *
2292
+ * @author Vova Feldman (@svovaf)
2293
+ * @since 1.1.4
2294
+ */
2295
+ function _add_connect_pointer_script() {
2296
+ $vars = array( 'slug' => $this->_slug );
2297
+ $pointer_content = fs_get_template(
2298
+ $this->is_pending_activation() ?
2299
+ 'pending-activation.php' :
2300
+ 'connect.php',
2301
+ $vars
2302
+ );
2303
+ ?>
2304
+ <script type="text/javascript">// <![CDATA[
2305
+ jQuery(document).ready(function ($) {
2306
+ if ('undefined' !== typeof(jQuery().pointer)) {
2307
+
2308
+ var element = <?php echo $this->apply_filters('optin_pointer_element', '$("#non_existing_element");') ?>;
2309
+
2310
+ if (element.length > 0) {
2311
+ var optin = $(element).pointer($.extend(true, {}, {
2312
+ content : <?php echo json_encode($pointer_content) ?>,
2313
+ position : {
2314
+ edge : 'left',
2315
+ align: 'center'
2316
+ },
2317
+ buttons : function () {
2318
+ // Don't show pointer buttons.
2319
+ return '';
2320
+ },
2321
+ pointerWidth: 482
2322
+ }, <?php echo $this->apply_filters('optin_pointer_options_json', '{}') ?>));
2323
+
2324
+ <?php
2325
+ echo $this->apply_filters('optin_pointer_execute', "
2326
+
2327
+ optin.pointer('open');
2328
+
2329
+ // Tag the opt-in pointer with custom class.
2330
+ $('.wp-pointer #fs_connect')
2331
+ .parents('.wp-pointer.wp-pointer-top')
2332
+ .addClass('fs-opt-in-pointer');
2333
+
2334
+ ", 'element', 'optin') ?>
2335
+ }
2336
+ }
2337
+ });
2338
+ // ]]></script>
2339
+ <?php
2340
+ }
2341
+
2342
+ /**
2343
+ * Return current page's URL.
2344
+ *
2345
+ * @author Vova Feldman (@svovaf)
2346
+ * @since 1.0.7
2347
+ *
2348
+ * @return string
2349
+ */
2350
+ function current_page_url() {
2351
+ $url = 'http';
2352
+
2353
+ if ( isset( $_SERVER["HTTPS"] ) ) {
2354
+ if ( $_SERVER["HTTPS"] == "on" ) {
2355
+ $url .= "s";
2356
+ }
2357
+ }
2358
+ $url .= "://";
2359
+ if ( $_SERVER["SERVER_PORT"] != "80" ) {
2360
+ $url .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
2361
+ } else {
2362
+ $url .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
2363
+ }
2364
+
2365
+ return esc_url( $url );
2366
+ }
2367
+
2368
+ /**
2369
+ * Check if the current page is the plugin's main admin settings page.
2370
+ *
2371
+ * @author Vova Feldman (@svovaf)
2372
+ * @since 1.0.7
2373
+ *
2374
+ * @return bool
2375
+ */
2376
+ function _is_plugin_page() {
2377
+ return fs_is_plugin_page( $this->_menu->get_raw_slug() ) ||
2378
+ fs_is_plugin_page( $this->_slug );
2379
+ }
2380
+
2381
+ /* Events
2382
+ ------------------------------------------------------------------------------------------------------------------*/
2383
+ /**
2384
+ * Delete site install from Database.
2385
+ *
2386
+ * @author Vova Feldman (@svovaf)
2387
+ * @since 1.0.1
2388
+ *
2389
+ * @param bool $store
2390
+ */
2391
+ function _delete_site( $store = true ) {
2392
+ $sites = self::get_all_sites();
2393
+
2394
+ if ( isset( $sites[ $this->_slug ] ) ) {
2395
+ unset( $sites[ $this->_slug ] );
2396
+ }
2397
+
2398
+ self::$_accounts->set_option( 'sites', $sites, $store );
2399
+ }
2400
+
2401
+ /**
2402
+ * Delete plugin's plans information.
2403
+ *
2404
+ * @param bool $store Flush to Database if true.
2405
+ *
2406
+ * @author Vova Feldman (@svovaf)
2407
+ * @since 1.0.9
2408
+ */
2409
+ private function _delete_plans( $store = true ) {
2410
+ $this->_logger->entrance();
2411
+
2412
+ $plans = self::get_all_plans();
2413
+
2414
+ unset( $plans[ $this->_slug ] );
2415
+
2416
+ self::$_accounts->set_option( 'plans', $plans, $store );
2417
+ }
2418
+
2419
+ /**
2420
+ * Delete all plugin licenses.
2421
+ *
2422
+ * @author Vova Feldman (@svovaf)
2423
+ * @since 1.0.9
2424
+ *
2425
+ * @param bool $store
2426
+ * @param string|bool $plugin_slug
2427
+ */
2428
+ private function _delete_licenses( $store = true, $plugin_slug = false ) {
2429
+ $this->_logger->entrance();
2430
+
2431
+ $all_licenses = self::get_all_licenses();
2432
+
2433
+ if ( ! is_string( $plugin_slug ) ) {
2434
+ $plugin_slug = $this->_slug;
2435
+ }
2436
+
2437
+ unset( $all_licenses[ $plugin_slug ] );
2438
+
2439
+ self::$_accounts->set_option( 'licenses', $all_licenses, $store );
2440
+ }
2441
+
2442
+ /**
2443
+ * @author Vova Feldman (@svovaf)
2444
+ * @since 1.1.5
2445
+ *
2446
+ * @return bool
2447
+ */
2448
+ private function is_plugin_new_install()
2449
+ {
2450
+ return isset($this->_storage->is_plugin_new_install) &&
2451
+ $this->_storage->is_plugin_new_install;
2452
+ }
2453
+
2454
+ /**
2455
+ * Plugin activated hook.
2456
+ *
2457
+ * @author Vova Feldman (@svovaf)
2458
+ * @since 1.0.1
2459
+ *
2460
+ * @uses FS_Api
2461
+ */
2462
+ function _activate_plugin_event_hook() {
2463
+ $this->_logger->entrance( 'slug = ' . $this->_slug );
2464
+
2465
+ if ( ! current_user_can( 'activate_plugins' ) ) {
2466
+ return;
2467
+ }
2468
+
2469
+ // Clear API cache on activation.
2470
+ FS_Api::clear_cache();
2471
+
2472
+ if ( $this->is_registered() ) {
2473
+ // Send re-activation event and sync.
2474
+ $this->sync_install( array(), true );
2475
+
2476
+ /**
2477
+ * @todo Work on automatic deactivation of the Free plugin version. It doesn't work since the slug of the free & premium versions is identical. Therefore, only one instance of Freemius is created and the activation hook of the premium version is not being added.
2478
+ */
2479
+ if ( $this->_plugin_basename !== $this->_free_plugin_basename ) {
2480
+ // Deactivate Free plugin version on premium plugin activation.
2481
+ deactivate_plugins( $this->_free_plugin_basename );
2482
+
2483
+ $this->_admin_notices->add(
2484
+ sprintf( __fs( 'successful-version-upgrade-message' ), sprintf( '<b>%s</b>', $this->_plugin->title ) ),
2485
+ __fs( 'woot' ) . '!'
2486
+ );
2487
+ }
2488
+ } else if ( $this->is_anonymous() ) {
2489
+ /**
2490
+ * Reset "skipped" click cache on the following:
2491
+ * 1. Development mode.
2492
+ * 2. If the user skipped the exact same version before.
2493
+ *
2494
+ * @todo 3. If explicitly asked to retry after every activation.
2495
+ */
2496
+ if ( WP_FS__DEV_MODE ||
2497
+ $this->get_plugin_version() == $this->_storage->is_anonymous['version']
2498
+ ) {
2499
+ $this->reset_anonymous_mode();
2500
+ }
2501
+ }
2502
+
2503
+ if ( ! isset( $this->_storage->is_plugin_new_install ) ) {
2504
+ /**
2505
+ * If no previous version of plugin's version exist, it means that it's either
2506
+ * the first time that the plugin installed on the site, or the plugin was installed
2507
+ * before but didn't have Freemius integrated.
2508
+ *
2509
+ * Since register_activation_hook() do NOT fires since 3.1, and only fires
2510
+ * on manual activation via the dashboard, is_plugin_activation() is TRUE
2511
+ * only after immediate activation.
2512
+ *
2513
+ * @since 1.1.4
2514
+ * @link https://make.wordpress.org/core/2010/10/27/plugin-activation-hooks-no-longer-fire-for-updates/
2515
+ */
2516
+ $this->_storage->is_plugin_new_install = empty( $this->_storage->plugin_last_version );
2517
+ }
2518
+
2519
+ if ( $this->has_api_connectivity(true) ) {
2520
+ // Store hint that the plugin was just activated to enable auto-redirection to settings.
2521
+ add_option( "fs_{$this->_slug}_activated", true );
2522
+ }
2523
+ }
2524
+
2525
+ /**
2526
+ * Delete account.
2527
+ *
2528
+ * @author Vova Feldman (@svovaf)
2529
+ * @since 1.0.3
2530
+ *
2531
+ * @param bool $check_user Enforce checking if user have plugins activation privileges.
2532
+ */
2533
+ function delete_account_event( $check_user = true ) {
2534
+ $this->_logger->entrance( 'slug = ' . $this->_slug );
2535
+
2536
+ if ( $check_user && ! current_user_can( 'activate_plugins' ) ) {
2537
+ return;
2538
+ }
2539
+
2540
+ $this->do_action( 'before_account_delete' );
2541
+
2542
+ // Clear all admin notices.
2543
+ $this->_admin_notices->clear_all_sticky();
2544
+
2545
+ $this->_delete_site( false );
2546
+
2547
+ $this->_delete_plans( false );
2548
+
2549
+ $this->_delete_licenses( false );
2550
+
2551
+ // Delete add-ons related to plugin's account.
2552
+ $this->_delete_account_addons( false );
2553
+
2554
+ // @todo Delete plans and licenses of add-ons.
2555
+
2556
+ self::$_accounts->store();
2557
+
2558
+ // Clear all storage data.
2559
+ $this->_storage->clear_all( true, array(
2560
+ 'connectivity_test',
2561
+ 'is_on',
2562
+ ) );
2563
+
2564
+ // Send delete event.
2565
+ $this->get_api_site_scope()->call( '/', 'delete' );
2566
+
2567
+ $this->do_action( 'after_account_delete' );
2568
+ }
2569
+
2570
+ /**
2571
+ * Plugin deactivation hook.
2572
+ *
2573
+ * @author Vova Feldman (@svovaf)
2574
+ * @since 1.0.1
2575
+ */
2576
+ function _deactivate_plugin_hook() {
2577
+ $this->_logger->entrance( 'slug = ' . $this->_slug );
2578
+
2579
+ if ( ! current_user_can( 'activate_plugins' ) ) {
2580
+ return;
2581
+ }
2582
+
2583
+ $this->_admin_notices->clear_all_sticky();
2584
+
2585
+ if ( ! $this->has_api_connectivity() ) {
2586
+ // Reset connectivity test cache.
2587
+ unset( $this->_storage->connectivity_test );
2588
+ }
2589
+
2590
+ if (!isset($this->_storage->is_plugin_new_install)) {
2591
+ // Remember that plugin was already installed.
2592
+ $this->_storage->is_plugin_new_install = false;
2593
+ }
2594
+
2595
+ if ( $this->is_registered() ) {
2596
+ // Send deactivation event.
2597
+ $this->sync_install( array(
2598
+ 'is_active' => false,
2599
+ ) );
2600
+ }
2601
+
2602
+ // Clear API cache on deactivation.
2603
+ FS_Api::clear_cache();
2604
+ }
2605
+
2606
+ /**
2607
+ * @author Vova Feldman (@svovaf)
2608
+ * @since 1.1.3
2609
+ *
2610
+ * @param bool $is_anonymous
2611
+ */
2612
+ private function set_anonymous_mode( $is_anonymous = true ) {
2613
+ // Store information regarding skip to try and opt-in the user
2614
+ // again in the future.
2615
+ $this->_storage->is_anonymous = array(
2616
+ 'is' => $is_anonymous,
2617
+ 'timestamp' => WP_FS__SCRIPT_START_TIME,
2618
+ 'version' => $this->get_plugin_version(),
2619
+ );
2620
+ }
2621
+
2622
+ /**
2623
+ * @author Vova Feldman (@svovaf)
2624
+ * @since 1.1.3
2625
+ */
2626
+ private function reset_anonymous_mode() {
2627
+ unset( $this->_storage->is_anonymous );
2628
+ }
2629
+
2630
+ /**
2631
+ * Skip account connect, and set anonymous mode.
2632
+ *
2633
+ * @author Vova Feldman (@svovaf)
2634
+ * @since 1.1.1
2635
+ */
2636
+ private function skip_connection() {
2637
+ $this->_logger->entrance();
2638
+
2639
+ $this->_admin_notices->remove_sticky( 'connect_account' );
2640
+
2641
+ $this->set_anonymous_mode();
2642
+
2643
+ // Send anonymous skip event.
2644
+ // No user identified info nor any tracking will be sent after the user skips the opt-in.
2645
+ $this->get_api_plugin_scope()->call( 'skip.json', 'put', array(
2646
+ 'uid' => $this->get_anonymous_id(),
2647
+ ) );
2648
+ }
2649
+
2650
+ /**
2651
+ * Plugin version update hook.
2652
+ *
2653
+ * @author Vova Feldman (@svovaf)
2654
+ * @since 1.0.4
2655
+ */
2656
+ private function update_plugin_version_event() {
2657
+ $this->_logger->entrance( 'slug = ' . $this->_slug );
2658
+
2659
+ $this->_site->version = $this->get_plugin_version();
2660
+
2661
+ // Send update event.
2662
+ $site = $this->send_install_update( array(), true );
2663
+
2664
+ if ( false !== $site && ! $this->is_api_error( $site ) ) {
2665
+ $this->_site = new FS_Site( $site );
2666
+ $this->_site->plan = $this->_get_plan_by_id( $site->plan_id );
2667
+ $this->_store_site( true );
2668
+ }
2669
+ }
2670
+
2671
+ /**
2672
+ * Update install details.
2673
+ *
2674
+ * @author Vova Feldman (@svovaf)
2675
+ * @since 1.1.2
2676
+ *
2677
+ * @param string[] string $override
2678
+ *
2679
+ * @return array
2680
+ */
2681
+ private function get_install_data_for_api( $override = array() ) {
2682
+ return array_merge( array(
2683
+ 'version' => $this->get_plugin_version(),
2684
+ 'is_premium' => $this->is_premium(),
2685
+ 'language' => get_bloginfo( 'language' ),
2686
+ 'charset' => get_bloginfo( 'charset' ),
2687
+ 'platform_version' => get_bloginfo( 'version' ),
2688
+ 'programming_language_version' => phpversion(),
2689
+ 'title' => get_bloginfo( 'name' ),
2690
+ 'url' => get_site_url(),
2691
+ // Special params.
2692
+ 'is_active' => true,
2693
+ 'is_uninstalled' => false,
2694
+ ), $override );
2695
+ }
2696
+
2697
+ /**
2698
+ * Update install only if changed.
2699
+ *
2700
+ * @author Vova Feldman (@svovaf)
2701
+ * @since 1.0.9
2702
+ *
2703
+ * @param string[] string $override
2704
+ * @param bool $flush
2705
+ *
2706
+ * @return false|object|string
2707
+ */
2708
+ private function send_install_update( $override = array(), $flush = false ) {
2709
+ $this->_logger->entrance();
2710
+
2711
+ $check_properties = $this->get_install_data_for_api( $override );
2712
+
2713
+ if ( $flush ) {
2714
+ $params = $check_properties;
2715
+ } else {
2716
+ $params = array();
2717
+ $special = array();
2718
+ $special_override = false;
2719
+
2720
+ foreach ( $check_properties as $p => $v ) {
2721
+ if ( property_exists( $this->_site, $p ) ) {
2722
+ if ( ! empty( $this->_site->{$p} ) &&
2723
+ $this->_site->{$p} != $v
2724
+ ) {
2725
+ $this->_site->{$p} = $v;
2726
+ $params[ $p ] = $v;
2727
+ }
2728
+ } else {
2729
+ $special[ $p ] = $v;
2730
+
2731
+ if ( isset( $override[ $p ] ) ) {
2732
+ $special_override = true;
2733
+ }
2734
+ }
2735
+ }
2736
+
2737
+ if ( $special_override || 0 < count( $params ) ) {
2738
+ // Add special params only if has at least one
2739
+ // standard param, or if explicitly requested to
2740
+ // override a special param or a pram which is not exist
2741
+ // in the install object.
2742
+ $params = array_merge( $params, $special );
2743
+ }
2744
+ }
2745
+
2746
+ if ( 0 < count( $params ) ) {
2747
+ // Send updated values to FS.
2748
+ return $this->get_api_site_scope()->call( '/', 'put', $params );
2749
+ }
2750
+
2751
+ return false;
2752
+ }
2753
+
2754
+ /**
2755
+ * Update install only if changed.
2756
+ *
2757
+ * @author Vova Feldman (@svovaf)
2758
+ * @since 1.0.9
2759
+ *
2760
+ * @param string[] string $override
2761
+ * @param bool $flush
2762
+ *
2763
+ * @return false|object|string
2764
+ */
2765
+ private function sync_install( $override = array(), $flush = false ) {
2766
+ $this->_logger->entrance();
2767
+
2768
+ $site = $this->send_install_update( $override, $flush );
2769
+
2770
+ if ( false === $site ) {
2771
+ // No sync required.
2772
+ return;
2773
+ }
2774
+
2775
+ if ( $this->is_api_error( $site ) ) {
2776
+ // Failed to sync, don't update locally.
2777
+ return;
2778
+ }
2779
+
2780
+ $plan = $this->get_plan();
2781
+ $this->_site = new FS_Site( $site );
2782
+ $this->_site->plan = $plan;
2783
+
2784
+ $this->_store_site( true );
2785
+ }
2786
+
2787
+ /**
2788
+ * Plugin uninstall hook.
2789
+ *
2790
+ * @author Vova Feldman (@svovaf)
2791
+ * @since 1.0.1
2792
+ *
2793
+ * @param bool $check_user Enforce checking if user have plugins activation privileges.
2794
+ */
2795
+ function _uninstall_plugin_event( $check_user = true ) {
2796
+ $this->_logger->entrance( 'slug = ' . $this->_slug );
2797
+
2798
+ if ( $check_user && ! current_user_can( 'activate_plugins' ) ) {
2799
+ return;
2800
+ }
2801
+
2802
+ $params = array();
2803
+ if ( isset( $this->_storage->uninstall_reason ) ) {
2804
+ $params['reason_id'] = $this->_storage->uninstall_reason->id;
2805
+ $params['reason_info'] = $this->_storage->uninstall_reason->info;
2806
+ }
2807
+
2808
+ if ( ! $this->is_registered() && isset( $this->_storage->uninstall_reason ) ) {
2809
+ // Send anonymous uninstall event only if user submitted a feedback.
2810
+ $params['uid'] = $this->get_anonymous_id();
2811
+ $this->get_api_plugin_scope()->call( 'uninstall.json', 'put', $params );
2812
+ } else {
2813
+ // Send uninstall event.
2814
+ $this->send_install_update( array_merge( $params, array(
2815
+ 'is_active' => false,
2816
+ 'is_uninstalled' => true,
2817
+ ) ) );
2818
+ }
2819
+
2820
+ // @todo Decide if we want to delete plugin information from db.
2821
+ }
2822
+
2823
+ /**
2824
+ * @author Vova Feldman (@svovaf)
2825
+ * @since 1.1.1
2826
+ *
2827
+ * @return string
2828
+ */
2829
+ private function premium_plugin_basename() {
2830
+ return preg_replace( '/\//', '-premium/', $this->_free_plugin_basename, 1 );
2831
+ }
2832
+
2833
+ /**
2834
+ * Uninstall plugin hook. Called only when connected his account with Freemius for active sites tracking.
2835
+ *
2836
+ * @author Vova Feldman (@svovaf)
2837
+ * @since 1.0.2
2838
+ */
2839
+ public static function _uninstall_plugin_hook() {
2840
+ self::_load_required_static();
2841
+
2842
+ self::$_static_logger->entrance();
2843
+
2844
+ if ( ! current_user_can( 'activate_plugins' ) ) {
2845
+ return;
2846
+ }
2847
+
2848
+ $plugin_file = substr( current_filter(), strlen( 'uninstall_' ) );
2849
+
2850
+ self::$_static_logger->info( 'plugin = ' . $plugin_file );
2851
+
2852
+ define( 'WP_FS__UNINSTALL_MODE', true );
2853
+
2854
+ $fs = self::get_instance_by_file( $plugin_file );
2855
+
2856
+ if ( is_object( $fs ) ) {
2857
+ self::require_plugin_essentials();
2858
+
2859
+ if ( is_plugin_active( $fs->_free_plugin_basename ) ||
2860
+ is_plugin_active( $fs->premium_plugin_basename() )
2861
+ ) {
2862
+ // Deleting Free or Premium plugin version while the other version still installed.
2863
+ return;
2864
+ }
2865
+
2866
+ $fs->_uninstall_plugin_event();
2867
+
2868
+ $fs->do_action( 'after_uninstall' );
2869
+ }
2870
+ }
2871
+
2872
+ #region Plugin Information ------------------------------------------------------------------
2873
+
2874
+ /**
2875
+ * Load WordPress core plugin.php essential module.
2876
+ *
2877
+ * @author Vova Feldman (@svovaf)
2878
+ * @since 1.1.1
2879
+ */
2880
+ private static function require_plugin_essentials() {
2881
+ if ( ! function_exists( 'get_plugins' ) ) {
2882
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
2883
+ }
2884
+ }
2885
+
2886
+ /**
2887
+ * Load WordPress core pluggable.php module.
2888
+ *
2889
+ * @author Vova Feldman (@svovaf)
2890
+ * @since 1.1.2
2891
+ */
2892
+ private static function require_pluggable_essentials() {
2893
+ if ( ! function_exists( 'wp_get_current_user' ) ) {
2894
+ require_once( ABSPATH . 'wp-includes/pluggable.php' );
2895
+ }
2896
+ }
2897
+
2898
+ /**
2899
+ * Return plugin data.
2900
+ *
2901
+ * @author Vova Feldman (@svovaf)
2902
+ * @since 1.0.1
2903
+ *
2904
+ * @return array
2905
+ */
2906
+ function get_plugin_data() {
2907
+ if ( ! isset( $this->_plugin_data ) ) {
2908
+ self::require_plugin_essentials();
2909
+
2910
+ $this->_plugin_data = get_plugin_data( $this->_plugin_main_file_path );
2911
+ }
2912
+
2913
+ return $this->_plugin_data;
2914
+ }
2915
+
2916
+ /**
2917
+ * @author Vova Feldman (@svovaf)
2918
+ * @since 1.0.1
2919
+ *
2920
+ * @return string Plugin slug.
2921
+ */
2922
+ function get_slug() {
2923
+ return $this->_slug;
2924
+ }
2925
+
2926
+ /**
2927
+ * @author Vova Feldman (@svovaf)
2928
+ * @since 1.0.1
2929
+ *
2930
+ * @return number Plugin ID.
2931
+ */
2932
+ function get_id() {
2933
+ return $this->_plugin->id;
2934
+ }
2935
+
2936
+ /**
2937
+ * @author Vova Feldman (@svovaf)
2938
+ * @since 1.0.1
2939
+ *
2940
+ * @return string Plugin public key.
2941
+ */
2942
+ function get_public_key() {
2943
+ return $this->_plugin->public_key;
2944
+ }
2945
+
2946
+ /**
2947
+ * Will be available only on sandbox mode.
2948
+ *
2949
+ * @author Vova Feldman (@svovaf)
2950
+ * @since 1.0.4
2951
+ *
2952
+ * @return mixed Plugin secret key.
2953
+ */
2954
+ function get_secret_key() {
2955
+ return $this->_plugin->secret_key;
2956
+ }
2957
+
2958
+ /**
2959
+ * @author Vova Feldman (@svovaf)
2960
+ * @since 1.1.1
2961
+ *
2962
+ * @return bool
2963
+ */
2964
+ function has_secret_key() {
2965
+ return ! empty( $this->_plugin->secret_key );
2966
+ }
2967
+
2968
+ /**
2969
+ * @author Vova Feldman (@svovaf)
2970
+ * @since 1.0.9
2971
+ *
2972
+ * @return string
2973
+ */
2974
+ function get_plugin_name() {
2975
+ $this->_logger->entrance();
2976
+
2977
+ if ( ! isset( $this->_plugin_name ) ) {
2978
+ $plugin_data = $this->get_plugin_data();
2979
+
2980
+ // Get name.
2981
+ $this->_plugin_name = $plugin_data['Name'];
2982
+
2983
+ // Check if plugin name contains [Premium] suffix and remove it.
2984
+ $suffix = '[premium]';
2985
+ $suffix_len = strlen( $suffix );
2986
+
2987
+ if ( strlen( $plugin_data['Name'] ) > $suffix_len &&
2988
+ $suffix === substr( strtolower( $plugin_data['Name'] ), - $suffix_len )
2989
+ ) {
2990
+ $this->_plugin_name = substr( $plugin_data['Name'], 0, - $suffix_len );
2991
+ }
2992
+
2993
+ $this->_logger->departure( 'Name = ' . $this->_plugin_name );
2994
+ }
2995
+
2996
+ return $this->_plugin_name;
2997
+ }
2998
+
2999
+ /**
3000
+ * @author Vova Feldman (@svovaf)
3001
+ * @since 1.0.0
3002
+ *
3003
+ * @return string
3004
+ */
3005
+ function get_plugin_version() {
3006
+ $this->_logger->entrance();
3007
+
3008
+ $plugin_data = $this->get_plugin_data();
3009
+
3010
+ $this->_logger->departure( 'Version = ' . $plugin_data['Version'] );
3011
+
3012
+ return $plugin_data['Version'];
3013
+ }
3014
+
3015
+ /**
3016
+ * @author Vova Feldman (@svovaf)
3017
+ * @since 1.0.4
3018
+ *
3019
+ * @return string
3020
+ */
3021
+ function get_plugin_basename() {
3022
+ return $this->_plugin_basename;
3023
+ }
3024
+
3025
+ function get_plugin_folder_name() {
3026
+ $this->_logger->entrance();
3027
+
3028
+ $plugin_folder = $this->_plugin_basename;
3029
+
3030
+ while ( '.' !== dirname( $plugin_folder ) ) {
3031
+ $plugin_folder = dirname( $plugin_folder );
3032
+ }
3033
+
3034
+ $this->_logger->departure( 'Folder Name = ' . $plugin_folder );
3035
+
3036
+ return $plugin_folder;
3037
+ }
3038
+
3039
+ #endregion ------------------------------------------------------------------
3040
+
3041
+ /* Account
3042
+ ------------------------------------------------------------------------------------------------------------------*/
3043
+
3044
+ /**
3045
+ * Find plugin's slug by plugin's basename.
3046
+ *
3047
+ * @author Vova Feldman (@svovaf)
3048
+ * @since 1.0.9
3049
+ *
3050
+ * @param string $plugin_base_name
3051
+ *
3052
+ * @return false|string
3053
+ */
3054
+ private static function find_slug_by_basename( $plugin_base_name ) {
3055
+ $file_slug_map = self::$_accounts->get_option( 'file_slug_map', array() );
3056
+
3057
+ if ( ! array( $file_slug_map ) || ! isset( $file_slug_map[ $plugin_base_name ] ) ) {
3058
+ return false;
3059
+ }
3060
+
3061
+ return $file_slug_map[ $plugin_base_name ];
3062
+ }
3063
+
3064
+ /**
3065
+ * Store the map between the plugin's basename to the slug.
3066
+ *
3067
+ * @author Vova Feldman (@svovaf)
3068
+ * @since 1.0.9
3069
+ */
3070
+ private function store_file_slug_map() {
3071
+ $file_slug_map = self::$_accounts->get_option( 'file_slug_map', array() );
3072
+
3073
+ if ( ! array( $file_slug_map ) ) {
3074
+ $file_slug_map = array();
3075
+ }
3076
+
3077
+ if ( ! isset( $file_slug_map[ $this->_plugin_basename ] ) ||
3078
+ $file_slug_map[ $this->_plugin_basename ] !== $this->_slug
3079
+ ) {
3080
+ $file_slug_map[ $this->_plugin_basename ] = $this->_slug;
3081
+ self::$_accounts->set_option( 'file_slug_map', $file_slug_map, true );
3082
+ }
3083
+ }
3084
+
3085
+ /**
3086
+ * @return FS_User[]
3087
+ */
3088
+ static function get_all_users() {
3089
+ $users = self::$_accounts->get_option( 'users', array() );
3090
+
3091
+ if ( ! is_array( $users ) ) {
3092
+ $users = array();
3093
+ }
3094
+
3095
+ return $users;
3096
+ }
3097
+
3098
+ /**
3099
+ * @return FS_Site[]
3100
+ */
3101
+ private static function get_all_sites() {
3102
+ $sites = self::$_accounts->get_option( 'sites', array() );
3103
+
3104
+ if ( ! is_array( $sites ) ) {
3105
+ $sites = array();
3106
+ }
3107
+
3108
+ return $sites;
3109
+ }
3110
+
3111
+ /**
3112
+ * @author Vova Feldman (@svovaf)
3113
+ * @since 1.0.6
3114
+ *
3115
+ * @return FS_Plugin_License[]
3116
+ */
3117
+ private static function get_all_licenses() {
3118
+ $licenses = self::$_accounts->get_option( 'licenses', array() );
3119
+
3120
+ if ( ! is_array( $licenses ) ) {
3121
+ $licenses = array();
3122
+ }
3123
+
3124
+ return $licenses;
3125
+ }
3126
+
3127
+ /**
3128
+ * @return FS_Plugin_Plan[]
3129
+ */
3130
+ private static function get_all_plans() {
3131
+ $plans = self::$_accounts->get_option( 'plans', array() );
3132
+
3133
+ if ( ! is_array( $plans ) ) {
3134
+ $plans = array();
3135
+ }
3136
+
3137
+ return $plans;
3138
+ }
3139
+
3140
+ /**
3141
+ * @author Vova Feldman (@svovaf)
3142
+ * @since 1.0.4
3143
+ *
3144
+ * @return FS_Plugin_Tag[]
3145
+ */
3146
+ private static function get_all_updates() {
3147
+ $updates = self::$_accounts->get_option( 'updates', array() );
3148
+
3149
+ if ( ! is_array( $updates ) ) {
3150
+ $updates = array();
3151
+ }
3152
+
3153
+ return $updates;
3154
+ }
3155
+
3156
+ /**
3157
+ * @author Vova Feldman (@svovaf)
3158
+ * @since 1.0.6
3159
+ *
3160
+ * @return FS_Plugin[]|false
3161
+ */
3162
+ private static function get_all_addons() {
3163
+ $addons = self::$_accounts->get_option( 'addons', array() );
3164
+
3165
+ if ( ! is_array( $addons ) ) {
3166
+ $addons = array();
3167
+ }
3168
+
3169
+ return $addons;
3170
+ }
3171
+
3172
+ /**
3173
+ * @author Vova Feldman (@svovaf)
3174
+ * @since 1.0.6
3175
+ *
3176
+ * @return FS_Plugin[]|false
3177
+ */
3178
+ private static function get_all_account_addons() {
3179
+ $addons = self::$_accounts->get_option( 'account_addons', array() );
3180
+
3181
+ if ( ! is_array( $addons ) ) {
3182
+ $addons = array();
3183
+ }
3184
+
3185
+ return $addons;
3186
+ }
3187
+
3188
+ /**
3189
+ * Check if user is registered.
3190
+ *
3191
+ * @author Vova Feldman (@svovaf)
3192
+ * @since 1.0.1
3193
+ * @return bool
3194
+ */
3195
+ function is_registered() {
3196
+ return is_object( $this->_user );
3197
+ }
3198
+
3199
+ /**
3200
+ * @author Vova Feldman (@svovaf)
3201
+ * @since 1.0.4
3202
+ *
3203
+ * @return FS_Plugin
3204
+ */
3205
+ function get_plugin() {
3206
+ return $this->_plugin;
3207
+ }
3208
+
3209
+ /**
3210
+ * @author Vova Feldman (@svovaf)
3211
+ * @since 1.0.3
3212
+ *
3213
+ * @return FS_User
3214
+ */
3215
+ function get_user() {
3216
+ return $this->_user;
3217
+ }
3218
+
3219
+ /**
3220
+ * @author Vova Feldman (@svovaf)
3221
+ * @since 1.0.3
3222
+ *
3223
+ * @return FS_Site
3224
+ */
3225
+ function get_site() {
3226
+ return $this->_site;
3227
+ }
3228
+
3229
+ /**
3230
+ * @author Vova Feldman (@svovaf)
3231
+ * @since 1.0.6
3232
+ *
3233
+ * @return FS_Plugin[]|false
3234
+ */
3235
+ function get_addons() {
3236
+ $this->_logger->entrance();
3237
+
3238
+ $addons = self::get_all_addons();
3239
+
3240
+ if ( ! is_array( $addons ) ||
3241
+ ! isset( $addons[ $this->_plugin->id ] ) ||
3242
+ ! is_array( $addons[ $this->_plugin->id ] ) ||
3243
+ 0 === count( $addons[ $this->_plugin->id ] )
3244
+ ) {
3245
+ return false;
3246
+ }
3247
+
3248
+ return $addons[ $this->_plugin->id ];
3249
+ }
3250
+
3251
+ /**
3252
+ * @author Vova Feldman (@svovaf)
3253
+ * @since 1.0.6
3254
+ *
3255
+ * @return FS_Plugin[]|false
3256
+ */
3257
+ function get_account_addons() {
3258
+ $this->_logger->entrance();
3259
+
3260
+ $addons = self::get_all_account_addons();
3261
+
3262
+ if ( ! is_array( $addons ) ||
3263
+ ! isset( $addons[ $this->_plugin->id ] ) ||
3264
+ ! is_array( $addons[ $this->_plugin->id ] ) ||
3265
+ 0 === count( $addons[ $this->_plugin->id ] )
3266
+ ) {
3267
+ return false;
3268
+ }
3269
+
3270
+ return $addons[ $this->_plugin->id ];
3271
+ }
3272
+
3273
+ /**
3274
+ * Get add-on by ID (from local data).
3275
+ *
3276
+ * @author Vova Feldman (@svovaf)
3277
+ * @since 1.0.6
3278
+ *
3279
+ * @param number $id
3280
+ *
3281
+ * @return FS_Plugin|false
3282
+ */
3283
+ function get_addon( $id ) {
3284
+ $this->_logger->entrance();
3285
+
3286
+ $addons = $this->get_addons();
3287
+
3288
+ if ( is_array( $addons ) ) {
3289
+ foreach ( $addons as $addon ) {
3290
+ if ( $id == $addon->id ) {
3291
+ return $addon;
3292
+ }
3293
+ }
3294
+ }
3295
+
3296
+ return false;
3297
+ }
3298
+
3299
+ /**
3300
+ * Get add-on by slug (from local data).
3301
+ *
3302
+ * @author Vova Feldman (@svovaf)
3303
+ * @since 1.0.6
3304
+ *
3305
+ * @param string $slug
3306
+ *
3307
+ * @return FS_Plugin|false
3308
+ */
3309
+ function get_addon_by_slug( $slug ) {
3310
+ $this->_logger->entrance();
3311
+
3312
+ $addons = $this->get_addons();
3313
+
3314
+ if ( is_array( $addons ) ) {
3315
+ foreach ( $addons as $addon ) {
3316
+ if ( $slug == $addon->slug ) {
3317
+ return $addon;
3318
+ }
3319
+ }
3320
+ }
3321
+
3322
+ return false;
3323
+ }
3324
+
3325
+ #region Plans & Licensing ------------------------------------------------------------------
3326
+
3327
+ /**
3328
+ * Check if running premium plugin code.
3329
+ *
3330
+ * @author Vova Feldman (@svovaf)
3331
+ * @since 1.0.5
3332
+ *
3333
+ * @return bool
3334
+ */
3335
+ function is_premium() {
3336
+ return $this->_plugin->is_premium;
3337
+ }
3338
+
3339
+ /**
3340
+ * Get site's plan ID.
3341
+ *
3342
+ * @author Vova Feldman (@svovaf)
3343
+ * @since 1.0.2
3344
+ *
3345
+ * @return number
3346
+ */
3347
+ function get_plan_id() {
3348
+ return $this->_site->plan->id;
3349
+ }
3350
+
3351
+ /**
3352
+ * Get site's plan title.
3353
+ *
3354
+ * @author Vova Feldman (@svovaf)
3355
+ * @since 1.0.2
3356
+ *
3357
+ * @return string
3358
+ */
3359
+ function get_plan_title() {
3360
+ return $this->_site->plan->title;
3361
+ }
3362
+
3363
+ /**
3364
+ * @author Vova Feldman (@svovaf)
3365
+ * @since 1.0.9
3366
+ *
3367
+ * @return FS_Plugin_Plan
3368
+ */
3369
+ function get_plan() {
3370
+ return is_object( $this->_site->plan ) ? $this->_site->plan : false;
3371
+ }
3372
+
3373
+ /**
3374
+ * @author Vova Feldman (@svovaf)
3375
+ * @since 1.0.3
3376
+ *
3377
+ * @return bool
3378
+ */
3379
+ function is_trial() {
3380
+ $this->_logger->entrance();
3381
+
3382
+ if ( ! $this->is_registered() ) {
3383
+ return false;
3384
+ }
3385
+
3386
+ // Paid plan beats trial.
3387
+ return $this->is_free_plan() && $this->_site->is_trial();
3388
+ }
3389
+
3390
+ /**
3391
+ * Check if trial already utilized.
3392
+ *
3393
+ * @since 1.0.9
3394
+ *
3395
+ * @return bool
3396
+ */
3397
+ function is_trial_utilized() {
3398
+ $this->_logger->entrance();
3399
+
3400
+ if ( ! $this->is_registered() ) {
3401
+ return false;
3402
+ }
3403
+
3404
+ return $this->_site->is_trial_utilized();
3405
+ }
3406
+
3407
+ /**
3408
+ * Get trial plan information (if in trial).
3409
+ *
3410
+ * @author Vova Feldman (@svovaf)
3411
+ * @since 1.0.9
3412
+ *
3413
+ * @return bool|FS_Plugin_Plan
3414
+ */
3415
+ function get_trial_plan() {
3416
+ $this->_logger->entrance();
3417
+
3418
+ if ( ! $this->is_trial() ) {
3419
+ return false;
3420
+ }
3421
+
3422
+ return $this->_storage->trial_plan;
3423
+ }
3424
+
3425
+ /**
3426
+ * Check if the user has an activated and valid paid license on current plugin's install.
3427
+ *
3428
+ * @since 1.0.9
3429
+ *
3430
+ * @return bool
3431
+ */
3432
+ function is_paying() {
3433
+ $this->_logger->entrance();
3434
+
3435
+ if ( ! $this->is_registered() ) {
3436
+ return false;
3437
+ }
3438
+
3439
+ return (
3440
+ ! $this->is_trial() &&
3441
+ 'free' !== $this->_site->plan->name &&
3442
+ $this->has_features_enabled_license()
3443
+ );
3444
+ }
3445
+
3446
+ /**
3447
+ * @author Vova Feldman (@svovaf)
3448
+ * @since 1.0.4
3449
+ *
3450
+ * @return bool
3451
+ */
3452
+ function is_free_plan() {
3453
+ if ( ! $this->is_registered() ) {
3454
+ return true;
3455
+ }
3456
+
3457
+ return (
3458
+ 'free' === $this->_site->plan->name ||
3459
+ ! $this->has_features_enabled_license()
3460
+ );
3461
+ }
3462
+
3463
+ /**
3464
+ * @author Vova Feldman (@svovaf)
3465
+ * @since 1.0.5
3466
+ *
3467
+ * @return bool
3468
+ */
3469
+ function _has_premium_license() {
3470
+ $this->_logger->entrance();
3471
+
3472
+ $premium_license = $this->_get_available_premium_license();
3473
+
3474
+ return ( false !== $premium_license );
3475
+ }
3476
+
3477
+ /**
3478
+ * @author Vova Feldman (@svovaf)
3479
+ * @since 1.0.5
3480
+ *
3481
+ * @return FS_Plugin_License
3482
+ */
3483
+ function _get_available_premium_license() {
3484
+ $this->_logger->entrance();
3485
+
3486
+ if ( is_array( $this->_licenses ) ) {
3487
+ foreach ( $this->_licenses as $license ) {
3488
+ if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
3489
+ return $license;
3490
+ }
3491
+ }
3492
+ }
3493
+
3494
+ return false;
3495
+ }
3496
+
3497
+ /**
3498
+ * Sync local plugin plans with remote server.
3499
+ *
3500
+ * @author Vova Feldman (@svovaf)
3501
+ * @since 1.0.5
3502
+ *
3503
+ * @return FS_Plugin_Plan[]|object
3504
+ */
3505
+ function _sync_plans() {
3506
+ $plans = $this->_fetch_plugin_plans();
3507
+ if ( ! $this->is_api_error( $plans ) ) {
3508
+ $this->_plans = $plans;
3509
+ $this->_store_plans();
3510
+ }
3511
+
3512
+ $this->do_action( 'after_plans_sync', $plans );
3513
+
3514
+ return $this->_plans;
3515
+ }
3516
+
3517
+ /**
3518
+ * @author Vova Feldman (@svovaf)
3519
+ * @since 1.0.5
3520
+ *
3521
+ * @param number $id
3522
+ *
3523
+ * @return FS_Plugin_Plan
3524
+ */
3525
+ function _get_plan_by_id( $id ) {
3526
+ $this->_logger->entrance();
3527
+
3528
+ if ( ! is_array( $this->_plans ) || 0 === count( $this->_plans ) ) {
3529
+ $this->_sync_plans();
3530
+ }
3531
+
3532
+ foreach ( $this->_plans as $plan ) {
3533
+ if ( $id == $plan->id ) {
3534
+ return $plan;
3535
+ }
3536
+ }
3537
+
3538
+ return false;
3539
+ }
3540
+
3541
+ /**
3542
+ * Sync local plugin plans with remote server.
3543
+ *
3544
+ * @author Vova Feldman (@svovaf)
3545
+ * @since 1.0.6
3546
+ *
3547
+ * @return FS_Plugin_License[]|object
3548
+ */
3549
+ function _sync_licenses() {
3550
+ $licenses = $this->_fetch_licenses();
3551
+ if ( ! isset( $licenses->error ) ) {
3552
+ $this->_licenses = $licenses;
3553
+ $this->_store_licenses();
3554
+ }
3555
+
3556
+ // Update current license.
3557
+ if ( is_object( $this->_license ) ) {
3558
+ $this->_license = $this->_get_license_by_id( $this->_license->id );
3559
+ }
3560
+
3561
+ return $this->_licenses;
3562
+ }
3563
+
3564
+ /**
3565
+ * @author Vova Feldman (@svovaf)
3566
+ * @since 1.0.5
3567
+ *
3568
+ * @param number $id
3569
+ *
3570
+ * @return FS_Plugin_License
3571
+ */
3572
+ function _get_license_by_id( $id ) {
3573
+ $this->_logger->entrance();
3574
+
3575
+ if ( ! is_numeric( $id ) ) {
3576
+ return false;
3577
+ }
3578
+
3579
+ if ( ! is_array( $this->_licenses ) || 0 === count( $this->_licenses ) ) {
3580
+ $this->_sync_licenses();
3581
+ }
3582
+
3583
+ foreach ( $this->_licenses as $license ) {
3584
+ if ( $id == $license->id ) {
3585
+ return $license;
3586
+ }
3587
+ }
3588
+
3589
+ return false;
3590
+ }
3591
+
3592
+ /**
3593
+ * Sync site's license with user licenses.
3594
+ *
3595
+ * @author Vova Feldman (@svovaf)
3596
+ * @since 1.0.6
3597
+ *
3598
+ * @param FS_Plugin_License|null $new_license
3599
+ */
3600
+ function _update_site_license( $new_license ) {
3601
+ $this->_logger->entrance();
3602
+
3603
+ $this->_license = $new_license;
3604
+
3605
+ if ( ! is_object( $new_license ) ) {
3606
+ $this->_site->license_id = null;
3607
+ $this->_sync_site_subscription( null );
3608
+
3609
+ return;
3610
+ }
3611
+
3612
+ $this->_site->license_id = $this->_license->id;
3613
+
3614
+ if ( ! is_array( $this->_licenses ) ) {
3615
+ $this->_licenses = array();
3616
+ }
3617
+
3618
+ $is_license_found = false;
3619
+ for ( $i = 0, $len = count( $this->_licenses ); $i < $len; $i ++ ) {
3620
+ if ( $new_license->id == $this->_licenses[ $i ]->id ) {
3621
+ $this->_licenses[ $i ] = $new_license;
3622
+
3623
+ $is_license_found = true;
3624
+ break;
3625
+ }
3626
+ }
3627
+
3628
+ // If new license just append.
3629
+ if ( ! $is_license_found ) {
3630
+ $this->_licenses[] = $new_license;
3631
+ }
3632
+
3633
+ $this->_sync_site_subscription( $new_license );
3634
+ }
3635
+
3636
+ /**
3637
+ * Sync site's subscription.
3638
+ *
3639
+ * @author Vova Feldman (@svovaf)
3640
+ * @since 1.0.9
3641
+ *
3642
+ * @param FS_Plugin_License|null $license
3643
+ *
3644
+ * @return bool|\FS_Subscription
3645
+ */
3646
+ private function _sync_site_subscription( $license ) {
3647
+ if ( ! is_object( $license ) ) {
3648
+ unset( $this->_storage->subscription );
3649
+
3650
+ return false;
3651
+ }
3652
+
3653
+ // Load subscription details if not lifetime.
3654
+ $subscription = $license->is_lifetime() ?
3655
+ false :
3656
+ $this->_fetch_site_license_subscription();
3657
+
3658
+ if ( is_object( $subscription ) && ! isset( $subscription->error ) ) {
3659
+ $this->_storage->subscription = $subscription;
3660
+ } else {
3661
+ unset( $this->_storage->subscription );
3662
+ }
3663
+
3664
+ return $subscription;
3665
+ }
3666
+
3667
+ /**
3668
+ * @author Vova Feldman (@svovaf)
3669
+ * @since 1.0.6
3670
+ *
3671
+ * @return bool|\FS_Plugin_License
3672
+ */
3673
+ function _get_license() {
3674
+ return $this->_license;
3675
+ }
3676
+
3677
+ /**
3678
+ * @return bool|\FS_Subscription
3679
+ */
3680
+ function _get_subscription() {
3681
+ return isset( $this->_storage->subscription ) ?
3682
+ $this->_storage->subscription :
3683
+ false;
3684
+ }
3685
+
3686
+ /**
3687
+ * @author Vova Feldman (@svovaf)
3688
+ * @since 1.0.2
3689
+ *
3690
+ * @param string $plan Plan name
3691
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
3692
+ *
3693
+ * @return bool
3694
+ */
3695
+ function is_plan( $plan, $exact = false ) {
3696
+ $this->_logger->entrance();
3697
+
3698
+ if ( ! $this->is_registered() ) {
3699
+ return false;
3700
+ }
3701
+
3702
+ $plan = strtolower( $plan );
3703
+
3704
+ if ( $this->_site->plan->name === $plan ) // Exact plan.
3705
+ {
3706
+ return true;
3707
+ } else if ( $exact ) // Required exact, but plans are different.
3708
+ {
3709
+ return false;
3710
+ }
3711
+
3712
+ $current_plan_order = - 1;
3713
+ $required_plan_order = - 1;
3714
+ for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
3715
+ if ( $plan === $this->_plans[ $i ]->name ) {
3716
+ $required_plan_order = $i;
3717
+ } else if ( $this->_site->plan->name === $this->_plans[ $i ]->name ) {
3718
+ $current_plan_order = $i;
3719
+ }
3720
+ }
3721
+
3722
+ return ( $current_plan_order > $required_plan_order );
3723
+ }
3724
+
3725
+ /**
3726
+ * Check if plan based on trial. If not in trial mode, should return false.
3727
+ *
3728
+ * @since 1.0.9
3729
+ *
3730
+ * @param string $plan Plan name
3731
+ * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.
3732
+ *
3733
+ * @return bool
3734
+ */
3735
+ function is_trial_plan( $plan, $exact = false ) {
3736
+ $this->_logger->entrance();
3737
+
3738
+ if ( ! $this->is_registered() ) {
3739
+ return false;
3740
+ }
3741
+
3742
+ if ( ! $this->is_trial() ) {
3743
+ return false;
3744
+ }
3745
+
3746
+ if ( ! isset( $this->_storage->trial_plan ) ) {
3747
+ // Store trial plan information.
3748
+ $this->_enrich_site_trial_plan( true );
3749
+ }
3750
+
3751
+ if ( $this->_storage->trial_plan->name === $plan ) // Exact plan.
3752
+ {
3753
+ return true;
3754
+ } else if ( $exact ) // Required exact, but plans are different.
3755
+ {
3756
+ return false;
3757
+ }
3758
+
3759
+ $current_plan_order = - 1;
3760
+ $required_plan_order = - 1;
3761
+ for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
3762
+ if ( $plan === $this->_plans[ $i ]->name ) {
3763
+ $required_plan_order = $i;
3764
+ } else if ( $this->_storage->trial_plan->name === $this->_plans[ $i ]->name ) {
3765
+ $current_plan_order = $i;
3766
+ }
3767
+ }
3768
+
3769
+ return ( $current_plan_order > $required_plan_order );
3770
+ }
3771
+
3772
+ /**
3773
+ * Check if plugin has any paid plans.
3774
+ *
3775
+ * @author Vova Feldman (@svovaf)
3776
+ * @since 1.0.7
3777
+ *
3778
+ * @return bool
3779
+ */
3780
+ function has_paid_plan() {
3781
+ return $this->_has_paid_plans || FS_Plan_Manager::instance()->has_paid_plan( $this->_plans );
3782
+ }
3783
+
3784
+ /**
3785
+ * Check if plugin has any plan with a trail.
3786
+ *
3787
+ * @author Vova Feldman (@svovaf)
3788
+ * @since 1.0.9
3789
+ *
3790
+ * @return bool
3791
+ */
3792
+ function has_trial_plan() {
3793
+ if ( ! $this->is_registered() ) {
3794
+ return false;
3795
+ }
3796
+
3797
+ return $this->_storage->get( 'has_trial_plan', false );
3798
+ }
3799
+
3800
+ /**
3801
+ * Check if plugin has any free plan, or is it premium only.
3802
+ *
3803
+ * Note: If no plans configured, assume plugin is free.
3804
+ *
3805
+ * @author Vova Feldman (@svovaf)
3806
+ * @since 1.0.7
3807
+ *
3808
+ * @return bool
3809
+ */
3810
+ function has_free_plan() {
3811
+ return FS_Plan_Manager::instance()->has_free_plan( $this->_plans );
3812
+ }
3813
+
3814
+ #region URL Generators
3815
+
3816
+ /**
3817
+ * Alias to pricing_url().
3818
+ *
3819
+ * @author Vova Feldman (@svovaf)
3820
+ * @since 1.0.2
3821
+ *
3822
+ * @uses pricing_url
3823
+ *
3824
+ * @param string $period Billing cycle
3825
+ *
3826
+ * @return string
3827
+ */
3828
+ function get_upgrade_url( $period = WP_FS__PERIOD_ANNUALLY ) {
3829
+ return $this->pricing_url( $period );
3830
+ }
3831
+
3832
+ /**
3833
+ * @author Vova Feldman (@svovaf)
3834
+ * @since 1.0.9
3835
+ *
3836
+ * @uses get_upgrade_url
3837
+ *
3838
+ * @return string
3839
+ */
3840
+ function get_trial_url() {
3841
+ return $this->get_upgrade_url( 'trial' );
3842
+ }
3843
+
3844
+ /**
3845
+ * Plugin's pricing URL.
3846
+ *
3847
+ * @author Vova Feldman (@svovaf)
3848
+ * @since 1.0.4
3849
+ *
3850
+ * @param string $period Billing cycle
3851
+ *
3852
+ * @return string
3853
+ */
3854
+ function pricing_url( $period = WP_FS__PERIOD_ANNUALLY ) {
3855
+ $this->_logger->entrance();
3856
+
3857
+ return $this->_get_admin_page_url( 'pricing', array( 'billing_cycle' => $period ) );
3858
+ }
3859
+
3860
+ /**
3861
+ * Checkout page URL.
3862
+ *
3863
+ * @author Vova Feldman (@svovaf)
3864
+ * @since 1.0.6
3865
+ *
3866
+ * @param string $period Billing cycle
3867
+ * @param bool|string $plan_name
3868
+ * @param bool|number $plan_id
3869
+ * @param bool|int $licenses
3870
+ *
3871
+ * @return string
3872
+ */
3873
+ function checkout_url(
3874
+ $period = WP_FS__PERIOD_ANNUALLY,
3875
+ $plan_name = false,
3876
+ $plan_id = false,
3877
+ $licenses = false
3878
+ ) {
3879
+ $this->_logger->entrance();
3880
+
3881
+ $params = array(
3882
+ 'checkout' => 'true',
3883
+ 'billing_cycle' => $period,
3884
+ );
3885
+
3886
+ if ( false !== $plan_name ) {
3887
+ $params['plan_name'] = $plan_name;
3888
+ }
3889
+ if ( false !== $plan_id ) {
3890
+ $params['plan_id'] = $plan_id;
3891
+ }
3892
+ if ( false !== $licenses ) {
3893
+ $params['licenses'] = $licenses;
3894
+ }
3895
+
3896
+ return $this->_get_admin_page_url( 'pricing', $params );
3897
+ }
3898
+
3899
+ #endregion
3900
+
3901
+ #endregion ------------------------------------------------------------------
3902
+
3903
+ /**
3904
+ * Check if plugin has any add-ons.
3905
+ *
3906
+ * @author Vova Feldman (@svovaf)
3907
+ * @since 1.0.5
3908
+ *
3909
+ * @return bool
3910
+ */
3911
+ function _has_addons() {
3912
+ $this->_logger->entrance();
3913
+
3914
+ return ( $this->_has_addons || false !== $this->get_addons() );
3915
+ }
3916
+
3917
+ /**
3918
+ * Check if plugin can work in anonymous mode.
3919
+ *
3920
+ * @author Vova Feldman (@svovaf)
3921
+ * @since 1.0.9
3922
+ *
3923
+ * @return bool
3924
+ */
3925
+ function enable_anonymous() {
3926
+ return $this->_enable_anonymous;
3927
+ }
3928
+
3929
+ /**
3930
+ * Check if feature supported with current site's plan.
3931
+ *
3932
+ * @author Vova Feldman (@svovaf)
3933
+ * @since 1.0.1
3934
+ *
3935
+ * @todo IMPLEMENT
3936
+ *
3937
+ * @param number $feature_id
3938
+ *
3939
+ * @throws Exception
3940
+ */
3941
+ function is_feature_supported( $feature_id ) {
3942
+ throw new Exception( 'not implemented' );
3943
+ }
3944
+
3945
+ /**
3946
+ * @author Vova Feldman (@svovaf)
3947
+ * @since 1.0.1
3948
+ *
3949
+ * @return bool Is running in SSL/HTTPS
3950
+ */
3951
+ function is_ssl() {
3952
+ return WP_FS__IS_HTTPS;
3953
+ }
3954
+
3955
+ /**
3956
+ * @author Vova Feldman (@svovaf)
3957
+ * @since 1.0.9
3958
+ *
3959
+ * @return bool Is running in AJAX call.
3960
+ *
3961
+ * @link http://wordpress.stackexchange.com/questions/70676/how-to-check-if-i-am-in-admin-ajax
3962
+ */
3963
+ function is_ajax() {
3964
+ return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
3965
+ }
3966
+
3967
+ /**
3968
+ * Check if running in HTTPS and if site's plan matching the specified plan.
3969
+ *
3970
+ * @param string $plan
3971
+ * @param bool $exact
3972
+ *
3973
+ * @return bool
3974
+ */
3975
+ function is_ssl_and_plan( $plan, $exact = false ) {
3976
+ return ( $this->is_ssl() && $this->is_plan( $plan, $exact ) );
3977
+ }
3978
+
3979
+ /**
3980
+ * Construct plugin's settings page URL.
3981
+ *
3982
+ * @author Vova Feldman (@svovaf)
3983
+ * @since 1.0.4
3984
+ *
3985
+ * @param string $page
3986
+ * @param array $params
3987
+ *
3988
+ * @return string
3989
+ */
3990
+ function _get_admin_page_url( $page = '', $params = array() ) {
3991
+ if ( ! $this->_menu->is_top_level() ) {
3992
+ $parent_slug = $this->_menu->get_parent_slug();
3993
+ $menu_file = ( false !== strpos( $parent_slug, '.php' ) ) ?
3994
+ $parent_slug :
3995
+ 'admin.php';
3996
+
3997
+ return add_query_arg( array_merge( $params, array(
3998
+ 'page' => $this->_menu->get_slug( $page ),
3999
+ ) ), admin_url( $menu_file, 'admin' ) );
4000
+ }
4001
+
4002
+ if ( $this->_menu->is_cpt() ) {
4003
+ if ( empty( $page ) && $this->is_activation_mode() ) {
4004
+ return add_query_arg( array_merge( $params, array(
4005
+ 'page' => $this->_menu->get_slug()
4006
+ ) ), admin_url( 'admin.php', 'admin' ) );
4007
+ } else {
4008
+ if ( ! empty( $page ) ) {
4009
+ $params['page'] = $this->_menu->get_slug( $page );
4010
+ }
4011
+
4012
+ return add_query_arg( $params, admin_url( $this->_menu->get_raw_slug(), 'admin' ) );
4013
+ }
4014
+ } else {
4015
+ return add_query_arg( array_merge( $params, array(
4016
+ 'page' => $this->_menu->get_slug( $page ),
4017
+ ) ), admin_url( 'admin.php', 'admin' ) );
4018
+ }
4019
+ }
4020
+
4021
+
4022
+ /**
4023
+ * Plugin's account URL.
4024
+ *
4025
+ * @author Vova Feldman (@svovaf)
4026
+ * @since 1.0.4
4027
+ *
4028
+ * @param bool|string $action
4029
+ * @param array $params
4030
+ *
4031
+ * @param bool $add_action_nonce
4032
+ *
4033
+ * @return string
4034
+ */
4035
+ function get_account_url( $action = false, $params = array(), $add_action_nonce = true ) {
4036
+ if ( is_string( $action ) ) {
4037
+ $params['fs_action'] = $action;
4038
+ }
4039
+
4040
+ self::require_pluggable_essentials();
4041
+
4042
+ return ( $add_action_nonce && is_string( $action ) ) ?
4043
+ wp_nonce_url( $this->_get_admin_page_url( 'account', $params ), $action ) :
4044
+ $this->_get_admin_page_url( 'account', $params );
4045
+ }
4046
+
4047
+ /**
4048
+ * Plugin's account URL.
4049
+ *
4050
+ * @author Vova Feldman (@svovaf)
4051
+ * @since 1.0.4
4052
+ *
4053
+ * @param bool|string $topic
4054
+ * @param bool|string $message
4055
+ *
4056
+ * @return string
4057
+ */
4058
+ function contact_url( $topic = false, $message = false ) {
4059
+ $params = array();
4060
+ if ( is_string( $topic ) ) {
4061
+ $params['topic'] = $topic;
4062
+ }
4063
+ if ( is_string( $message ) ) {
4064
+ $params['message'] = $message;
4065
+ }
4066
+
4067
+ if ( $this->is_addon() ) {
4068
+ $params['addon_id'] = $this->get_id();
4069
+
4070
+ return $this->get_parent_instance()->_get_admin_page_url( 'contact', $params );
4071
+ } else {
4072
+ return $this->_get_admin_page_url( 'contact', $params );
4073
+ }
4074
+ }
4075
+
4076
+ /**
4077
+ * Add-on direct info URL.
4078
+ *
4079
+ * @author Vova Feldman (@svovaf)
4080
+ * @since 1.1.0
4081
+ *
4082
+ * @param string $slug
4083
+ *
4084
+ * @return string
4085
+ */
4086
+ function addon_url( $slug ) {
4087
+ return $this->_get_admin_page_url( 'addons', array(
4088
+ 'slug' => $slug
4089
+ ) );
4090
+ }
4091
+
4092
+ /* Logger
4093
+ ------------------------------------------------------------------------------------------------------------------*/
4094
+ /**
4095
+ * @param string $id
4096
+ * @param bool $prefix_slug
4097
+ *
4098
+ * @return FS_Logger
4099
+ */
4100
+ function get_logger( $id = '', $prefix_slug = true ) {
4101
+ return FS_Logger::get_logger( ( $prefix_slug ? $this->_slug : '' ) . ( ( ! $prefix_slug || empty( $id ) ) ? '' : '_' ) . $id );
4102
+ }
4103
+
4104
+ /**
4105
+ * @param $id
4106
+ * @param bool $load_options
4107
+ * @param bool $prefix_slug
4108
+ *
4109
+ * @return FS_Option_Manager
4110
+ */
4111
+ function get_options_manager( $id, $load_options = false, $prefix_slug = true ) {
4112
+ return FS_Option_Manager::get_manager( ( $prefix_slug ? $this->_slug : '' ) . ( ( ! $prefix_slug || empty( $id ) ) ? '' : '_' ) . $id, $load_options );
4113
+ }
4114
+
4115
+ /* Security
4116
+ ------------------------------------------------------------------------------------------------------------------*/
4117
+ private function _encrypt( $str ) {
4118
+ if ( is_null( $str ) ) {
4119
+ return null;
4120
+ }
4121
+
4122
+ return base64_encode( $str );
4123
+ }
4124
+
4125
+ private function _decrypt( $str ) {
4126
+ if ( is_null( $str ) ) {
4127
+ return null;
4128
+ }
4129
+
4130
+ return base64_decode( $str );
4131
+ }
4132
+
4133
+ /**
4134
+ * @author Vova Feldman (@svovaf)
4135
+ * @since 1.0.5
4136
+ *
4137
+ * @param FS_Entity $entity
4138
+ *
4139
+ * @return FS_Entity Return an encrypted clone entity.
4140
+ */
4141
+ private function _encrypt_entity( FS_Entity $entity ) {
4142
+ $clone = clone $entity;
4143
+ $props = get_object_vars( $entity );
4144
+
4145
+ foreach ( $props as $key => $val ) {
4146
+ $clone->{$key} = $this->_encrypt( $val );
4147
+ }
4148
+
4149
+ return $clone;
4150
+ }
4151
+
4152
+ /**
4153
+ * @author Vova Feldman (@svovaf)
4154
+ * @since 1.0.5
4155
+ *
4156
+ * @param FS_Entity $entity
4157
+ *
4158
+ * @return FS_Entity Return an decrypted clone entity.
4159
+ */
4160
+ private function _decrypt_entity( FS_Entity $entity ) {
4161
+ $clone = clone $entity;
4162
+ $props = get_object_vars( $entity );
4163
+
4164
+ foreach ( $props as $key => $val ) {
4165
+ $clone->{$key} = $this->_decrypt( $val );
4166
+ }
4167
+
4168
+ return $clone;
4169
+ }
4170
+
4171
+ /**
4172
+ * Tries to activate account based on POST params.
4173
+ *
4174
+ * @author Vova Feldman (@svovaf)
4175
+ * @since 1.0.2
4176
+ */
4177
+ function _activate_account() {
4178
+ if ( $this->is_registered() ) {
4179
+ // Already activated.
4180
+ return;
4181
+ }
4182
+
4183
+ $this->_clean_admin_content_section();
4184
+
4185
+ if ( fs_request_is_action( 'activate' ) && fs_request_is_post() ) {
4186
+ // check_admin_referer( 'activate_' . $this->_plugin->public_key );
4187
+
4188
+ // Verify matching plugin details.
4189
+ if ( $this->_plugin->id != fs_request_get( 'plugin_id' ) || $this->_slug != fs_request_get( 'plugin_slug' ) ) {
4190
+ return;
4191
+ }
4192
+
4193
+ $user = new FS_User();
4194
+ $user->id = fs_request_get( 'user_id' );
4195
+ $user->public_key = fs_request_get( 'user_public_key' );
4196
+ $user->secret_key = fs_request_get( 'user_secret_key' );
4197
+ $user->email = fs_request_get( 'user_email' );
4198
+ $user->first = fs_request_get( 'user_first' );
4199
+ $user->last = fs_request_get( 'user_last' );
4200
+ $user->is_verified = fs_request_get_bool( 'user_is_verified' );
4201
+
4202
+ $site = new FS_Site();
4203
+ $site->id = fs_request_get( 'install_id' );
4204
+ $site->public_key = fs_request_get( 'install_public_key' );
4205
+ $site->secret_key = fs_request_get( 'install_secret_key' );
4206
+ $site->plan->id = fs_request_get( 'plan_id' );
4207
+ $site->plan->title = fs_request_get( 'plan_title' );
4208
+ $site->plan->name = fs_request_get( 'plan_name' );
4209
+
4210
+ $plans = array();
4211
+ $plans_data = json_decode( urldecode( fs_request_get( 'plans' ) ) );
4212
+ foreach ( $plans_data as $p ) {
4213
+ $plans[] = new FS_Plugin_Plan( $p );
4214
+ }
4215
+
4216
+ $this->_set_account( $user, $site, $plans );
4217
+
4218
+ // Reload the page with the keys.
4219
+ if ( fs_redirect( $this->_get_admin_page_url() ) ) {
4220
+ exit();
4221
+ }
4222
+ }
4223
+ }
4224
+
4225
+ /**
4226
+ * @author Vova Feldman (@svovaf)
4227
+ * @since 1.0.7
4228
+ *
4229
+ * @param string $email
4230
+ *
4231
+ * @return FS_User|bool
4232
+ */
4233
+ static function _get_user_by_email( $email ) {
4234
+ self::$_static_logger->entrance();
4235
+
4236
+ $email = trim( strtolower( $email ) );
4237
+ $users = self::get_all_users();
4238
+ if ( is_array( $users ) ) {
4239
+ foreach ( $users as $u ) {
4240
+ if ( $email === trim( strtolower( $u->email ) ) ) {
4241
+ return $u;
4242
+ }
4243
+ }
4244
+ }
4245
+
4246
+ return false;
4247
+ }
4248
+
4249
+ #region Account (Loading, Updates & Activation) ------------------------------------------------------------------
4250
+
4251
+ /***
4252
+ * Load account information (user + site).
4253
+ *
4254
+ * @author Vova Feldman (@svovaf)
4255
+ * @since 1.0.1
4256
+ */
4257
+ private function _load_account() {
4258
+ $this->_logger->entrance();
4259
+
4260
+ $this->do_action( 'before_account_load' );
4261
+
4262
+ $sites = self::get_all_sites();
4263
+ $users = self::get_all_users();
4264
+ $plans = self::get_all_plans();
4265
+ $licenses = self::get_all_licenses();
4266
+
4267
+ if ( $this->_logger->is_on() && is_admin() ) {
4268
+ $this->_logger->log( 'sites = ' . var_export( $sites, true ) );
4269
+ $this->_logger->log( 'users = ' . var_export( $users, true ) );
4270
+ $this->_logger->log( 'plans = ' . var_export( $plans, true ) );
4271
+ $this->_logger->log( 'licenses = ' . var_export( $licenses, true ) );
4272
+ }
4273
+
4274
+ $site = isset( $sites[ $this->_slug ] ) ? $sites[ $this->_slug ] : false;
4275
+
4276
+ if ( is_object( $site ) &&
4277
+ is_numeric( $site->id ) &&
4278
+ is_numeric( $site->user_id ) &&
4279
+ is_object( $site->plan )
4280
+ ) {
4281
+ // Load site.
4282
+ $this->_site = clone $site;
4283
+ $this->_site->plan = $this->_decrypt_entity( $this->_site->plan );
4284
+
4285
+ // Load relevant user.
4286
+ $this->_user = clone $users[ $this->_site->user_id ];
4287
+
4288
+ // Load plans.
4289
+ $this->_plans = $plans[ $this->_slug ];
4290
+ if ( ! is_array( $this->_plans ) || empty( $this->_plans ) ) {
4291
+ $this->_sync_plans( true );
4292
+ } else {
4293
+ for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
4294
+ if ( $this->_plans[ $i ] instanceof FS_Plugin_Plan ) {
4295
+ $this->_plans[ $i ] = $this->_decrypt_entity( $this->_plans[ $i ] );
4296
+ } else {
4297
+ unset( $this->_plans[ $i ] );
4298
+ }
4299
+ }
4300
+ }
4301
+
4302
+ // Load licenses.
4303
+ $this->_licenses = array();
4304
+ if ( is_array( $licenses ) &&
4305
+ isset( $licenses[ $this->_slug ] ) &&
4306
+ isset( $licenses[ $this->_slug ][ $this->_user->id ] )
4307
+ ) {
4308
+ $this->_licenses = $licenses[ $this->_slug ][ $this->_user->id ];
4309
+ }
4310
+
4311
+ $this->_license = $this->_get_license_by_id( $this->_site->license_id );
4312
+
4313
+ if ( $this->_site->version != $this->get_plugin_version() ) {
4314
+ // If stored install version is different than current installed plugin version,
4315
+ // then update plugin version event.
4316
+ $this->update_plugin_version_event();
4317
+ }
4318
+ }
4319
+
4320
+ $this->_register_account_hooks();
4321
+ }
4322
+
4323
+ /**
4324
+ * @author Vova Feldman (@svovaf)
4325
+ * @since 1.0.1
4326
+ *
4327
+ * @param FS_User $user
4328
+ * @param FS_Site $site
4329
+ * @param bool|array $plans
4330
+ */
4331
+ private function _set_account( FS_User $user, FS_Site $site, $plans = false ) {
4332
+ $site->slug = $this->_slug;
4333
+ $site->user_id = $user->id;
4334
+
4335
+ $this->_site = $site;
4336
+ $this->_user = $user;
4337
+ if ( false !== $plans ) {
4338
+ $this->_plans = $plans;
4339
+ }
4340
+
4341
+ $this->send_install_update( array(), true );
4342
+
4343
+ $this->_store_account();
4344
+
4345
+ }
4346
+
4347
+ /**
4348
+ * Set user and site identities.
4349
+ *
4350
+ * @author Vova Feldman (@svovaf)
4351
+ * @since 1.0.9
4352
+ *
4353
+ * @param FS_User $user
4354
+ * @param FS_Site $site
4355
+ * @param bool $redirect
4356
+ *
4357
+ * @return bool False if account already set.
4358
+ */
4359
+ function setup_account( FS_User $user, FS_Site $site, $redirect = true ) {
4360
+ $this->_user = $user;
4361
+ $this->_site = $site;
4362
+ $this->_enrich_site_plan( false );
4363
+
4364
+ $this->_set_account( $user, $site );
4365
+ $this->_sync_plans();
4366
+
4367
+ if ( $this->is_trial() ) {
4368
+ // Store trial plan information.
4369
+ $this->_enrich_site_trial_plan( true );
4370
+ }
4371
+
4372
+ $this->do_action( 'after_account_connection', $user, $site );
4373
+
4374
+ if ( is_numeric( $site->license_id ) ) {
4375
+ $this->_license = $this->_get_license_by_id( $site->license_id );
4376
+ }
4377
+
4378
+ if ( $this->is_pending_activation() ) {
4379
+ // Remove pending activation sticky notice (if still exist).
4380
+ $this->_admin_notices->remove_sticky( 'activation_pending' );
4381
+
4382
+ // Remove plugin from pending activation mode.
4383
+ unset( $this->_storage->is_pending_activation );
4384
+
4385
+ if ( ! $this->is_paying() ) {
4386
+ $this->_admin_notices->add_sticky(
4387
+ sprintf( __fs( 'plugin-x-activation-message' ), '<b>' . $this->get_plugin_name() . '</b>' ),
4388
+ 'activation_complete'
4389
+ );
4390
+ }
4391
+ }
4392
+
4393
+ if ( $this->is_paying() && ! $this->is_premium() ) {
4394
+ $this->_admin_notices->add_sticky(
4395
+ sprintf(
4396
+ __fs( 'activation-with-plan-x-message' ),
4397
+ $this->_site->plan->title
4398
+ ) . ' ' . $this->_get_latest_download_link( sprintf(
4399
+ __fs( 'download-latest-x-version' ),
4400
+ $this->_site->plan->title
4401
+ ) ),
4402
+ 'plan_upgraded',
4403
+ __fs( 'yee-haw' ) . '!'
4404
+ );
4405
+ }
4406
+
4407
+ $plugin_id = fs_request_get( 'plugin_id', false );
4408
+
4409
+ // Store activation time ONLY for plugins (not add-ons).
4410
+ if ( ! is_numeric( $plugin_id ) || ( $plugin_id == $this->_plugin->id ) ) {
4411
+ $this->_storage->activation_timestamp = WP_FS__SCRIPT_START_TIME;
4412
+ }
4413
+
4414
+ if ( is_numeric( $plugin_id ) ) {
4415
+ if ( $plugin_id != $this->_plugin->id ) {
4416
+ // Add-on was installed - sync license right after install.
4417
+ if ( $redirect && fs_redirect( fs_nonce_url( $this->_get_admin_page_url(
4418
+ 'account',
4419
+ array(
4420
+ 'fs_action' => $this->_slug . '_sync_license',
4421
+ 'plugin_id' => $plugin_id
4422
+ )
4423
+ ), $this->_slug . '_sync_license' ) )
4424
+ ) {
4425
+ exit();
4426
+ }
4427
+
4428
+ }
4429
+ } else {
4430
+ // Reload the page with the keys.
4431
+ if ( $redirect && fs_redirect( $this->get_after_activation_url( 'after_connect_url' ) ) ) {
4432
+ exit();
4433
+ }
4434
+ }
4435
+ }
4436
+
4437
+ /**
4438
+ * Install plugin with new user information after approval.
4439
+ *
4440
+ * @author Vova Feldman (@svovaf)
4441
+ * @since 1.0.7
4442
+ */
4443
+ function _install_with_new_user() {
4444
+ if ( $this->is_registered() ) {
4445
+ return;
4446
+ }
4447
+
4448
+ if ( fs_request_is_action( $this->_slug . '_activate_new' ) ) {
4449
+ // check_admin_referer( $this->_slug . '_activate_new' );
4450
+
4451
+ $this->_admin_notices->remove_sticky( 'connect_account' );
4452
+
4453
+ if ( fs_request_has( 'user_secret_key' ) ) {
4454
+ $user = new FS_User();
4455
+ $user->id = fs_request_get( 'user_id' );
4456
+ $user->public_key = fs_request_get( 'user_public_key' );
4457
+ $user->secret_key = fs_request_get( 'user_secret_key' );
4458
+
4459
+ $this->_user = $user;
4460
+ $user_result = $this->get_api_user_scope()->get();
4461
+ $user = new FS_User( $user_result );
4462
+ $this->_user = $user;
4463
+
4464
+ $site = new FS_Site();
4465
+ $site->id = fs_request_get( 'install_id' );
4466
+ $site->public_key = fs_request_get( 'install_public_key' );
4467
+ $site->secret_key = fs_request_get( 'install_secret_key' );
4468
+
4469
+ $this->_site = $site;
4470
+ $site_result = $this->get_api_site_scope()->get();
4471
+ $site = new FS_Site( $site_result );
4472
+ $this->_site = $site;
4473
+
4474
+ $this->setup_account( $this->_user, $this->_site );
4475
+ } else if ( fs_request_has( 'pending_activation' ) ) {
4476
+ // Install must be activated via email since
4477
+ // user with the same email already exist.
4478
+ $this->_storage->is_pending_activation = true;
4479
+ $this->_add_pending_activation_notice( fs_request_get( 'user_email' ) );
4480
+
4481
+ // Reload the page with with pending activation message.
4482
+ if ( fs_redirect( $this->get_after_activation_url( 'after_pending_connect_url' ) ) ) {
4483
+ exit();
4484
+ }
4485
+ }
4486
+ }
4487
+ }
4488
+
4489
+ /**
4490
+ * Install plugin with current logged WP user info.
4491
+ *
4492
+ * @author Vova Feldman (@svovaf)
4493
+ * @since 1.0.7
4494
+ */
4495
+ function _install_with_current_user() {
4496
+ if ( $this->is_registered() ) {
4497
+ return;
4498
+ }
4499
+
4500
+ if ( fs_request_is_action( $this->_slug . '_activate_existing' ) && fs_request_is_post() ) {
4501
+ // check_admin_referer( 'activate_existing_' . $this->_plugin->public_key );
4502
+
4503
+ $this->_admin_notices->remove_sticky( 'connect_account' );
4504
+
4505
+ // Get current logged WP user.
4506
+ $current_user = wp_get_current_user();
4507
+
4508
+ // Find the relevant FS user by the email.
4509
+ $user = self::_get_user_by_email( $current_user->user_email );
4510
+
4511
+ // We have to set the user before getting user scope API handler.
4512
+ $this->_user = $user;
4513
+
4514
+ // Install the plugin.
4515
+ $install = $this->get_api_user_scope()->call(
4516
+ "/plugins/{$this->get_id()}/installs.json",
4517
+ 'post',
4518
+ $this->get_install_data_for_api( array(
4519
+ 'uid' => $this->get_anonymous_id(),
4520
+ ) )
4521
+ );
4522
+
4523
+ if ( isset( $install->error ) ) {
4524
+ $this->_admin_notices->add(
4525
+ sprintf( __fs( 'could-not-activate-x' ), $this->get_plugin_name() ) . ' ' .
4526
+ __fs( 'contact-us-with-error-message' ) . ' ' . '<b>' . $install->error->message . '</b>',
4527
+ __fs( 'oops' ) . '...',
4528
+ 'error'
4529
+ );
4530
+
4531
+ return;
4532
+ }
4533
+
4534
+ $site = new FS_Site( $install );
4535
+ $this->_site = $site;
4536
+ // $this->_enrich_site_plan( false );
4537
+
4538
+ // $this->_set_account( $user, $site );
4539
+ // $this->_sync_plans();
4540
+
4541
+ $this->setup_account( $this->_user, $this->_site );
4542
+ }
4543
+ }
4544
+
4545
+ /**
4546
+ * Tries to activate add-on account based on parent plugin info.
4547
+ *
4548
+ * @author Vova Feldman (@svovaf)
4549
+ * @since 1.0.6
4550
+ *
4551
+ * @param Freemius $parent_fs
4552
+ */
4553
+ private function _activate_addon_account( Freemius $parent_fs ) {
4554
+ if ( $this->is_registered() ) {
4555
+ // Already activated.
4556
+ return;
4557
+ }
4558
+
4559
+ // Activate add-on with parent plugin credentials.
4560
+ $addon_install = $parent_fs->get_api_site_scope()->call(
4561
+ "/addons/{$this->_plugin->id}/installs.json",
4562
+ 'post',
4563
+ $this->get_install_data_for_api( array(
4564
+ 'uid' => $this->get_anonymous_id(),
4565
+ ) )
4566
+ );
4567
+
4568
+ if ( isset( $addon_install->error ) ) {
4569
+ $this->_admin_notices->add(
4570
+ sprintf( __fs( 'could-not-activate-x' ), $this->get_plugin_name() ) . ' ' .
4571
+ __fs( 'contact-us-with-error-message' ) . ' ' . '<b>' . $addon_install->error->message . '</b>',
4572
+ __fs( 'oops' ) . '...',
4573
+ 'error'
4574
+ );
4575
+
4576
+ return;
4577
+ }
4578
+
4579
+ // First of all, set site info - otherwise we won't
4580
+ // be able to invoke API calls.
4581
+ $this->_site = new FS_Site( $addon_install );
4582
+
4583
+ // Sync add-on plans.
4584
+ $this->_sync_plans();
4585
+
4586
+ // Get site's current plan.
4587
+ $this->_site->plan = $this->_get_plan_by_id( $this->_site->plan->id );
4588
+
4589
+ // Get user information based on parent's plugin.
4590
+ $user = $parent_fs->get_user();
4591
+
4592
+ $this->_set_account( $user, $this->_site );
4593
+
4594
+ // Sync licenses.
4595
+ $this->_sync_licenses();
4596
+
4597
+ // Try to activate premium license.
4598
+ $this->_activate_license( true );
4599
+ }
4600
+
4601
+ #endregion ------------------------------------------------------------------
4602
+
4603
+ #region Admin Menu Items ------------------------------------------------------------------
4604
+
4605
+ private $_menu_items = array();
4606
+
4607
+ /**
4608
+ * @author Vova Feldman (@svovaf)
4609
+ * @since 1.0.7
4610
+ *
4611
+ * @return string
4612
+ */
4613
+ function get_menu_slug() {
4614
+ return $this->_menu->get_slug();
4615
+ }
4616
+
4617
+ /**
4618
+ * @author Vova Feldman (@svovaf)
4619
+ * @since 1.0.9
4620
+ */
4621
+ function _prepare_admin_menu() {
4622
+ if ( ! $this->is_on() ) {
4623
+ return;
4624
+ }
4625
+
4626
+ if ( ! $this->has_api_connectivity() && ! $this->enable_anonymous() ) {
4627
+ $this->_menu->remove_menu_item();
4628
+ } else {
4629
+ $this->add_submenu_items();
4630
+ $this->add_menu_action();
4631
+ }
4632
+ }
4633
+
4634
+ /**
4635
+ * Admin dashboard menu items modifications.
4636
+ *
4637
+ * NOTE: admin_menu action executed before admin_init.
4638
+ *
4639
+ * @author Vova Feldman (@svovaf)
4640
+ * @since 1.0.7
4641
+ *
4642
+ */
4643
+ private function add_menu_action() {
4644
+ if ( $this->is_activation_mode() ) {
4645
+ $this->override_plugin_menu_with_activation();
4646
+ } else {
4647
+ // If not registered try to install user.
4648
+ if ( ! $this->is_registered() &&
4649
+ fs_request_is_action( $this->_slug . '_activate_new' )
4650
+ ) {
4651
+ $this->_install_with_new_user();
4652
+ }
4653
+ }
4654
+ }
4655
+
4656
+ /**
4657
+ * @author Vova Feldman (@svovaf)
4658
+ * @since 1.0.1
4659
+ *
4660
+ * @return string
4661
+ */
4662
+ function _redirect_on_clicked_menu_link() {
4663
+ $this->_logger->entrance();
4664
+
4665
+ $page = strtolower( isset( $_REQUEST['page'] ) ? $_REQUEST['page'] : '' );
4666
+
4667
+ $this->_logger->log( 'page = ' . $page );
4668
+
4669
+ foreach ( $this->_menu_items as $priority => $items ) {
4670
+ foreach ( $items as $item ) {
4671
+ if ( isset( $item['url'] ) ) {
4672
+ if ( $page === $item['menu_slug'] ) {
4673
+ $this->_logger->log( 'Redirecting to ' . $item['url'] );
4674
+
4675
+ fs_redirect( $item['url'] );
4676
+ }
4677
+ }
4678
+ }
4679
+ }
4680
+ }
4681
+
4682
+ /**
4683
+ * Remove plugin's all admin menu items & pages, and replace with activation page.
4684
+ *
4685
+ * @author Vova Feldman (@svovaf)
4686
+ * @since 1.0.1
4687
+ */
4688
+ private function override_plugin_menu_with_activation() {
4689
+ $this->_logger->entrance();
4690
+
4691
+ $hook = false;
4692
+
4693
+ if ( $this->_menu->is_top_level() ) {
4694
+ $hook = $this->_menu->override_menu_item( array( &$this, '_connect_page_render' ) );
4695
+
4696
+ if ( false === $hook ) {
4697
+ // Create new menu item just for the opt-in.
4698
+ $hook = add_menu_page(
4699
+ $this->get_plugin_name(),
4700
+ $this->get_plugin_name(),
4701
+ 'manage_options',
4702
+ $this->_menu->get_slug(),
4703
+ array( &$this, '_connect_page_render' )
4704
+ );
4705
+ }
4706
+ } else {
4707
+ $menus = array( $this->_menu->get_parent_slug() );
4708
+
4709
+ if ( $this->_menu->is_override_exact() ) {
4710
+ // Make sure the current page is matching the activation page.
4711
+ $activation_url = strtolower( $this->get_activation_url() );
4712
+ $request_url = strtolower( $_SERVER['REQUEST_URI'] );
4713
+
4714
+ if ( parse_url( $activation_url, PHP_URL_PATH ) !== parse_url( $request_url, PHP_URL_PATH ) ) {
4715
+ // Different path - DO NOT OVERRIDE PAGE.
4716
+ return;
4717
+ }
4718
+
4719
+ $activation_url_params = array();
4720
+ parse_str( parse_url( $activation_url, PHP_URL_QUERY ), $activation_url_params );
4721
+
4722
+ $request_url_params = array();
4723
+ parse_str( parse_url( $request_url, PHP_URL_QUERY ), $request_url_params );
4724
+
4725
+
4726
+ foreach ( $activation_url_params as $key => $val ) {
4727
+ if ( ! isset( $request_url_params[ $key ] ) || $val != $request_url_params[ $key ] ) {
4728
+ // Not matching query string - DO NOT OVERRIDE PAGE.
4729
+ return;
4730
+ }
4731
+ }
4732
+ }
4733
+
4734
+ foreach ( $menus as $parent_slug ) {
4735
+ $hook = $this->_menu->override_submenu_action(
4736
+ $parent_slug,
4737
+ $this->_menu->get_raw_slug(),
4738
+ array( &$this, '_connect_page_render' )
4739
+ );
4740
+
4741
+ if ( false !== $hook ) {
4742
+ // Found plugin's submenu item.
4743
+ break;
4744
+ }
4745
+ }
4746
+ }
4747
+
4748
+ if ( $this->_menu->is_activation_page() ) {
4749
+ // Clean admin page from distracting content.
4750
+ $this->_clean_admin_content_section();
4751
+ }
4752
+
4753
+ if ( false !== $hook ) {
4754
+ if ( fs_request_is_action( $this->_slug . '_activate_existing' ) ) {
4755
+ add_action( "load-$hook", array( &$this, '_install_with_current_user' ) );
4756
+ } else if ( fs_request_is_action( $this->_slug . '_activate_new' ) ) {
4757
+ add_action( "load-$hook", array( &$this, '_install_with_new_user' ) );
4758
+ }
4759
+ }
4760
+ }
4761
+
4762
+ /**
4763
+ * @author Vova Feldman (@svovaf)
4764
+ * @since 1.0.0
4765
+ *
4766
+ * @return string
4767
+ */
4768
+ private function get_top_level_menu_slug() {
4769
+ return ( $this->is_addon() ?
4770
+ $this->get_parent_instance()->_menu->get_top_level_menu_slug() :
4771
+ $this->_menu->get_top_level_menu_slug() );
4772
+ }
4773
+
4774
+ /**
4775
+ * Add default Freemius menu items.
4776
+ *
4777
+ * @author Vova Feldman (@svovaf)
4778
+ * @since 1.0.0
4779
+ */
4780
+ private function add_submenu_items() {
4781
+ $this->_logger->entrance();
4782
+
4783
+ $this->do_action( 'before_admin_menu_init' );
4784
+
4785
+ if ( ! $this->is_addon() ) {
4786
+ if ( $this->is_registered() || $this->is_anonymous() ) {
4787
+ if ( $this->is_registered() ) {
4788
+ // Add user account page.
4789
+ $this->add_submenu_item(
4790
+ __fs( 'account' ),
4791
+ array( &$this, '_account_page_render' ),
4792
+ $this->get_plugin_name() . ' &ndash; ' . __fs( 'account' ),
4793
+ 'manage_options',
4794
+ 'account',
4795
+ array( &$this, '_account_page_load' ),
4796
+ WP_FS__DEFAULT_PRIORITY,
4797
+ $this->_menu->is_submenu_item_visible( 'account' )
4798
+ );
4799
+ }
4800
+
4801
+ // Add contact page.
4802
+ $this->add_submenu_item(
4803
+ __fs( 'contact-us' ),
4804
+ array( &$this, '_contact_page_render' ),
4805
+ $this->get_plugin_name() . ' &ndash; ' . __fs( 'contact-us' ),
4806
+ 'manage_options',
4807
+ 'contact',
4808
+ array( &$this, '_clean_admin_content_section' ),
4809
+ WP_FS__DEFAULT_PRIORITY,
4810
+ $this->_menu->is_submenu_item_visible( 'contact' )
4811
+ );
4812
+
4813
+ if ( $this->_has_addons() ) {
4814
+ $this->add_submenu_item(
4815
+ __fs( 'add-ons' ),
4816
+ array( &$this, '_addons_page_render' ),
4817
+ $this->get_plugin_name() . ' &ndash; ' . __fs( 'add-ons' ),
4818
+ 'manage_options',
4819
+ 'addons',
4820
+ array( &$this, '_addons_page_load' ),
4821
+ WP_FS__LOWEST_PRIORITY - 1,
4822
+ $this->_menu->is_submenu_item_visible( 'addons' )
4823
+ );
4824
+ }
4825
+
4826
+ // Add upgrade/pricing page.
4827
+ $this->add_submenu_item(
4828
+ ( $this->is_paying() ? __fs( 'pricing' ) : __fs( 'upgrade' ) . '&nbsp;&nbsp;&#x27a4;' ),
4829
+ array( &$this, '_pricing_page_render' ),
4830
+ $this->get_plugin_name() . ' &ndash; ' . __fs( 'pricing' ),
4831
+ 'manage_options',
4832
+ 'pricing',
4833
+ array( &$this, '_clean_admin_content_section' ),
4834
+ WP_FS__LOWEST_PRIORITY,
4835
+ // If user don't have paid plans, add pricing page
4836
+ // to support add-ons checkout but don't add the submenu item.
4837
+ $this->_menu->is_submenu_item_visible( 'pricing' ) && ( $this->has_paid_plan() || ( isset( $_GET['page'] ) && $this->_menu->get_slug( 'pricing' ) == $_GET['page'] ) )
4838
+ );
4839
+ }
4840
+ }
4841
+
4842
+
4843
+ if ( 0 < count( $this->_menu_items ) ) {
4844
+ if ( ! $this->_menu->is_top_level() ) {
4845
+ fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
4846
+
4847
+ // Append submenu items right after the plugin's submenu item.
4848
+ $this->order_sub_submenu_items();
4849
+ } else {
4850
+ // Append submenu items.
4851
+ $this->embed_submenu_items();
4852
+ }
4853
+ }
4854
+ }
4855
+
4856
+ /**
4857
+ * Moved the actual submenu item additions to a separated function,
4858
+ * in order to support sub-submenu items when the plugin's settings
4859
+ * only have a submenu and not top-level menu item.
4860
+ *
4861
+ * @author Vova Feldman (@svovaf)
4862
+ * @since 1.1.4
4863
+ */
4864
+ private function embed_submenu_items() {
4865
+ $item_template = $this->_menu->is_top_level() ?
4866
+ '<span class="fs-submenu-item">%s</span>' :
4867
+ '<span class="fs-submenu-item fs-sub">%s</span>';
4868
+
4869
+ ksort( $this->_menu_items );
4870
+
4871
+ foreach ( $this->_menu_items as $priority => $items ) {
4872
+ foreach ( $items as $item ) {
4873
+ if ( ! isset( $item['url'] ) ) {
4874
+ $hook = add_submenu_page(
4875
+ $item['show_submenu'] ?
4876
+ $this->get_top_level_menu_slug() :
4877
+ null,
4878
+ $item['page_title'],
4879
+ sprintf( $item_template, $item['menu_title'] ),
4880
+ $item['capability'],
4881
+ $item['menu_slug'],
4882
+ $item['render_function']
4883
+ );
4884
+
4885
+ if ( false !== $item['before_render_function'] ) {
4886
+ add_action( "load-$hook", $item['before_render_function'] );
4887
+ }
4888
+ } else {
4889
+ add_submenu_page(
4890
+ $this->get_top_level_menu_slug(),
4891
+ $item['page_title'],
4892
+ sprintf( $item_template, $item['menu_title'] ),
4893
+ $item['capability'],
4894
+ $item['menu_slug'],
4895
+ array( $this, '' )
4896
+ );
4897
+ }
4898
+ }
4899
+ }
4900
+ }
4901
+
4902
+ /**
4903
+ * Re-order the submenu items so all Freemius added new submenu items
4904
+ * are added right after the plugin's settings submenu item.
4905
+ *
4906
+ * @author Vova Feldman (@svovaf)
4907
+ * @since 1.1.4
4908
+ */
4909
+ private function order_sub_submenu_items() {
4910
+ global $submenu;
4911
+
4912
+ $top_level_menu = &$submenu[ $this->_menu->get_top_level_menu_slug() ];
4913
+
4914
+ $all_submenu_items_after = array();
4915
+
4916
+ $found_submenu_item = false;
4917
+
4918
+ foreach ( $top_level_menu as $submenu_id => $meta ) {
4919
+ if ( $found_submenu_item ) {
4920
+ // Remove all submenu items after the plugin's submenu item.
4921
+ $all_submenu_items_after[] = $meta;
4922
+ unset( $top_level_menu[ $submenu_id ] );
4923
+ }
4924
+
4925
+ if ( $this->_menu->get_raw_slug() === $meta[2] ) {
4926
+ // Found the submenu item, put all below.
4927
+ $found_submenu_item = true;
4928
+ continue;
4929
+ }
4930
+ }
4931
+
4932
+ // Embed all plugin's new submenu items.
4933
+ $this->embed_submenu_items();
4934
+
4935
+ // Start with specially high number to make sure it's appended.
4936
+ $i = 10000;
4937
+ foreach ( $all_submenu_items_after as $meta ) {
4938
+ $top_level_menu[ $i ] = $meta;
4939
+ $i ++;
4940
+ }
4941
+
4942
+ // Sort submenu items.
4943
+ ksort( $top_level_menu );
4944
+ }
4945
+
4946
+ function _add_default_submenu_items() {
4947
+ if ( ! $this->is_on() ) {
4948
+ return;
4949
+ }
4950
+
4951
+ if ( $this->is_registered() ) {
4952
+ if ( $this->_menu->is_submenu_item_visible( 'support' ) ) {
4953
+ $this->add_submenu_link_item(
4954
+ __fs( 'support-forum' ),
4955
+ 'https://wordpress.org/support/plugin/' . $this->_slug,
4956
+ 'wp-support-forum',
4957
+ 'read',
4958
+ 50
4959
+ );
4960
+ }
4961
+ }
4962
+ }
4963
+
4964
+ /**
4965
+ * @author Vova Feldman (@svovaf)
4966
+ * @since 1.0.1
4967
+ *
4968
+ * @param string $menu_title
4969
+ * @param callable $render_function
4970
+ * @param bool|string $page_title
4971
+ * @param string $capability
4972
+ * @param bool|string $menu_slug
4973
+ * @param bool|callable $before_render_function
4974
+ * @param int $priority
4975
+ * @param bool $show_submenu
4976
+ */
4977
+ function add_submenu_item(
4978
+ $menu_title,
4979
+ $render_function,
4980
+ $page_title = false,
4981
+ $capability = 'manage_options',
4982
+ $menu_slug = false,
4983
+ $before_render_function = false,
4984
+ $priority = WP_FS__DEFAULT_PRIORITY,
4985
+ $show_submenu = true
4986
+ ) {
4987
+ $this->_logger->entrance( 'Title = ' . $menu_title );
4988
+
4989
+ if ( $this->is_addon() ) {
4990
+ $parent_fs = $this->get_parent_instance();
4991
+
4992
+ if ( is_object( $parent_fs ) ) {
4993
+ $parent_fs->add_submenu_item(
4994
+ $menu_title,
4995
+ $render_function,
4996
+ $page_title,
4997
+ $capability,
4998
+ $menu_slug,
4999
+ $before_render_function,
5000
+ $priority,
5001
+ $show_submenu
5002
+ );
5003
+
5004
+ return;
5005
+ }
5006
+ }
5007
+
5008
+ if ( ! isset( $this->_menu_items[ $priority ] ) ) {
5009
+ $this->_menu_items[ $priority ] = array();
5010
+ }
5011
+
5012
+ $this->_menu_items[ $priority ][] = array(
5013
+ 'page_title' => is_string( $page_title ) ? $page_title : $menu_title,
5014
+ 'menu_title' => $menu_title,
5015
+ 'capability' => $capability,
5016
+ 'menu_slug' => $this->_menu->get_slug( is_string( $menu_slug ) ? $menu_slug : strtolower( $menu_title ) ),
5017
+ 'render_function' => $render_function,
5018
+ 'before_render_function' => $before_render_function,
5019
+ 'show_submenu' => $show_submenu,
5020
+ );
5021
+ }
5022
+
5023
+ /**
5024
+ * @author Vova Feldman (@svovaf)
5025
+ * @since 1.0.1
5026
+ *
5027
+ * @param string $menu_title
5028
+ * @param string $url
5029
+ * @param bool $menu_slug
5030
+ * @param string $capability
5031
+ * @param int $priority
5032
+ *
5033
+ */
5034
+ function add_submenu_link_item(
5035
+ $menu_title,
5036
+ $url,
5037
+ $menu_slug = false,
5038
+ $capability = 'read',
5039
+ $priority = WP_FS__DEFAULT_PRIORITY
5040
+ ) {
5041
+ $this->_logger->entrance( 'Title = ' . $menu_title . '; Url = ' . $url );
5042
+
5043
+ if ( $this->is_addon() ) {
5044
+ $parent_fs = $this->get_parent_instance();
5045
+
5046
+ if ( is_object( $parent_fs ) ) {
5047
+ $parent_fs->add_submenu_link_item(
5048
+ $menu_title,
5049
+ $url,
5050
+ $menu_slug,
5051
+ $capability,
5052
+ $priority
5053
+ );
5054
+
5055
+ return;
5056
+ }
5057
+ }
5058
+
5059
+ if ( ! isset( $this->_menu_items[ $priority ] ) ) {
5060
+ $this->_menu_items[ $priority ] = array();
5061
+ }
5062
+
5063
+ $this->_menu_items[ $priority ][] = array(
5064
+ 'menu_title' => $menu_title,
5065
+ 'capability' => $capability,
5066
+ 'menu_slug' => $this->_menu->get_slug( is_string( $menu_slug ) ? $menu_slug : strtolower( $menu_title ) ),
5067
+ 'url' => $url,
5068
+ 'page_title' => $menu_title,
5069
+ 'render_function' => 'fs_dummy',
5070
+ 'before_render_function' => '',
5071
+ );
5072
+ }
5073
+
5074
+ #endregion ------------------------------------------------------------------
5075
+
5076
+ /* Actions / Hooks / Filters
5077
+ ------------------------------------------------------------------------------------------------------------------*/
5078
+ /**
5079
+ * Do action, specific for the current context plugin.
5080
+ *
5081
+ * @author Vova Feldman (@svovaf)
5082
+ * @since 1.0.1
5083
+ *
5084
+ * @param string $tag The name of the action to be executed.
5085
+ * @param mixed $arg,... Optional. Additional arguments which are passed on to the
5086
+ * functions hooked to the action. Default empty.
5087
+ *
5088
+ * @uses do_action()
5089
+ */
5090
+ function do_action( $tag, $arg = '' ) {
5091
+ $this->_logger->entrance( $tag );
5092
+
5093
+ $args = func_get_args();
5094
+
5095
+ call_user_func_array( 'do_action', array_merge(
5096
+ array( 'fs_' . $tag . '_' . $this->_slug ),
5097
+ array_slice( $args, 1 ) )
5098
+ );
5099
+ }
5100
+
5101
+ /**
5102
+ * Add action, specific for the current context plugin.
5103
+ *
5104
+ * @author Vova Feldman (@svovaf)
5105
+ * @since 1.0.1
5106
+ *
5107
+ * @param string $tag
5108
+ * @param callable $function_to_add
5109
+ * @param int $priority
5110
+ * @param int $accepted_args
5111
+ *
5112
+ * @uses add_action()
5113
+ */
5114
+ function add_action( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
5115
+ $this->_logger->entrance( $tag );
5116
+
5117
+ add_action( 'fs_' . $tag . '_' . $this->_slug, $function_to_add, $priority, $accepted_args );
5118
+ }
5119
+
5120
+ /**
5121
+ * Apply filter, specific for the current context plugin.
5122
+ *
5123
+ * @author Vova Feldman (@svovaf)
5124
+ * @since 1.0.9
5125
+ *
5126
+ * @param string $tag The name of the filter hook.
5127
+ * @param mixed $value The value on which the filters hooked to `$tag` are applied on.
5128
+ *
5129
+ * @return mixed The filtered value after all hooked functions are applied to it.
5130
+ *
5131
+ * @uses apply_filters()
5132
+ */
5133
+ function apply_filters( $tag, $value ) {
5134
+ $this->_logger->entrance( $tag );
5135
+
5136
+ $args = func_get_args();
5137
+
5138
+ return call_user_func_array( 'apply_filters', array_merge(
5139
+ array( 'fs_' . $tag . '_' . $this->_slug ),
5140
+ array_slice( $args, 1 ) )
5141
+ );
5142
+ }
5143
+
5144
+ /**
5145
+ * Add filter, specific for the current context plugin.
5146
+ *
5147
+ * @author Vova Feldman (@svovaf)
5148
+ * @since 1.0.9
5149
+ *
5150
+ * @param string $tag
5151
+ * @param callable $function_to_add
5152
+ * @param int $priority
5153
+ * @param int $accepted_args
5154
+ *
5155
+ * @uses add_filter()
5156
+ */
5157
+ function add_filter( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
5158
+ $this->_logger->entrance( $tag );
5159
+
5160
+ add_filter( 'fs_' . $tag . '_' . $this->_slug, $function_to_add, $priority, $accepted_args );
5161
+ }
5162
+
5163
+ /**
5164
+ * Check if has filter.
5165
+ *
5166
+ * @author Vova Feldman (@svovaf)
5167
+ * @since 1.1.4
5168
+ *
5169
+ * @param string $tag
5170
+ * @param callable|bool $function_to_check Optional. The callback to check for. Default false.
5171
+ */
5172
+ function has_filter( $tag, $function_to_check = false ) {
5173
+ $this->_logger->entrance( $tag );
5174
+
5175
+ return has_filter( 'fs_' . $tag . '_' . $this->_slug, $function_to_check );
5176
+ }
5177
+
5178
+ /* Account Page
5179
+ ------------------------------------------------------------------------------------------------------------------*/
5180
+ /**
5181
+ * Update site information.
5182
+ *
5183
+ * @author Vova Feldman (@svovaf)
5184
+ * @since 1.0.1
5185
+ *
5186
+ * @param bool $store Flush to Database if true.
5187
+ */
5188
+ private function _store_site( $store = true ) {
5189
+ $this->_logger->entrance();
5190
+
5191
+ $encrypted_site = clone $this->_site;
5192
+ $encrypted_site->plan = $this->_encrypt_entity( $this->_site->plan );
5193
+
5194
+ $sites = self::get_all_sites();
5195
+ $sites[ $this->_slug ] = $encrypted_site;
5196
+ self::$_accounts->set_option( 'sites', $sites, $store );
5197
+ }
5198
+
5199
+ /**
5200
+ * Update plugin's plans information.
5201
+ *
5202
+ * @author Vova Feldman (@svovaf)
5203
+ * @since 1.0.2
5204
+ *
5205
+ * @param bool $store Flush to Database if true.
5206
+ */
5207
+ private function _store_plans( $store = true ) {
5208
+ $this->_logger->entrance();
5209
+
5210
+ $plans = self::get_all_plans();
5211
+
5212
+ // Copy plans.
5213
+ $encrypted_plans = array();
5214
+ for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
5215
+ $encrypted_plans[] = $this->_encrypt_entity( $this->_plans[ $i ] );
5216
+ }
5217
+
5218
+ $plans[ $this->_slug ] = $encrypted_plans;
5219
+ self::$_accounts->set_option( 'plans', $plans, $store );
5220
+ }
5221
+
5222
+ /**
5223
+ * Update user's plugin licenses.
5224
+ *
5225
+ * @author Vova Feldman (@svovaf)
5226
+ * @since 1.0.5
5227
+ *
5228
+ * @param bool $store
5229
+ * @param string|bool $plugin_slug
5230
+ * @param FS_Plugin_License[] $licenses
5231
+ */
5232
+ private function _store_licenses( $store = true, $plugin_slug = false, $licenses = array() ) {
5233
+ $this->_logger->entrance();
5234
+
5235
+ $all_licenses = self::get_all_licenses();
5236
+
5237
+ if ( ! is_string( $plugin_slug ) ) {
5238
+ $plugin_slug = $this->_slug;
5239
+ $licenses = $this->_licenses;
5240
+ }
5241
+
5242
+ if ( ! isset( $all_licenses[ $plugin_slug ] ) ) {
5243
+ $all_licenses[ $plugin_slug ] = array();
5244
+ }
5245
+
5246
+ $all_licenses[ $plugin_slug ][ $this->_user->id ] = $licenses;
5247
+
5248
+ self::$_accounts->set_option( 'licenses', $all_licenses, $store );
5249
+ }
5250
+
5251
+ /**
5252
+ * Update user information.
5253
+ *
5254
+ * @author Vova Feldman (@svovaf)
5255
+ * @since 1.0.1
5256
+ *
5257
+ * @param bool $store Flush to Database if true.
5258
+ */
5259
+ private function _store_user( $store = true ) {
5260
+ $this->_logger->entrance();
5261
+
5262
+ $users = self::get_all_users();
5263
+ $users[ $this->_user->id ] = $this->_user;
5264
+ self::$_accounts->set_option( 'users', $users, $store );
5265
+ }
5266
+
5267
+ /**
5268
+ * Update new updates information.
5269
+ *
5270
+ * @author Vova Feldman (@svovaf)
5271
+ * @since 1.0.4
5272
+ *
5273
+ * @param FS_Plugin_Tag|null $update
5274
+ * @param bool $store Flush to Database if true.
5275
+ * @param bool|number $plugin_id
5276
+ */
5277
+ private function _store_update( $update, $store = true, $plugin_id = false ) {
5278
+ $this->_logger->entrance();
5279
+
5280
+ if ( $update instanceof FS_Plugin_Tag ) {
5281
+ $update->updated = time();
5282
+ }
5283
+
5284
+ if ( ! is_numeric( $plugin_id ) ) {
5285
+ $plugin_id = $this->_plugin->id;
5286
+ }
5287
+
5288
+ $updates = self::get_all_updates();
5289
+ $updates[ $plugin_id ] = $update;
5290
+ self::$_accounts->set_option( 'updates', $updates, $store );
5291
+ }
5292
+
5293
+ /**
5294
+ * Update new updates information.
5295
+ *
5296
+ * @author Vova Feldman (@svovaf)
5297
+ * @since 1.0.6
5298
+ *
5299
+ * @param FS_Plugin[] $plugin_addons
5300
+ * @param bool $store Flush to Database if true.
5301
+ */
5302
+ private function _store_addons( $plugin_addons, $store = true ) {
5303
+ $this->_logger->entrance();
5304
+
5305
+ $addons = self::get_all_addons();
5306
+ $addons[ $this->_plugin->id ] = $plugin_addons;
5307
+ self::$_accounts->set_option( 'addons', $addons, $store );
5308
+ }
5309
+
5310
+ /**
5311
+ * Delete plugin's associated add-ons.
5312
+ *
5313
+ * @author Vova Feldman (@svovaf)
5314
+ * @since 1.0.8
5315
+ *
5316
+ * @param bool $store
5317
+ *
5318
+ * @return bool
5319
+ */
5320
+ private function _delete_account_addons( $store = true ) {
5321
+ $all_addons = self::get_all_account_addons();
5322
+
5323
+ if ( ! isset( $all_addons[ $this->_plugin->id ] ) ) {
5324
+ return false;
5325
+ }
5326
+
5327
+ unset( $all_addons[ $this->_plugin->id ] );
5328
+
5329
+ self::$_accounts->set_option( 'account_addons', $all_addons, $store );
5330
+
5331
+ return true;
5332
+ }
5333
+
5334
+ /**
5335
+ * Update account add-ons list.
5336
+ *
5337
+ * @author Vova Feldman (@svovaf)
5338
+ * @since 1.0.6
5339
+ *
5340
+ * @param FS_Plugin[] $addons
5341
+ * @param bool $store Flush to Database if true.
5342
+ */
5343
+ private function _store_account_addons( $addons, $store = true ) {
5344
+ $this->_logger->entrance();
5345
+
5346
+ $all_addons = self::get_all_account_addons();
5347
+ $all_addons[ $this->_plugin->id ] = $addons;
5348
+ self::$_accounts->set_option( 'account_addons', $all_addons, $store );
5349
+ }
5350
+
5351
+ /**
5352
+ * Store account params in the Database.
5353
+ *
5354
+ * @author Vova Feldman (@svovaf)
5355
+ * @since 1.0.1
5356
+ */
5357
+ private function _store_account() {
5358
+ $this->_logger->entrance();
5359
+
5360
+ $this->_store_site( false );
5361
+ $this->_store_user( false );
5362
+ $this->_store_plans( false );
5363
+ $this->_store_licenses( false );
5364
+
5365
+ self::$_accounts->store();
5366
+ }
5367
+
5368
+ /**
5369
+ * Sync user's information.
5370
+ *
5371
+ * @author Vova Feldman (@svovaf)
5372
+ * @since 1.0.3
5373
+ * @uses FS_Api
5374
+ */
5375
+ private function _handle_account_user_sync() {
5376
+ $this->_logger->entrance();
5377
+
5378
+ $api = $this->get_api_user_scope();
5379
+
5380
+ // Get user's information.
5381
+ $user = $api->get( '/', true );
5382
+
5383
+ if ( isset( $user->id ) ) {
5384
+ $this->_user->first = $user->first;
5385
+ $this->_user->last = $user->last;
5386
+ $this->_user->email = $user->email;
5387
+
5388
+ if ( ( ! isset( $this->_user->is_verified ) || false === $this->_user->is_verified ) && $user->is_verified ) {
5389
+ $this->_user->is_verified = $user->is_verified;
5390
+
5391
+ $this->do_action( 'account_email_verified', $user->email );
5392
+
5393
+ $this->_admin_notices->add(
5394
+ __fs( 'email-verified-message' ),
5395
+ __fs( 'right-on' ) . '!'
5396
+ );
5397
+ }
5398
+
5399
+ // Flush user details to DB.
5400
+ $this->_store_user();
5401
+
5402
+ $this->do_action( 'after_account_user_sync', $user );
5403
+ }
5404
+ }
5405
+
5406
+ /**
5407
+ * @author Vova Feldman (@svovaf)
5408
+ * @since 1.0.5
5409
+ * @uses FS_Api
5410
+ *
5411
+ * @param bool $flush
5412
+ *
5413
+ * @return object|\FS_Site
5414
+ */
5415
+ private function _fetch_site( $flush = false ) {
5416
+ $this->_logger->entrance();
5417
+ $api = $this->get_api_site_scope();
5418
+
5419
+ $site = $api->get( '/', $flush );
5420
+
5421
+ if ( ! isset( $site->error ) ) {
5422
+ $site = new FS_Site( $site );
5423
+ $site->slug = $this->_slug;
5424
+ $site->version = $this->get_plugin_version();
5425
+ }
5426
+
5427
+ return $site;
5428
+ }
5429
+
5430
+ /**
5431
+ * @param bool $store
5432
+ *
5433
+ * @return FS_Plugin_Plan|object|false
5434
+ */
5435
+ private function _enrich_site_plan( $store = true ) {
5436
+ // Try to load plan from local cache.
5437
+ $plan = $this->_get_plan_by_id( $this->_site->plan->id );
5438
+
5439
+ if ( false === $plan ) {
5440
+ $plan = $this->_fetch_site_plan();
5441
+ }
5442
+
5443
+ if ( $plan instanceof FS_Plugin_Plan ) {
5444
+ $this->_update_plan( $plan, $store );
5445
+ }
5446
+
5447
+ return $plan;
5448
+ }
5449
+
5450
+ /**
5451
+ * @author Vova Feldman (@svovaf)
5452
+ * @since 1.0.9
5453
+ * @uses FS_Api
5454
+ *
5455
+ * @param bool $store
5456
+ *
5457
+ * @return FS_Plugin_Plan|object|false
5458
+ */
5459
+ private function _enrich_site_trial_plan( $store = true ) {
5460
+ // Try to load plan from local cache.
5461
+ $trial_plan = $this->_get_plan_by_id( $this->_site->trial_plan_id );
5462
+
5463
+ if ( false === $trial_plan ) {
5464
+ $trial_plan = $this->_fetch_site_plan( $this->_site->trial_plan_id );
5465
+ }
5466
+
5467
+ if ( $trial_plan instanceof FS_Plugin_Plan ) {
5468
+ $this->_storage->store( 'trial_plan', $trial_plan, $store );
5469
+ }
5470
+
5471
+ return $trial_plan;
5472
+ }
5473
+
5474
+ /**
5475
+ * @author Vova Feldman (@svovaf)
5476
+ * @since 1.0.9
5477
+ * @uses FS_Api
5478
+ *
5479
+ * @param number|bool $license_id
5480
+ *
5481
+ * @return FS_Subscription|object|bool
5482
+ */
5483
+ private function _fetch_site_license_subscription( $license_id = false ) {
5484
+ $this->_logger->entrance();
5485
+ $api = $this->get_api_site_scope();
5486
+
5487
+ if ( ! is_numeric( $license_id ) ) {
5488
+ $license_id = $this->_license->id;
5489
+ }
5490
+
5491
+ $result = $api->get( "/licenses/{$license_id}/subscriptions.json", true );
5492
+
5493
+ return ! isset( $result->error ) ?
5494
+ ( ( is_array( $result->subscriptions ) && 0 < count( $result->subscriptions ) ) ?
5495
+ new FS_Subscription( $result->subscriptions[0] ) :
5496
+ false
5497
+ ) :
5498
+ $result;
5499
+ }
5500
+
5501
+ /**
5502
+ * @author Vova Feldman (@svovaf)
5503
+ * @since 1.0.4
5504
+ * @uses FS_Api
5505
+ *
5506
+ * @param number|bool $plan_id
5507
+ *
5508
+ * @return FS_Plugin_Plan|object
5509
+ */
5510
+ private function _fetch_site_plan( $plan_id = false ) {
5511
+ $this->_logger->entrance();
5512
+ $api = $this->get_api_site_scope();
5513
+
5514
+ if ( ! is_numeric( $plan_id ) ) {
5515
+ $plan_id = $this->_site->plan->id;
5516
+ }
5517
+
5518
+ $plan = $api->get( "/plans/{$plan_id}.json", true );
5519
+
5520
+ return ! isset( $plan->error ) ? new FS_Plugin_Plan( $plan ) : $plan;
5521
+ }
5522
+
5523
+ /**
5524
+ * @author Vova Feldman (@svovaf)
5525
+ * @since 1.0.5
5526
+ * @uses FS_Api
5527
+ *
5528
+ * @return FS_Plugin_Plan[]|object
5529
+ */
5530
+ private function _fetch_plugin_plans() {
5531
+ $this->_logger->entrance();
5532
+ $api = $this->get_api_site_scope();
5533
+
5534
+ $result = $api->get( '/plans.json', true );
5535
+
5536
+ if ( ! $this->is_api_error( $result ) ) {
5537
+ for ( $i = 0, $len = count( $result->plans ); $i < $len; $i ++ ) {
5538
+ $result->plans[ $i ] = new FS_Plugin_Plan( $result->plans[ $i ] );
5539
+ }
5540
+
5541
+ $result = $result->plans;
5542
+ }
5543
+
5544
+ return $result;
5545
+ }
5546
+
5547
+ /**
5548
+ * @author Vova Feldman (@svovaf)
5549
+ * @since 1.0.5
5550
+ * @uses FS_Api
5551
+ *
5552
+ * @param number|bool $plugin_id
5553
+ *
5554
+ * @return FS_Plugin_License[]|object
5555
+ */
5556
+ private function _fetch_licenses( $plugin_id = false ) {
5557
+ $this->_logger->entrance();
5558
+
5559
+ $api = $this->get_api_user_scope();
5560
+
5561
+ if ( ! is_numeric( $plugin_id ) ) {
5562
+ $plugin_id = $this->_plugin->id;
5563
+ }
5564
+
5565
+ $result = $api->get( "/plugins/{$plugin_id}/licenses.json", true );
5566
+
5567
+ if ( ! isset( $result->error ) ) {
5568
+ for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {
5569
+ $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );
5570
+ }
5571
+
5572
+ $result = $result->licenses;
5573
+ }
5574
+
5575
+ return $result;
5576
+ }
5577
+
5578
+ /**
5579
+ * @author Vova Feldman (@svovaf)
5580
+ * @since 1.0.4
5581
+ *
5582
+ * @param FS_Plugin_Plan $plan
5583
+ * @param bool $store
5584
+ */
5585
+ private function _update_plan( $plan, $store = false ) {
5586
+ $this->_logger->entrance();
5587
+
5588
+ $this->_site->plan = $plan;
5589
+ $this->_store_site( $store );
5590
+ }
5591
+
5592
+ /**
5593
+ * @author Vova Feldman (@svovaf)
5594
+ * @since 1.0.5
5595
+ *
5596
+ * @param FS_Plugin_License[] $licenses
5597
+ * @param string|bool $plugin_slug
5598
+ */
5599
+ private function _update_licenses( $licenses, $plugin_slug = false ) {
5600
+ $this->_logger->entrance();
5601
+
5602
+ if ( is_array( $licenses ) ) {
5603
+ for ( $i = 0, $len = count( $licenses ); $i < $len; $i ++ ) {
5604
+ $licenses[ $i ]->updated = time();
5605
+ }
5606
+ }
5607
+
5608
+ if ( ! is_string( $plugin_slug ) ) {
5609
+ $this->_licenses = $licenses;
5610
+ }
5611
+
5612
+ $this->_store_licenses( true, $plugin_slug, $licenses );
5613
+ }
5614
+
5615
+ /**
5616
+ * @author Vova Feldman (@svovaf)
5617
+ * @since 1.0.4
5618
+ *
5619
+ * @param bool|number $plugin_id
5620
+ *
5621
+ * @return object|false New plugin tag info if exist.
5622
+ */
5623
+ private function _fetch_newer_version( $plugin_id = false ) {
5624
+ $latest_tag = $this->_fetch_latest_version( $plugin_id );
5625
+
5626
+ if ( ! is_object( $latest_tag ) ) {
5627
+ return false;
5628
+ }
5629
+
5630
+ // Check if version is actually newer.
5631
+ $has_new_version =
5632
+ // If it's an non-installed add-on then always return latest.
5633
+ ( $this->_is_addon_id( $plugin_id ) && ! $this->is_addon_activated( $plugin_id ) ) ||
5634
+ // Compare versions.
5635
+ version_compare( $this->get_plugin_version(), $latest_tag->version, '<' );
5636
+
5637
+ $this->_logger->departure( $has_new_version ? 'Found newer plugin version ' . $latest_tag->version : 'No new version' );
5638
+
5639
+ return $has_new_version ? $latest_tag : false;
5640
+ }
5641
+
5642
+ /**
5643
+ * @author Vova Feldman (@svovaf)
5644
+ * @since 1.0.5
5645
+ *
5646
+ * @param bool|number $plugin_id
5647
+ *
5648
+ * @return bool|FS_Plugin_Tag
5649
+ */
5650
+ function get_update( $plugin_id = false ) {
5651
+ $this->_logger->entrance();
5652
+
5653
+ if ( ! is_numeric( $plugin_id ) ) {
5654
+ $plugin_id = $this->_plugin->id;
5655
+ }
5656
+
5657
+ $this->_check_updates( true, $plugin_id );
5658
+ $updates = $this->get_all_updates();
5659
+
5660
+ return isset( $updates[ $plugin_id ] ) && is_object( $updates[ $plugin_id ] ) ? $updates[ $plugin_id ] : false;
5661
+ }
5662
+
5663
+ /**
5664
+ * Check if site assigned with active license.
5665
+ *
5666
+ * @author Vova Feldman (@svovaf)
5667
+ * @since 1.0.6
5668
+ */
5669
+ function has_active_license() {
5670
+ return (
5671
+ is_object( $this->_license ) &&
5672
+ is_numeric( $this->_license->id ) &&
5673
+ ! $this->_license->is_expired()
5674
+ );
5675
+ }
5676
+
5677
+ /**
5678
+ * Check if site assigned with license with enabled features.
5679
+ *
5680
+ * @author Vova Feldman (@svovaf)
5681
+ * @since 1.0.6
5682
+ *
5683
+ * @return bool
5684
+ */
5685
+ function has_features_enabled_license() {
5686
+ return (
5687
+ is_object( $this->_license ) &&
5688
+ is_numeric( $this->_license->id ) &&
5689
+ $this->_license->is_features_enabled()
5690
+ );
5691
+ }
5692
+
5693
+ /**
5694
+ * Sync site's plan.
5695
+ *
5696
+ * @author Vova Feldman (@svovaf)
5697
+ * @since 1.0.3
5698
+ *
5699
+ * @uses FS_Api
5700
+ *
5701
+ * @param bool $background Hints the method if it's a background sync. If false, it means that was initiated by
5702
+ * the admin.
5703
+ */
5704
+ private function _sync_license( $background = false ) {
5705
+ $this->_logger->entrance();
5706
+
5707
+ $plugin_id = fs_request_get( 'plugin_id', $this->get_id() );
5708
+
5709
+ $is_addon_sync = ( ! $this->_plugin->is_addon() && $plugin_id != $this->get_id() );
5710
+
5711
+ if ( $is_addon_sync ) {
5712
+ $this->_sync_addon_license( $plugin_id, $background );
5713
+ } else {
5714
+ $this->_sync_plugin_license( $background );
5715
+ }
5716
+
5717
+ $this->do_action( 'after_account_plan_sync', $this->_site->plan->name );
5718
+ }
5719
+
5720
+ /**
5721
+ * Sync plugin's add-on license.
5722
+ *
5723
+ * @author Vova Feldman (@svovaf)
5724
+ * @since 1.0.6
5725
+ * @uses FS_Api
5726
+ *
5727
+ * @param number $addon_id
5728
+ * @param bool $background
5729
+ */
5730
+ private function _sync_addon_license( $addon_id, $background ) {
5731
+ $this->_logger->entrance();
5732
+
5733
+ if ( $this->is_addon_activated( $addon_id ) ) {
5734
+ // If already installed, use add-on sync.
5735
+ $fs_addon = self::get_instance_by_id( $addon_id );
5736
+ $fs_addon->_sync_license( $background );
5737
+
5738
+ return;
5739
+ }
5740
+
5741
+ // Validate add-on exists.
5742
+ $addon = $this->get_addon( $addon_id );
5743
+
5744
+ if ( ! is_object( $addon ) ) {
5745
+ return;
5746
+ }
5747
+
5748
+ // Add add-on into account add-ons.
5749
+ $account_addons = $this->get_account_addons();
5750
+ if ( ! is_array( $account_addons ) ) {
5751
+ $account_addons = array();
5752
+ }
5753
+ $account_addons[] = $addon->id;
5754
+ $account_addons = array_unique( $account_addons );
5755
+ $this->_store_account_addons( $account_addons );
5756
+
5757
+ // Load add-on licenses.
5758
+ $licenses = $this->_fetch_licenses( $addon->id );
5759
+
5760
+ // Sync add-on licenses.
5761
+ if ( ! isset( $licenses->error ) ) {
5762
+ $this->_update_licenses( $licenses, $addon->slug );
5763
+
5764
+ if ( ! $this->is_addon_installed( $addon->slug ) && FS_License_Manager::has_premium_license( $licenses ) ) {
5765
+ $plans_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$addon_id}/plans.json" );
5766
+
5767
+ if ( ! isset( $plans_result->error ) ) {
5768
+ $plans = array();
5769
+ foreach ( $plans_result->plans as $plan ) {
5770
+ $plans[] = new FS_Plugin_Plan( $plan );
5771
+ }
5772
+
5773
+ $this->_admin_notices->add_sticky(
5774
+ FS_Plan_Manager::instance()->has_free_plan( $plans ) ?
5775
+ sprintf(
5776
+ __fs( 'addon-successfully-upgraded-message' ),
5777
+ $addon->title
5778
+ ) . ' ' . $this->_get_latest_download_link(
5779
+ __fs( 'download-latest-version' ),
5780
+ $addon_id
5781
+ )
5782
+ :
5783
+ sprintf(
5784
+ __fs( 'addon-successfully-purchased-message' ),
5785
+ $addon->title
5786
+ ) . ' ' . $this->_get_latest_download_link(
5787
+ __fs( 'download-latest-version' ),
5788
+ $addon_id
5789
+ ),
5790
+ 'addon_plan_upgraded_' . $addon->slug,
5791
+ __fs( 'yee-haw' ) . '!'
5792
+ );
5793
+ }
5794
+ }
5795
+ }
5796
+ }
5797
+
5798
+ /**
5799
+ * Sync site's plugin plan.
5800
+ *
5801
+ * @author Vova Feldman (@svovaf)
5802
+ * @since 1.0.6
5803
+ * @uses FS_Api
5804
+ *
5805
+ * @param bool $background Hints the method if it's a background sync. If false, it means that was initiated by
5806
+ * the admin.
5807
+ */
5808
+ private function _sync_plugin_license( $background = false ) {
5809
+ $this->_logger->entrance();
5810
+
5811
+ // Sync site info.
5812
+ $site = $this->send_install_update( array(), true );
5813
+
5814
+ $plan_change = 'none';
5815
+
5816
+ if ( $this->is_api_error( $site ) ) {
5817
+ $api = $this->get_api_site_scope();
5818
+
5819
+ // Try to ping API to see if not blocked.
5820
+ if ( ! $api->test() ) {
5821
+ // Failed to ping API - blocked!
5822
+ $this->_admin_notices->add(
5823
+ sprintf(
5824
+ __fs( 'server-blocking-access' ),
5825
+ $this->get_plugin_name(),
5826
+ '<a href="' . $api->get_url() . '" target="_blank">' . $api->get_url() . '</a>'
5827
+ ) . '<br> ' . __fs( 'server-error-message' ) . var_export( $site->error, true ),
5828
+ __fs( 'oops' ) . '...',
5829
+ 'error',
5830
+ $background
5831
+ );
5832
+ } else {
5833
+ // Authentication params are broken.
5834
+ $this->_admin_notices->add(
5835
+ __fs( 'wrong-authentication-param-message' ),
5836
+ __fs( 'oops' ) . '...',
5837
+ 'error'
5838
+ );
5839
+ }
5840
+ } else {
5841
+ $site = new FS_Site( $site );
5842
+
5843
+ // Sync licenses.
5844
+ $this->_sync_licenses();
5845
+
5846
+ // Sync plans.
5847
+ $this->_sync_plans();
5848
+
5849
+ // Check if plan / license changed.
5850
+ if ( ! FS_Entity::equals( $site->plan, $this->_site->plan ) ||
5851
+ // Check if trial started.
5852
+ $site->trial_plan_id != $this->_site->trial_plan_id ||
5853
+ $site->trial_ends != $this->_site->trial_ends ||
5854
+ // Check if license changed.
5855
+ $site->license_id != $this->_site->license_id
5856
+ ) {
5857
+ if ( $site->is_trial() && ! $this->_site->is_trial() ) {
5858
+ // New trial started.
5859
+ $this->_site = $site;
5860
+ $plan_change = 'trial_started';
5861
+
5862
+ // Store trial plan information.
5863
+ $this->_enrich_site_trial_plan( true );
5864
+
5865
+ } else if ( $this->_site->is_trial() && ! $site->is_trial() && ! is_numeric( $site->license_id ) ) {
5866
+ // Was in trial, but now trial expired and no license ID.
5867
+ // New trial started.
5868
+ $this->_site = $site;
5869
+ $plan_change = 'trial_expired';
5870
+
5871
+ // Clear trial plan information.
5872
+ $this->_storage->trial_plan = null;
5873
+
5874
+ } else {
5875
+ $is_free = $this->is_free_plan();
5876
+
5877
+ // Make sure license exist and not expired.
5878
+ $new_license = is_null( $site->license_id ) ? null : $this->_get_license_by_id( $site->license_id );
5879
+
5880
+ if ( $is_free && ( ( ! is_object( $new_license ) || $new_license->is_expired() ) ) ) {
5881
+ // The license is expired, so ignore upgrade method.
5882
+ } else {
5883
+ // License changed.
5884
+ $this->_site = $site;
5885
+ $this->_update_site_license( $new_license );
5886
+ $this->_store_licenses();
5887
+ $this->_enrich_site_plan( true );
5888
+
5889
+ $plan_change = $is_free ?
5890
+ 'upgraded' :
5891
+ ( is_object( $new_license ) ?
5892
+ 'changed' :
5893
+ 'downgraded' );
5894
+ }
5895
+ }
5896
+
5897
+ // Store updated site info.
5898
+ $this->_store_site();
5899
+ } else {
5900
+ if ( is_object( $this->_license ) && $this->_license->is_expired() ) {
5901
+ if ( ! $this->has_features_enabled_license() ) {
5902
+ $this->_deactivate_license();
5903
+ $plan_change = 'downgraded';
5904
+ } else {
5905
+ $plan_change = 'expired';
5906
+ }
5907
+ }
5908
+
5909
+ if ( is_numeric( $site->license_id ) && is_object( $this->_license ) ) {
5910
+ $this->_sync_site_subscription( $this->_license );
5911
+ }
5912
+ }
5913
+ }
5914
+
5915
+ switch ( $plan_change ) {
5916
+ case 'none':
5917
+ if ( ! $background && is_admin() ) {
5918
+ $this->_admin_notices->add(
5919
+ sprintf(
5920
+ __fs( 'plan-did-not-change-message' ) . ' ' .
5921
+ sprintf(
5922
+ '<a href="%s">%s</a>',
5923
+ $this->contact_url(
5924
+ 'bug',
5925
+ sprintf( __fs( 'plan-did-not-change-email-message', 'freemius' ),
5926
+ strtoupper( $this->_site->plan->name )
5927
+ )
5928
+ ),
5929
+ __fs( 'contact-us-here' )
5930
+ )
5931
+ ),
5932
+ __fs( 'hmm' ) . '...',
5933
+ 'error'
5934
+ );
5935
+ }
5936
+ break;
5937
+ case 'upgraded':
5938
+ $this->_admin_notices->add_sticky(
5939
+ sprintf(
5940
+ __fs( 'plan-upgraded-message' ),
5941
+ '<i>' . $this->get_plugin_name() . '</i>'
5942
+ ) . ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
5943
+ __fs( 'download-latest-x-version' ),
5944
+ $this->_site->plan->title
5945
+ ) )
5946
+ ),
5947
+ 'plan_upgraded',
5948
+ __fs( 'yee-haw' ) . '!'
5949
+ );
5950
+
5951
+ $this->_admin_notices->remove_sticky( array(
5952
+ 'trial_started',
5953
+ 'trial_promotion',
5954
+ 'trial_expired',
5955
+ 'activation_complete',
5956
+ ) );
5957
+ break;
5958
+ case 'changed':
5959
+ $this->_admin_notices->add_sticky(
5960
+ sprintf(
5961
+ __fs( 'plan-changed-to-x-message' ),
5962
+ $this->_site->plan->title
5963
+ ),
5964
+ 'plan_changed'
5965
+ );
5966
+
5967
+ $this->_admin_notices->remove_sticky( array(
5968
+ 'trial_started',
5969
+ 'trial_promotion',
5970
+ 'trial_expired',
5971
+ 'activation_complete',
5972
+ ) );
5973
+ break;
5974
+ case 'downgraded':
5975
+ $this->_admin_notices->add_sticky(
5976
+ sprintf( __fs( 'license-expired-blocking-message' ) ),
5977
+ 'license_expired',
5978
+ __fs( 'hmm' ) . '...'
5979
+ );
5980
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
5981
+ break;
5982
+ case 'expired':
5983
+ $this->_admin_notices->add_sticky(
5984
+ sprintf( __fs( 'license-expired-non-blocking-message' ), $this->_site->plan->title ),
5985
+ 'license_expired',
5986
+ __fs( 'hmm' ) . '...'
5987
+ );
5988
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
5989
+ break;
5990
+ case 'trial_started':
5991
+ $this->_admin_notices->add_sticky(
5992
+ sprintf(
5993
+ __fs( 'trial-started-message' ),
5994
+ '<i>' . $this->get_plugin_name() . '</i>'
5995
+ ) . ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
5996
+ __fs( 'download-latest-x-version' ),
5997
+ $this->_storage->trial_plan->title
5998
+ ) ) ),
5999
+ 'trial_started',
6000
+ __fs( 'yee-haw' ) . '!'
6001
+ );
6002
+
6003
+ $this->_admin_notices->remove_sticky( array(
6004
+ 'trial_promotion',
6005
+ ) );
6006
+ break;
6007
+ case 'trial_expired':
6008
+ $this->_admin_notices->add_sticky(
6009
+ __fs( 'trial-expired-message' ),
6010
+ 'trial_expired',
6011
+ __fs( 'hmm' ) . '...'
6012
+ );
6013
+ $this->_admin_notices->remove_sticky( array(
6014
+ 'trial_started',
6015
+ 'trial_promotion',
6016
+ 'plan_upgraded',
6017
+ ) );
6018
+ break;
6019
+ }
6020
+
6021
+ if ( 'none' !== $plan_change ) {
6022
+ $this->do_action( 'after_license_change', $plan_change, $this->_site->plan );
6023
+ }
6024
+ }
6025
+
6026
+ /**
6027
+ * @author Vova Feldman (@svovaf)
6028
+ * @since 1.0.5
6029
+ *
6030
+ * @param bool $background
6031
+ */
6032
+ protected function _activate_license( $background = false ) {
6033
+ $this->_logger->entrance();
6034
+
6035
+ $premium_license = $this->_get_available_premium_license();
6036
+
6037
+ if ( ! is_object( $premium_license ) ) {
6038
+ return;
6039
+ }
6040
+
6041
+ $api = $this->get_api_site_scope();
6042
+ $license = $api->call( "/licenses/{$premium_license->id}.json", 'put' );
6043
+
6044
+ if ( isset( $license->error ) ) {
6045
+ if ( ! $background ) {
6046
+ $this->_admin_notices->add(
6047
+ __fs( 'license-activation-failed-message' ) . '<br> ' .
6048
+ __fs( 'server-error-message' ) . ' ' . var_export( $license->error, true ),
6049
+ __fs( 'hmm' ) . '...',
6050
+ 'error'
6051
+ );
6052
+ }
6053
+
6054
+ return;
6055
+ }
6056
+
6057
+ $premium_license = new FS_Plugin_License( $license );
6058
+
6059
+ // Updated site plan.
6060
+ $this->_site->plan->id = $premium_license->plan_id;
6061
+ $this->_update_site_license( $premium_license );
6062
+ $this->_enrich_site_plan( false );
6063
+
6064
+ $this->_store_account();
6065
+
6066
+ if ( ! $background ) {
6067
+ $this->_admin_notices->add_sticky(
6068
+ __fs( 'license-activated-message' ) .
6069
+ ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
6070
+ __fs( 'download-latest-x-version' ),
6071
+ $this->_site->plan->title
6072
+ ) ) ),
6073
+ 'license_activated',
6074
+ __fs( 'yee-haw' ) . '!'
6075
+ );
6076
+ }
6077
+
6078
+ $this->_admin_notices->remove_sticky( array(
6079
+ 'trial_promotion',
6080
+ 'license_expired',
6081
+ ) );
6082
+ }
6083
+
6084
+ /**
6085
+ * @author Vova Feldman (@svovaf)
6086
+ * @since 1.0.5
6087
+ *
6088
+ * @param bool $show_notice
6089
+ */
6090
+ protected function _deactivate_license( $show_notice = true ) {
6091
+ $this->_logger->entrance();
6092
+
6093
+ if ( ! is_object( $this->_license ) ) {
6094
+ $this->_admin_notices->add(
6095
+ sprintf( __fs( 'no-active-license-message' ), $this->_site->plan->title ),
6096
+ __fs( 'hmm' ) . '...'
6097
+ );
6098
+
6099
+ return;
6100
+ }
6101
+
6102
+ $api = $this->get_api_site_scope();
6103
+ $license = $api->call( "/licenses/{$this->_site->license_id}.json", 'delete' );
6104
+
6105
+ if ( isset( $license->error ) ) {
6106
+ $this->_admin_notices->add(
6107
+ __fs( 'license-deactivation-failed-message' ) . '<br> ' .
6108
+ __fs( 'server-error-message' ) . ' ' . var_export( $license->error, true ),
6109
+ __fs( 'hmm' ) . '...',
6110
+ 'error'
6111
+ );
6112
+
6113
+ return;
6114
+ }
6115
+
6116
+ // Update license cache.
6117
+ for ( $i = 0, $len = count( $this->_licenses ); $i < $len; $i ++ ) {
6118
+ if ( $license->id == $this->_licenses[ $i ]->id ) {
6119
+ $this->_licenses[ $i ] = new FS_Plugin_License( $license );
6120
+ }
6121
+ }
6122
+
6123
+ // Updated site plan to default.
6124
+ $this->_sync_plans();
6125
+ $this->_site->plan->id = $this->_plans[0]->id;
6126
+ // Unlink license from site.
6127
+ $this->_update_site_license( null );
6128
+ $this->_enrich_site_plan( false );
6129
+
6130
+ $this->_store_account();
6131
+
6132
+ if ( $show_notice ) {
6133
+ $this->_admin_notices->add(
6134
+ sprintf( __fs( 'license-deactivation-message' ), $this->_site->plan->title ),
6135
+ __fs( 'ok' )
6136
+ );
6137
+ }
6138
+
6139
+ $this->_admin_notices->remove_sticky( array(
6140
+ 'plan_upgraded',
6141
+ 'license_activated',
6142
+ ) );
6143
+ }
6144
+
6145
+ /**
6146
+ * Site plan downgrade.
6147
+ *
6148
+ * @author Vova Feldman (@svovaf)
6149
+ * @since 1.0.4
6150
+ *
6151
+ * @uses FS_Api
6152
+ */
6153
+ private function _downgrade_site() {
6154
+ $this->_logger->entrance();
6155
+
6156
+ $api = $this->get_api_site_scope();
6157
+ $site = $api->call( 'downgrade.json', 'put' );
6158
+
6159
+ $plan_downgraded = false;
6160
+ $plan = false;
6161
+ if ( ! isset( $site->error ) ) {
6162
+ $prev_plan_id = $this->_site->plan->id;
6163
+
6164
+ // Update new site plan id.
6165
+ $this->_site->plan->id = $site->plan_id;
6166
+
6167
+ $plan = $this->_enrich_site_plan();
6168
+ $subscription = $this->_sync_site_subscription( $this->_license );
6169
+
6170
+ // Plan downgraded if plan was changed or subscription was cancelled.
6171
+ $plan_downgraded = ( $plan instanceof FS_Plugin_Plan && $prev_plan_id != $plan->id ) ||
6172
+ ( is_object( $subscription ) && ! isset( $subscription->error ) && ! $subscription->is_active() );
6173
+ } else {
6174
+ // handle different error cases.
6175
+
6176
+ }
6177
+
6178
+ if ( $plan_downgraded ) {
6179
+ // Remove previous sticky message about upgrade (if exist).
6180
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
6181
+
6182
+ $this->_admin_notices->add(
6183
+ sprintf( __fs( 'plan-x-downgraded-message' ),
6184
+ $plan->title,
6185
+ human_time_diff( time(), strtotime( $this->_license->expiration ) )
6186
+ )
6187
+ );
6188
+
6189
+ // Store site updates.
6190
+ $this->_store_site();
6191
+ } else {
6192
+ $this->_admin_notices->add(
6193
+ __fs( 'plan-downgraded-failure-message' ),
6194
+ __fs( 'oops' ) . '...',
6195
+ 'error'
6196
+ );
6197
+ }
6198
+ }
6199
+
6200
+ /**
6201
+ * Cancel site trial.
6202
+ *
6203
+ * @author Vova Feldman (@svovaf)
6204
+ * @since 1.0.9
6205
+ *
6206
+ * @uses FS_Api
6207
+ */
6208
+ private function _cancel_trial() {
6209
+ $this->_logger->entrance();
6210
+
6211
+ if ( ! $this->is_trial() ) {
6212
+ $this->_admin_notices->add(
6213
+ __fs( 'trial-cancel-no-trial-message' ),
6214
+ __fs( 'oops' ) . '...',
6215
+ 'error'
6216
+ );
6217
+
6218
+ return;
6219
+ }
6220
+
6221
+ $api = $this->get_api_site_scope();
6222
+ $site = $api->call( 'trials.json', 'delete' );
6223
+
6224
+ $trial_cancelled = false;
6225
+
6226
+ if ( ! isset( $site->error ) ) {
6227
+ $prev_trial_ends = $this->_site->trial_ends;
6228
+
6229
+ // Update new site plan id.
6230
+ $this->_site->trial_ends = $site->trial_ends;
6231
+
6232
+ $trial_cancelled = ( $prev_trial_ends != $site->trial_ends );
6233
+ } else {
6234
+ // handle different error cases.
6235
+
6236
+ }
6237
+
6238
+ if ( $trial_cancelled ) {
6239
+ // Remove previous sticky message about upgrade (if exist).
6240
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
6241
+
6242
+ $this->_admin_notices->add(
6243
+ sprintf( __fs( 'trial-cancel-message' ), $this->_storage->trial_plan->title )
6244
+ );
6245
+
6246
+ $this->_admin_notices->remove_sticky( array(
6247
+ 'trial_started',
6248
+ 'trial_promotion',
6249
+ 'plan_upgraded',
6250
+ ) );
6251
+
6252
+ // Store site updates.
6253
+ $this->_store_site();
6254
+
6255
+ // Clear trial plan information.
6256
+ unset( $this->_storage->trial_plan );
6257
+ } else {
6258
+ $this->_admin_notices->add(
6259
+ __fs( 'trial-cancel-failure-message' ),
6260
+ __fs( 'oops' ) . '...',
6261
+ 'error'
6262
+ );
6263
+ }
6264
+ }
6265
+
6266
+ /**
6267
+ * @author Vova Feldman (@svovaf)
6268
+ * @since 1.0.6
6269
+ *
6270
+ * @param bool|number $plugin_id
6271
+ *
6272
+ * @return bool
6273
+ */
6274
+ private function _is_addon_id( $plugin_id ) {
6275
+ return is_numeric( $plugin_id ) && ( $this->get_id() != $plugin_id );
6276
+ }
6277
+
6278
+ /**
6279
+ * Check if user eligible to download premium version updates.
6280
+ *
6281
+ * @author Vova Feldman (@svovaf)
6282
+ * @since 1.0.6
6283
+ *
6284
+ * @return bool
6285
+ */
6286
+ private function _can_download_premium() {
6287
+ return $this->has_active_license() ||
6288
+ ( $this->is_trial() && ! $this->get_trial_plan()->is_free() );
6289
+ }
6290
+
6291
+ /**
6292
+ *
6293
+ * @author Vova Feldman (@svovaf)
6294
+ * @since 1.0.6
6295
+ *
6296
+ * @param bool|number $addon_id
6297
+ * @param string $type "json" or "zip"
6298
+ *
6299
+ * @return string
6300
+ */
6301
+ private function _get_latest_version_endpoint( $addon_id = false, $type = 'json' ) {
6302
+
6303
+ $is_addon = $this->_is_addon_id( $addon_id );
6304
+
6305
+ $is_premium = null;
6306
+ if ( ! $is_addon ) {
6307
+ $is_premium = $this->_can_download_premium();
6308
+ } else if ( $this->is_addon_activated( $addon_id ) ) {
6309
+ $is_premium = self::get_instance_by_id( $addon_id )->_can_download_premium();
6310
+ }
6311
+
6312
+ return // If add-on, then append add-on ID.
6313
+ ( $is_addon ? "/addons/$addon_id" : '' ) .
6314
+ '/updates/latest.' . $type .
6315
+ // If add-on and not yet activated, try to fetch based on server licensing.
6316
+ ( is_bool( $is_premium ) ? '?is_premium=' . json_encode( $is_premium ) : '' );
6317
+ }
6318
+
6319
+ /**
6320
+ * @author Vova Feldman (@svovaf)
6321
+ * @since 1.0.4
6322
+ *
6323
+ * @param bool|number $addon_id
6324
+ *
6325
+ * @return object|false Plugin latest tag info.
6326
+ */
6327
+ function _fetch_latest_version( $addon_id = false ) {
6328
+ $tag = $this->get_api_site_or_plugin_scope()->get(
6329
+ $this->_get_latest_version_endpoint( $addon_id, 'json' ),
6330
+ true
6331
+ );
6332
+ $latest_version = ( is_object( $tag ) && isset( $tag->version ) ) ? $tag->version : 'couldn\'t get';
6333
+ $this->_logger->departure( 'Latest version ' . $latest_version );
6334
+
6335
+ return ( is_object( $tag ) && isset( $tag->version ) ) ? $tag : false;
6336
+ }
6337
+
6338
+ #region Download Plugin ------------------------------------------------------------------
6339
+
6340
+ /**
6341
+ * Download latest plugin version, based on plan.
6342
+ * The download will be fetched via the API first.
6343
+ *
6344
+ * @author Vova Feldman (@svovaf)
6345
+ * @since 1.0.4
6346
+ *
6347
+ * @param bool|number $plugin_id
6348
+ *
6349
+ * @uses FS_Api
6350
+ *
6351
+ * @deprecated
6352
+ */
6353
+ private function _download_latest( $plugin_id = false ) {
6354
+ $this->_logger->entrance();
6355
+
6356
+ $is_addon = $this->_is_addon_id( $plugin_id );
6357
+
6358
+ $is_premium = $this->_can_download_premium();
6359
+
6360
+ $latest = $this->get_api_site_scope()->call(
6361
+ $this->_get_latest_version_endpoint( $plugin_id, 'zip' )
6362
+ );
6363
+
6364
+ $slug = $this->_slug;
6365
+ if ( $is_addon ) {
6366
+ $addon = $this->get_addon( $plugin_id );
6367
+ $slug = is_object( $addon ) ? $addon->slug : 'addon';
6368
+ }
6369
+
6370
+ if ( ! is_object( $latest ) ) {
6371
+ header( "Content-Type: application/zip" );
6372
+ header( "Content-Disposition: attachment; filename={$slug}" . ( ! $is_addon && $is_premium ? '-premium' : '' ) . ".zip" );
6373
+ header( "Content-Length: " . strlen( $latest ) );
6374
+ echo $latest;
6375
+
6376
+ exit();
6377
+ }
6378
+ }
6379
+
6380
+ /**
6381
+ * Download latest plugin version, based on plan.
6382
+ *
6383
+ * Not like _download_latest(), this will redirect the page
6384
+ * to secure download url to prevent dual download (from FS to WP server,
6385
+ * and then from WP server to the client / browser).
6386
+ *
6387
+ * @author Vova Feldman (@svovaf)
6388
+ * @since 1.0.9
6389
+ *
6390
+ * @param bool|number $plugin_id
6391
+ *
6392
+ * @uses FS_Api
6393
+ * @uses wp_redirect()
6394
+ */
6395
+ private function _download_latest_directly( $plugin_id = false ) {
6396
+ $this->_logger->entrance();
6397
+
6398
+ wp_redirect( $this->_get_latest_download_api_url( $plugin_id ) );
6399
+ }
6400
+
6401
+ /**
6402
+ * Get latest plugin FS API download URL.
6403
+ *
6404
+ * @author Vova Feldman (@svovaf)
6405
+ * @since 1.0.9
6406
+ *
6407
+ * @param bool|number $plugin_id
6408
+ *
6409
+ * @return string
6410
+ */
6411
+ private function _get_latest_download_api_url( $plugin_id = false ) {
6412
+ $this->_logger->entrance();
6413
+
6414
+ return $this->get_api_site_scope()->get_signed_url(
6415
+ $this->_get_latest_version_endpoint( $plugin_id, 'zip' )
6416
+ );
6417
+ }
6418
+
6419
+ /**
6420
+ * Get latest plugin download link.
6421
+ *
6422
+ * @author Vova Feldman (@svovaf)
6423
+ * @since 1.0.9
6424
+ *
6425
+ * @param string $label
6426
+ * @param bool|number $plugin_id
6427
+ *
6428
+ * @return string
6429
+ */
6430
+ private function _get_latest_download_link( $label, $plugin_id = false ) {
6431
+ return sprintf(
6432
+ '<a target="_blank" href="%s">%s</a>',
6433
+ $this->_get_latest_download_local_url( $plugin_id ),
6434
+ $label
6435
+ );
6436
+ }
6437
+
6438
+ /**
6439
+ * Get latest plugin download local URL.
6440
+ *
6441
+ * @author Vova Feldman (@svovaf)
6442
+ * @since 1.0.9
6443
+ *
6444
+ * @param bool|number $plugin_id
6445
+ *
6446
+ * @return string
6447
+ */
6448
+ function _get_latest_download_local_url( $plugin_id = false ) {
6449
+ // Add timestamp to protect from caching.
6450
+ $params = array( 'ts' => WP_FS__SCRIPT_START_TIME );
6451
+
6452
+ if ( ! empty( $plugin_id ) ) {
6453
+ $params['plugin_id'] = $plugin_id;
6454
+ }
6455
+
6456
+ return $this->get_account_url( 'download_latest', $params );
6457
+ }
6458
+
6459
+ #endregion Download Plugin ------------------------------------------------------------------
6460
+
6461
+ /**
6462
+ * @author Vova Feldman (@svovaf)
6463
+ * @since 1.0.4
6464
+ *
6465
+ * @uses FS_Api
6466
+ *
6467
+ * @param bool $background Hints the method if it's a background updates check. If false, it means that
6468
+ * was initiated by the admin.
6469
+ * @param bool|number $plugin_id
6470
+ */
6471
+ private function _check_updates( $background = false, $plugin_id = false ) {
6472
+ $this->_logger->entrance();
6473
+
6474
+ // Check if there's a newer version for download.
6475
+ $new_version = $this->_fetch_newer_version( $plugin_id );
6476
+
6477
+ $update = null;
6478
+ if ( is_object( $new_version ) ) {
6479
+ $update = new FS_Plugin_Tag( $new_version );
6480
+
6481
+ if ( ! $background ) {
6482
+ $this->_admin_notices->add(
6483
+ sprintf(
6484
+ __fs( 'version-x-released' ) . ' ' . __fS( 'please-download-x' ),
6485
+ $update->version,
6486
+ sprintf(
6487
+ '<a href="%s" target="_blank">%s</a>',
6488
+ $this->get_account_url( 'download_latest' ),
6489
+ sprintf( __fs( 'latest-x-version' ), $this->_site->plan->title )
6490
+ )
6491
+ ),
6492
+ __fs( 'new' ) . '!'
6493
+ );
6494
+ }
6495
+ } else if ( false === $new_version && ! $background ) {
6496
+ $this->_admin_notices->add(
6497
+ __fs( 'you-have-latest' ),
6498
+ __fs( 'you-are-good' )
6499
+ );
6500
+ }
6501
+
6502
+ $this->_store_update( $update, true, $plugin_id );
6503
+ }
6504
+
6505
+ /**
6506
+ * @author Vova Feldman (@svovaf)
6507
+ * @since 1.0.4
6508
+ *
6509
+ * @uses FS_Api
6510
+ *
6511
+ */
6512
+ private function _sync_addons() {
6513
+ $this->_logger->entrance();
6514
+
6515
+ $result = $this->get_api_site_or_plugin_scope()->get( '/addons.json?enriched=true', true );
6516
+
6517
+ if ( isset( $result->error ) ) {
6518
+ return;
6519
+ }
6520
+
6521
+ $addons = array();
6522
+ for ( $i = 0, $len = count( $result->plugins ); $i < $len; $i ++ ) {
6523
+ $addons[ $i ] = new FS_Plugin( $result->plugins[ $i ] );
6524
+ }
6525
+
6526
+ $this->_store_addons( $addons, true );
6527
+ }
6528
+
6529
+ /**
6530
+ * Handle user email update.
6531
+ *
6532
+ * @author Vova Feldman (@svovaf)
6533
+ * @since 1.0.3
6534
+ * @uses FS_Api
6535
+ *
6536
+ * @param string $new_email
6537
+ *
6538
+ * @return object
6539
+ */
6540
+ private function _update_email( $new_email ) {
6541
+ $this->_logger->entrance();
6542
+
6543
+
6544
+ $api = $this->get_api_user_scope();
6545
+ $user = $api->call( "?plugin_id={$this->_plugin->id}&fields=id,email,is_verified", 'put', array(
6546
+ 'email' => $new_email,
6547
+ 'after_email_confirm_url' => $this->_get_admin_page_url(
6548
+ 'account',
6549
+ array( 'fs_action' => 'sync_user' )
6550
+ ),
6551
+ ) );
6552
+
6553
+ if ( ! isset( $user->error ) ) {
6554
+ $this->_user->email = $user->email;
6555
+ $this->_user->is_verified = $user->is_verified;
6556
+ $this->_store_user();
6557
+ } else {
6558
+ // handle different error cases.
6559
+
6560
+ }
6561
+
6562
+ return $user;
6563
+ }
6564
+
6565
+ /**
6566
+ * @author Vova Feldman (@svovaf)
6567
+ * @since 1.1.1
6568
+ *
6569
+ * @param mixed $result
6570
+ *
6571
+ * @return bool Is API result contains an error.
6572
+ */
6573
+ private function is_api_error( $result ) {
6574
+ return ( is_object( $result ) && isset( $result->error ) ) ||
6575
+ is_string( $result );
6576
+ }
6577
+
6578
+ /**
6579
+ * Start install ownership change.
6580
+ *
6581
+ * @author Vova Feldman (@svovaf)
6582
+ * @since 1.1.1
6583
+ * @uses FS_Api
6584
+ *
6585
+ * @param string $candidate_email
6586
+ *
6587
+ * @return bool Is ownership change successfully initiated.
6588
+ */
6589
+ private function init_change_owner( $candidate_email ) {
6590
+ $this->_logger->entrance();
6591
+
6592
+ $api = $this->get_api_site_scope();
6593
+ $result = $api->call( "/users/{$this->_user->id}.json", 'put', array(
6594
+ 'email' => $candidate_email,
6595
+ 'after_confirm_url' => $this->_get_admin_page_url(
6596
+ 'account',
6597
+ array( 'fs_action' => 'change_owner' )
6598
+ ),
6599
+ ) );
6600
+
6601
+ return ! $this->is_api_error( $result );
6602
+ }
6603
+
6604
+ /**
6605
+ * Handle install ownership change.
6606
+ *
6607
+ * @author Vova Feldman (@svovaf)
6608
+ * @since 1.1.1
6609
+ * @uses FS_Api
6610
+ *
6611
+ * @return bool Was ownership change successfully complete.
6612
+ */
6613
+ private function complete_change_owner() {
6614
+ $this->_logger->entrance();
6615
+
6616
+ $site_result = $this->get_api_site_scope( true )->get();
6617
+ $site = new FS_Site( $site_result );
6618
+ $this->_site = $site;
6619
+
6620
+ $user = new FS_User();
6621
+ $user->id = fs_request_get( 'user_id' );
6622
+
6623
+ // Validate install's user and given user.
6624
+ if ( $user->id != $this->_site->user_id ) {
6625
+ return false;
6626
+ }
6627
+
6628
+ $user->public_key = fs_request_get( 'user_public_key' );
6629
+ $user->secret_key = fs_request_get( 'user_secret_key' );
6630
+
6631
+ // Fetch new user information.
6632
+ $this->_user = $user;
6633
+ $user_result = $this->get_api_user_scope( true )->get();
6634
+ $user = new FS_User( $user_result );
6635
+ $this->_user = $user;
6636
+
6637
+ $this->_set_account( $user, $site );
6638
+
6639
+ return true;
6640
+ }
6641
+
6642
+ /**
6643
+ * Handle user name update.
6644
+ *
6645
+ * @author Vova Feldman (@svovaf)
6646
+ * @since 1.0.9
6647
+ * @uses FS_Api
6648
+ *
6649
+ * @return object
6650
+ */
6651
+ private function update_user_name() {
6652
+ $this->_logger->entrance();
6653
+ $name = fs_request_get( 'fs_user_name_' . $this->_slug, '' );
6654
+
6655
+ $api = $this->get_api_user_scope();
6656
+ $user = $api->call( "?plugin_id={$this->_plugin->id}&fields=id,first,last", 'put', array(
6657
+ 'name' => $name,
6658
+ ) );
6659
+
6660
+ if ( ! isset( $user->error ) ) {
6661
+ $this->_user->first = $user->first;
6662
+ $this->_user->last = $user->last;
6663
+ $this->_store_user();
6664
+ } else {
6665
+ // handle different error cases.
6666
+
6667
+ }
6668
+
6669
+ return $user;
6670
+ }
6671
+
6672
+ /**
6673
+ * Verify user email.
6674
+ *
6675
+ * @author Vova Feldman (@svovaf)
6676
+ * @since 1.0.3
6677
+ * @uses FS_Api
6678
+ */
6679
+ private function verify_email() {
6680
+ $this->_handle_account_user_sync();
6681
+
6682
+ if ( $this->_user->is_verified() ) {
6683
+ return;
6684
+ }
6685
+
6686
+ $api = $this->get_api_site_scope();
6687
+ $result = $api->call( "/users/{$this->_user->id}/verify.json", 'put', array(
6688
+ 'after_email_confirm_url' => $this->_get_admin_page_url(
6689
+ 'account',
6690
+ array( 'fs_action' => 'sync_user' )
6691
+ )
6692
+ ) );
6693
+
6694
+ if ( ! isset( $result->error ) ) {
6695
+ $this->_admin_notices->add( sprintf(
6696
+ __fs( 'verification-email-sent-message' ),
6697
+ sprintf( '<a href="mailto:%1s">%2s</a>', esc_url( $this->_user->email ), $this->_user->email )
6698
+ ) );
6699
+ } else {
6700
+ // handle different error cases.
6701
+
6702
+ }
6703
+ }
6704
+
6705
+ /**
6706
+ * @author Vova Feldman (@svovaf)
6707
+ * @since 1.1.2
6708
+ *
6709
+ * @return string
6710
+ */
6711
+ private function get_activation_url() {
6712
+ return $this->apply_filters( 'connect_url', $this->_get_admin_page_url() );
6713
+ }
6714
+
6715
+ /**
6716
+ * @author Vova Feldman (@svovaf)
6717
+ * @since 1.1.3
6718
+ *
6719
+ * @param string $filter Filter name.
6720
+ *
6721
+ * @return string
6722
+ */
6723
+ private function get_after_activation_url( $filter ) {
6724
+ $first_time_path = $this->_menu->get_first_time_path();
6725
+
6726
+ return $this->apply_filters(
6727
+ $filter,
6728
+ empty( $first_time_path ) ?
6729
+ $this->_get_admin_page_url() :
6730
+ $first_time_path
6731
+ );
6732
+ }
6733
+
6734
+ /**
6735
+ * Handle account page updates / edits / actions.
6736
+ *
6737
+ * @author Vova Feldman (@svovaf)
6738
+ * @since 1.0.2
6739
+ *
6740
+ */
6741
+ private function _handle_account_edits() {
6742
+ if ( ! current_user_can( 'activate_plugins' ) ) {
6743
+ return;
6744
+ }
6745
+
6746
+ $plugin_id = fs_request_get( 'plugin_id', $this->get_id() );
6747
+ $action = fs_get_action();
6748
+
6749
+ switch ( $action ) {
6750
+ case 'delete_account':
6751
+ check_admin_referer( $action );
6752
+
6753
+ if ( $plugin_id == $this->get_id() ) {
6754
+ $this->delete_account_event();
6755
+
6756
+ // Clear user and site.
6757
+ $this->_site = null;
6758
+ $this->_user = null;
6759
+
6760
+ if ( fs_redirect( $this->get_activation_url() ) ) {
6761
+ exit();
6762
+ }
6763
+ } else {
6764
+ if ( $this->is_addon_activated( $plugin_id ) ) {
6765
+ $fs_addon = self::get_instance_by_id( $plugin_id );
6766
+ $fs_addon->delete_account_event();
6767
+
6768
+ if ( fs_redirect( $this->_get_admin_page_url( 'account' ) ) ) {
6769
+ exit();
6770
+ }
6771
+ }
6772
+ }
6773
+
6774
+ return;
6775
+
6776
+ case 'downgrade_account':
6777
+ check_admin_referer( $action );
6778
+ $this->_downgrade_site();
6779
+
6780
+ return;
6781
+
6782
+ case 'activate_license':
6783
+ check_admin_referer( $action );
6784
+
6785
+ if ( $plugin_id == $this->get_id() ) {
6786
+ $this->_activate_license();
6787
+ } else {
6788
+ if ( $this->is_addon_activated( $plugin_id ) ) {
6789
+ $fs_addon = self::get_instance_by_id( $plugin_id );
6790
+ $fs_addon->_activate_license();
6791
+ }
6792
+ }
6793
+
6794
+ return;
6795
+
6796
+ case 'deactivate_license':
6797
+ check_admin_referer( $action );
6798
+
6799
+ if ( $plugin_id == $this->get_id() ) {
6800
+ $this->_deactivate_license();
6801
+ } else {
6802
+ if ( $this->is_addon_activated( $plugin_id ) ) {
6803
+ $fs_addon = self::get_instance_by_id( $plugin_id );
6804
+ $fs_addon->_deactivate_license();
6805
+ }
6806
+ }
6807
+
6808
+ return;
6809
+
6810
+ case 'check_updates':
6811
+ check_admin_referer( $action );
6812
+ $this->_check_updates();
6813
+
6814
+ return;
6815
+
6816
+ case 'change_owner':
6817
+ $state = fs_request_get( 'state', 'init' );
6818
+ switch ( $state ) {
6819
+ case 'init':
6820
+ $candidate_email = fs_request_get( 'candidate_email', '' );
6821
+
6822
+ if ( $this->init_change_owner( $candidate_email ) ) {
6823
+ $this->_admin_notices->add( sprintf( __fs( 'change-owner-request-sent-x' ), '<b>' . $this->_user->email . '</b>' ) );
6824
+ }
6825
+ break;
6826
+ case 'owner_confirmed':
6827
+ $candidate_email = fs_request_get( 'candidate_email', '' );
6828
+
6829
+ $this->_admin_notices->add( sprintf( __fs( 'change-owner-request_owner-confirmed' ), '<b>' . $candidate_email . '</b>' ) );
6830
+ break;
6831
+ case 'candidate_confirmed':
6832
+ if ( $this->complete_change_owner() ) {
6833
+ $this->_admin_notices->add_sticky(
6834
+ sprintf( __fs( 'change-owner-request_candidate-confirmed' ), '<b>' . $this->_user->email . '</b>' ),
6835
+ 'ownership_changed',
6836
+ __fs( 'congrats' ) . '!'
6837
+ );
6838
+ } else {
6839
+ // @todo Handle failed ownership change message.
6840
+ }
6841
+ break;
6842
+ }
6843
+
6844
+ return;
6845
+
6846
+ case 'update_email':
6847
+ check_admin_referer( 'update_email' );
6848
+
6849
+ $new_email = fs_request_get( 'fs_email_' . $this->_slug, '' );
6850
+ $result = $this->_update_email( $new_email );
6851
+
6852
+ if ( isset( $result->error ) ) {
6853
+ switch ( $result->error->code ) {
6854
+ case 'user_exist':
6855
+ $this->_admin_notices->add(
6856
+ __fs( 'user-exist-message' ) . ' ' .
6857
+ sprintf( __fs( 'user-exist-message_ownership' ), '<b>' . $new_email . '</b>' ) .
6858
+ sprintf(
6859
+ '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s &nbsp;&#10140;</button></a>',
6860
+ $this->get_account_url( 'change_owner', array(
6861
+ 'state' => 'init',
6862
+ 'candidate_email' => $new_email
6863
+ ) ),
6864
+ __fs( 'change-ownership' )
6865
+ ),
6866
+ __fs( 'oops' ) . '...',
6867
+ 'error'
6868
+ );
6869
+ break;
6870
+ }
6871
+ } else {
6872
+ $this->_admin_notices->add( __fs( 'email-updated-message' ) );
6873
+ }
6874
+
6875
+ return;
6876
+
6877
+ case 'update_user_name':
6878
+ check_admin_referer( 'update_user_name' );
6879
+
6880
+ $result = $this->update_user_name();
6881
+
6882
+ if ( isset( $result->error ) ) {
6883
+ $this->_admin_notices->add(
6884
+ __fs( 'name-update-failed-message' ),
6885
+ __fs( 'oops' ) . '...',
6886
+ 'error'
6887
+ );
6888
+ } else {
6889
+ $this->_admin_notices->add( __fs( 'name-updated-message' ) );
6890
+ }
6891
+
6892
+ return;
6893
+
6894
+ #region Actions that might be called from external links (e.g. email)
6895
+
6896
+ case 'cancel_trial':
6897
+ $this->_cancel_trial();
6898
+
6899
+ return;
6900
+
6901
+ case 'verify_email':
6902
+ $this->verify_email();
6903
+
6904
+ return;
6905
+
6906
+ case 'sync_user':
6907
+ $this->_handle_account_user_sync();
6908
+
6909
+ return;
6910
+
6911
+ case $this->_slug . '_sync_license':
6912
+ $this->_sync_license();
6913
+
6914
+ return;
6915
+
6916
+ case 'download_latest':
6917
+ $this->_download_latest_directly( $plugin_id );
6918
+
6919
+ return;
6920
+
6921
+ #endregion
6922
+ }
6923
+
6924
+ if ( WP_FS__IS_POST_REQUEST ) {
6925
+ $properties = array( 'site_secret_key', 'site_id', 'site_public_key' );
6926
+ foreach ( $properties as $p ) {
6927
+ if ( 'update_' . $p === $action ) {
6928
+ check_admin_referer( $action );
6929
+
6930
+ $this->_logger->log( $action );
6931
+
6932
+ $site_property = substr( $p, strlen( 'site_' ) );
6933
+ $site_property_value = fs_request_get( 'fs_' . $p . '_' . $this->_slug, '' );
6934
+ $this->get_site()->{$site_property} = $site_property_value;
6935
+
6936
+ // Store account after modification.
6937
+ $this->_store_site();
6938
+
6939
+ $this->do_action( 'account_property_edit', 'site', $site_property, $site_property_value );
6940
+
6941
+ $this->_admin_notices->add( sprintf(
6942
+ __fs( 'x-updated' ),
6943
+ '<b>' . str_replace( '_', ' ', $p ) . '</b>' ) );
6944
+
6945
+ return;
6946
+ }
6947
+ }
6948
+ }
6949
+ }
6950
+
6951
+ /**
6952
+ * Account page resources load.
6953
+ *
6954
+ * @author Vova Feldman (@svovaf)
6955
+ * @since 1.0.6
6956
+ */
6957
+ function _account_page_load() {
6958
+ $this->_logger->entrance();
6959
+
6960
+ $this->_logger->info( var_export( $_REQUEST, true ) );
6961
+
6962
+ fs_enqueue_local_style( 'fs_account', '/admin/account.css' );
6963
+
6964
+ if ( $this->_has_addons() ) {
6965
+ wp_enqueue_script( 'plugin-install' );
6966
+ add_thickbox();
6967
+
6968
+ function fs_addons_body_class( $classes ) {
6969
+ $classes .= ' plugins-php';
6970
+
6971
+ return $classes;
6972
+ }
6973
+
6974
+ add_filter( 'admin_body_class', 'fs_addons_body_class' );
6975
+ }
6976
+
6977
+ $this->_handle_account_edits();
6978
+
6979
+ $this->do_action( 'account_page_load_before_departure' );
6980
+ }
6981
+
6982
+ /**
6983
+ * Render account page.
6984
+ *
6985
+ * @author Vova Feldman (@svovaf)
6986
+ * @since 1.0.0
6987
+ */
6988
+ function _account_page_render() {
6989
+ $this->_logger->entrance();
6990
+
6991
+ $vars = array( 'slug' => $this->_slug );
6992
+ fs_require_once_template( 'account.php', $vars );
6993
+ }
6994
+
6995
+ /**
6996
+ * Render account connect page.
6997
+ *
6998
+ * @author Vova Feldman (@svovaf)
6999
+ * @since 1.0.7
7000
+ */
7001
+ function _connect_page_render() {
7002
+ $this->_logger->entrance();
7003
+
7004
+ $vars = array( 'slug' => $this->_slug );
7005
+ if ( $this->is_pending_activation() ) {
7006
+ fs_require_once_template( 'pending-activation.php', $vars );
7007
+ } else {
7008
+ fs_require_once_template( 'connect.php', $vars );
7009
+ }
7010
+ }
7011
+
7012
+ /**
7013
+ * Load required resources before add-ons page render.
7014
+ *
7015
+ * @author Vova Feldman (@svovaf)
7016
+ * @since 1.0.6
7017
+ */
7018
+ function _addons_page_load() {
7019
+ $this->_logger->entrance();
7020
+
7021
+ fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
7022
+
7023
+ wp_enqueue_script( 'plugin-install' );
7024
+ add_thickbox();
7025
+
7026
+ function fs_addons_body_class( $classes ) {
7027
+ $classes .= ' plugins-php';
7028
+
7029
+ return $classes;
7030
+ }
7031
+
7032
+ add_filter( 'admin_body_class', 'fs_addons_body_class' );
7033
+
7034
+ if ( ! $this->is_registered() && $this->is_org_repo_compliant() ) {
7035
+ $this->_admin_notices->add(
7036
+ sprintf( __fs( 'addons-info-external-message' ), '<b>' . $this->get_plugin_name() . '</b>' ),
7037
+ __fs( 'heads-up' ),
7038
+ 'update-nag'
7039
+ );
7040
+ }
7041
+ }
7042
+
7043
+ /**
7044
+ * Render add-ons page.
7045
+ *
7046
+ * @author Vova Feldman (@svovaf)
7047
+ * @since 1.0.6
7048
+ */
7049
+ function _addons_page_render() {
7050
+ $this->_logger->entrance();
7051
+
7052
+ $vars = array( 'slug' => $this->_slug );
7053
+ fs_require_once_template( 'add-ons.php', $vars );
7054
+ }
7055
+
7056
+ /* Pricing & Upgrade
7057
+ ------------------------------------------------------------------------------------------------------------------*/
7058
+ /**
7059
+ * Render pricing page.
7060
+ *
7061
+ * @author Vova Feldman (@svovaf)
7062
+ * @since 1.0.0
7063
+ */
7064
+ function _pricing_page_render() {
7065
+ $this->_logger->entrance();
7066
+
7067
+ $vars = array( 'slug' => $this->_slug );
7068
+
7069
+ if ( 'true' === fs_request_get( 'checkout', false ) ) {
7070
+ fs_require_once_template( 'checkout.php', $vars );
7071
+ } else {
7072
+ fs_require_once_template( 'pricing.php', $vars );
7073
+ }
7074
+ }
7075
+
7076
+ #region Contact Us ------------------------------------------------------------------
7077
+
7078
+ /**
7079
+ * Render contact-us page.
7080
+ *
7081
+ * @author Vova Feldman (@svovaf)
7082
+ * @since 1.0.3
7083
+ */
7084
+ function _contact_page_render() {
7085
+ $this->_logger->entrance();
7086
+
7087
+ $vars = array( 'slug' => $this->_slug );
7088
+ fs_require_once_template( 'contact.php', $vars );
7089
+ }
7090
+
7091
+ #endregion ------------------------------------------------------------------
7092
+
7093
+ /**
7094
+ * Hide all admin notices to prevent distractions.
7095
+ *
7096
+ * @author Vova Feldman (@svovaf)
7097
+ * @since 1.0.3
7098
+ *
7099
+ * @uses remove_all_actions()
7100
+ */
7101
+ function _hide_admin_notices() {
7102
+ remove_all_actions( 'admin_notices' );
7103
+ remove_all_actions( 'network_admin_notices' );
7104
+ remove_all_actions( 'all_admin_notices' );
7105
+ remove_all_actions( 'user_admin_notices' );
7106
+ }
7107
+
7108
+ function _clean_admin_content_section_hook() {
7109
+ $this->_hide_admin_notices();
7110
+
7111
+ // Hide footer.
7112
+ echo '<style>#wpfooter { display: none !important; }</style>';
7113
+ }
7114
+
7115
+ /**
7116
+ * Attach to admin_head hook to hide all admin notices.
7117
+ *
7118
+ * @author Vova Feldman (@svovaf)
7119
+ * @since 1.0.3
7120
+ */
7121
+ function _clean_admin_content_section() {
7122
+ add_action( 'admin_head', array( &$this, '_clean_admin_content_section_hook' ) );
7123
+ }
7124
+
7125
+ /* CSS & JavaScript
7126
+ ------------------------------------------------------------------------------------------------------------------*/
7127
+ /* function _enqueue_script($handle, $src) {
7128
+ $url = plugins_url( substr( WP_FS__DIR_JS, strlen( $this->_plugin_dir_path ) ) . '/assets/js/' . $src );
7129
+
7130
+ $this->_logger->entrance( 'script = ' . $url );
7131
+
7132
+ wp_enqueue_script( $handle, $url );
7133
+ }*/
7134
+
7135
+ /* SDK
7136
+ ------------------------------------------------------------------------------------------------------------------*/
7137
+ private $_user_api;
7138
+
7139
+ /**
7140
+ *
7141
+ * @author Vova Feldman (@svovaf)
7142
+ * @since 1.0.2
7143
+ *
7144
+ * @param bool $flush
7145
+ *
7146
+ * @return FS_Api
7147
+ */
7148
+ function get_api_user_scope( $flush = false ) {
7149
+ if ( ! isset( $this->_user_api ) || $flush ) {
7150
+ $this->_user_api = FS_Api::instance(
7151
+ $this->_slug,
7152
+ 'user',
7153
+ $this->_user->id,
7154
+ $this->_user->public_key,
7155
+ ! $this->is_live(),
7156
+ $this->_user->secret_key
7157
+ );
7158
+ }
7159
+
7160
+ return $this->_user_api;
7161
+ }
7162
+
7163
+ private $_site_api;
7164
+
7165
+ /**
7166
+ *
7167
+ * @author Vova Feldman (@svovaf)
7168
+ * @since 1.0.2
7169
+ *
7170
+ * @param bool $flush
7171
+ *
7172
+ * @return FS_Api
7173
+ */
7174
+ function get_api_site_scope( $flush = false ) {
7175
+ if ( ! isset( $this->_site_api ) || $flush ) {
7176
+ $this->_site_api = FS_Api::instance(
7177
+ $this->_slug,
7178
+ 'install',
7179
+ $this->_site->id,
7180
+ $this->_site->public_key,
7181
+ ! $this->is_live(),
7182
+ $this->_site->secret_key
7183
+ );
7184
+ }
7185
+
7186
+ return $this->_site_api;
7187
+ }
7188
+
7189
+ private $_plugin_api;
7190
+
7191
+ /**
7192
+ * Get plugin public API scope.
7193
+ *
7194
+ * @author Vova Feldman (@svovaf)
7195
+ * @since 1.0.7
7196
+ *
7197
+ * @return FS_Api
7198
+ */
7199
+ function get_api_plugin_scope() {
7200
+ if ( ! isset( $this->_plugin_api ) ) {
7201
+ $this->_plugin_api = FS_Api::instance(
7202
+ $this->_slug,
7203
+ 'plugin',
7204
+ $this->_plugin->id,
7205
+ $this->_plugin->public_key,
7206
+ ! $this->is_live()
7207
+ );
7208
+ }
7209
+
7210
+ return $this->_plugin_api;
7211
+ }
7212
+
7213
+ /**
7214
+ * Get site API scope object (fallback to public plugin scope when not registered).
7215
+ *
7216
+ * @author Vova Feldman (@svovaf)
7217
+ * @since 1.0.7
7218
+ *
7219
+ * @return FS_Api
7220
+ */
7221
+ function get_api_site_or_plugin_scope() {
7222
+ return $this->is_registered() ?
7223
+ $this->get_api_site_scope() :
7224
+ $this->get_api_plugin_scope();
7225
+ }
7226
+
7227
+ /**
7228
+ * Show trial promotional notice (if any trial exist).
7229
+ *
7230
+ * @author Vova Feldman (@svovaf)
7231
+ * @since 1.0.9
7232
+ *
7233
+ * @param $plans
7234
+ */
7235
+ function _check_for_trial_plans( $plans ) {
7236
+ $this->_storage->has_trial_plan = FS_Plan_Manager::instance()->has_trial_plan( $plans );
7237
+ }
7238
+
7239
+ /**
7240
+ * Show trial promotional notice (if any trial exist).
7241
+ *
7242
+ * @author Vova Feldman (@svovaf)
7243
+ * @since 1.0.9
7244
+ */
7245
+ function _add_trial_notice() {
7246
+ // Check if trial already utilized.
7247
+ if ( $this->_site->is_trial_utilized() ) {
7248
+ return;
7249
+ }
7250
+
7251
+ // Check if already paying.
7252
+ if ( $this->is_paying() ) {
7253
+ return;
7254
+ }
7255
+
7256
+ // Check if trial message is already shown.
7257
+ if ( $this->_admin_notices->has_sticky( 'trial_promotion' ) ) {
7258
+ return;
7259
+ }
7260
+
7261
+ $trial_plans = FS_Plan_Manager::instance()->get_trial_plans( $this->_plans );
7262
+ $trial_plans_count = count( $trial_plans );
7263
+
7264
+ // Check if any of the plans contains trial.
7265
+ if ( 0 === $trial_plans_count ) {
7266
+ return;
7267
+ }
7268
+
7269
+ /**
7270
+ * @var FS_Plugin_Plan $paid_plan
7271
+ */
7272
+ $paid_plan = $trial_plans[0];
7273
+ $require_subscription = $paid_plan->is_require_subscription;
7274
+ $upgrade_url = $this->get_trial_url();
7275
+ $cc_string = $require_subscription ?
7276
+ sprintf( __fs( 'no-commitment-for-x-days' ), $paid_plan->trial_period ) :
7277
+ __fs( 'no-cc-required' ) . '!';
7278
+
7279
+
7280
+ $total_paid_plans = count( $this->_plans ) - ( FS_Plan_Manager::instance()->has_free_plan( $this->_plans ) ? 1 : 0 );
7281
+
7282
+ if ( $total_paid_plans === $trial_plans_count ) {
7283
+ // All paid plans have trials.
7284
+ $message = sprintf(
7285
+ __fs( 'hey' ) . '! ' . __fs( 'trial-x-promotion-message' ),
7286
+ sprintf( '<b>%s</b>', $this->get_plugin_name() ),
7287
+ strtolower( __fs( 'awesome' ) ),
7288
+ $paid_plan->trial_period
7289
+ );
7290
+ } else {
7291
+ $plans_string = '';
7292
+ for ( $i = 0; $i < $trial_plans_count; $i ++ ) {
7293
+ $plans_string .= sprintf( '<a href="%s">%s</a>', $upgrade_url, $trial_plans[ $i ]->title );
7294
+
7295
+ if ( $i < $trial_plans_count - 2 ) {
7296
+ $plans_string .= ', ';
7297
+ } else if ( $i == $trial_plans_count - 2 ) {
7298
+ $plans_string .= ' and ';
7299
+ }
7300
+ }
7301
+
7302
+ // Not all paid plans have trials.
7303
+ $message = sprintf(
7304
+ __fs( 'hey' ) . '! ' . __fs( 'trial-x-promotion-message' ),
7305
+ sprintf( '<b>%s</b>', $this->get_plugin_name() ),
7306
+ $plans_string,
7307
+ $paid_plan->trial_period
7308
+ );
7309
+ }
7310
+
7311
+ $message .= ' ' . $cc_string;
7312
+
7313
+ // Add start trial button.
7314
+ $message .= ' ' . sprintf(
7315
+ '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s &nbsp;&#10140;</button></a>',
7316
+ $upgrade_url,
7317
+ __fs( 'start-free-trial' )
7318
+ );
7319
+
7320
+ $this->_admin_notices->add_sticky(
7321
+ $this->apply_filters( 'trial_promotion_message', $message ),
7322
+ 'trial_promotion',
7323
+ '',
7324
+ 'promotion'
7325
+ );
7326
+
7327
+ $this->_storage->trial_promotion_shown = WP_FS__SCRIPT_START_TIME;
7328
+ }
7329
+
7330
+ /* Action Links
7331
+ ------------------------------------------------------------------------------------------------------------------*/
7332
+ private $_action_links_hooked = false;
7333
+ private $_action_links = array();
7334
+
7335
+ /**
7336
+ * @author Vova Feldman (@svovaf)
7337
+ * @since 1.0.0
7338
+ *
7339
+ * @return bool
7340
+ */
7341
+ private function is_plugin_action_links_hooked() {
7342
+ $this->_logger->entrance( json_encode( $this->_action_links_hooked ) );
7343
+
7344
+ return $this->_action_links_hooked;
7345
+ }
7346
+
7347
+ /**
7348
+ * Hook to plugin action links filter.
7349
+ *
7350
+ * @author Vova Feldman (@svovaf)
7351
+ * @since 1.0.0
7352
+ */
7353
+ private function hook_plugin_action_links() {
7354
+ $this->_logger->entrance();
7355
+
7356
+ $this->_action_links_hooked = true;
7357
+
7358
+ $this->_logger->log( 'Adding action links hooks.' );
7359
+
7360
+ // Add action link to settings page.
7361
+ add_filter( 'plugin_action_links_' . $this->_plugin_basename, array(
7362
+ &$this,
7363
+ '_modify_plugin_action_links_hook'
7364
+ ), WP_FS__DEFAULT_PRIORITY, 2 );
7365
+ add_filter( 'network_admin_plugin_action_links_' . $this->_plugin_basename, array(
7366
+ &$this,
7367
+ '_modify_plugin_action_links_hook'
7368
+ ), WP_FS__DEFAULT_PRIORITY, 2 );
7369
+ }
7370
+
7371
+ /**
7372
+ * Add plugin action link.
7373
+ *
7374
+ * @author Vova Feldman (@svovaf)
7375
+ * @since 1.0.0
7376
+ *
7377
+ * @param $label
7378
+ * @param $url
7379
+ * @param bool $external
7380
+ * @param int $priority
7381
+ * @param bool $key
7382
+ */
7383
+ function add_plugin_action_link( $label, $url, $external = false, $priority = WP_FS__DEFAULT_PRIORITY, $key = false ) {
7384
+ $this->_logger->entrance();
7385
+
7386
+ if ( ! isset( $this->_action_links[ $priority ] ) ) {
7387
+ $this->_action_links[ $priority ] = array();
7388
+ }
7389
+
7390
+ if ( false === $key ) {
7391
+ $key = preg_replace( "/[^A-Za-z0-9 ]/", '', strtolower( $label ) );
7392
+ }
7393
+
7394
+ $this->_action_links[ $priority ][] = array(
7395
+ 'label' => $label,
7396
+ 'href' => $url,
7397
+ 'key' => $key,
7398
+ 'external' => $external
7399
+ );
7400
+ }
7401
+
7402
+ /**
7403
+ * Adds Upgrade and Add-Ons links to the main Plugins page link actions collection.
7404
+ *
7405
+ * @author Vova Feldman (@svovaf)
7406
+ * @since 1.0.0
7407
+ */
7408
+ function _add_upgrade_action_link() {
7409
+ $this->_logger->entrance();
7410
+
7411
+ if ( $this->is_registered() ) {
7412
+ if ( ! $this->is_paying() && $this->has_paid_plan() ) {
7413
+ $this->add_plugin_action_link(
7414
+ __fs( 'upgrade' ),
7415
+ $this->get_upgrade_url(),
7416
+ false,
7417
+ 20,
7418
+ 'upgrade'
7419
+ );
7420
+ }
7421
+
7422
+ if ( $this->_has_addons() ) {
7423
+ $this->add_plugin_action_link(
7424
+ __fs( 'add-ons' ),
7425
+ $this->_get_admin_page_url( 'addons' ),
7426
+ false,
7427
+ WP_FS__DEFAULT_PRIORITY,
7428
+ 'addons'
7429
+ );
7430
+ }
7431
+ }
7432
+ }
7433
+
7434
+ /**
7435
+ * Forward page to activation page.
7436
+ *
7437
+ * @author Vova Feldman (@svovaf)
7438
+ * @since 1.0.3
7439
+ */
7440
+ function _redirect_on_activation_hook() {
7441
+ $url = false;
7442
+ $plugin_fs = false;
7443
+
7444
+ if ( ! $this->is_addon() ) {
7445
+ $first_time_path = $this->_menu->get_first_time_path();
7446
+ $plugin_fs = $this;
7447
+ $url = $plugin_fs->is_activation_mode() ?
7448
+ $plugin_fs->get_activation_url() :
7449
+ ( empty( $first_time_path ) ?
7450
+ $this->_get_admin_page_url() :
7451
+ $first_time_path );
7452
+ } else {
7453
+ if ( $this->is_parent_plugin_installed() ) {
7454
+ $plugin_fs = self::get_parent_instance();
7455
+ }
7456
+
7457
+ if ( is_object( $plugin_fs ) ) {
7458
+ if ( ! $plugin_fs->is_registered() ) {
7459
+ // Forward to parent plugin connect when parent not registered.
7460
+ $url = $plugin_fs->get_activation_url();
7461
+ } else {
7462
+ // Forward to account page.
7463
+ $url = $plugin_fs->_get_admin_page_url( 'account' );
7464
+ }
7465
+ }
7466
+ }
7467
+
7468
+ if ( is_string( $url ) ) {
7469
+ fs_redirect( $url );
7470
+ exit();
7471
+ }
7472
+ }
7473
+
7474
+ /**
7475
+ * Modify plugin's page action links collection.
7476
+ *
7477
+ * @author Vova Feldman (@svovaf)
7478
+ * @since 1.0.0
7479
+ *
7480
+ * @param array $links
7481
+ * @param $file
7482
+ *
7483
+ * @return array
7484
+ */
7485
+ function _modify_plugin_action_links_hook( $links, $file ) {
7486
+ $this->_logger->entrance();
7487
+
7488
+ ksort( $this->_action_links );
7489
+
7490
+ foreach ( $this->_action_links as $new_links ) {
7491
+ foreach ( $new_links as $link ) {
7492
+ $links[ $link['key'] ] = '<a href="' . $link['href'] . '"' . ( $link['external'] ? ' target="_blank"' : '' ) . '>' . $link['label'] . '</a>';
7493
+ }
7494
+ }
7495
+
7496
+ /*
7497
+ * This HTML element is used to identify the correct plugin when attaching an event to its Deactivate link.
7498
+ *
7499
+ * If user is paying or in trial and have the free version installed,
7500
+ * assume that the deactivation is for the upgrade process, so this is not needed.
7501
+ */
7502
+ if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
7503
+ if ( isset( $links['deactivate'] ) ) {
7504
+ $links['deactivate'] .= '<i class="fs-slug" data-slug="' . $this->_slug . '"></i>';
7505
+ }
7506
+ }
7507
+
7508
+ return $links;
7509
+ }
7510
+
7511
+ /**
7512
+ * Adds admin message.
7513
+ *
7514
+ * @author Vova Feldman (@svovaf)
7515
+ * @since 1.0.4
7516
+ *
7517
+ * @param string $message
7518
+ * @param string $title
7519
+ * @param string $type
7520
+ */
7521
+ function add_admin_message( $message, $title = '', $type = 'success' ) {
7522
+ $this->_admin_notices->add( $message, $title, $type );
7523
+ }
7524
+
7525
+ /**
7526
+ * Adds sticky admin message.
7527
+ *
7528
+ * @author Vova Feldman (@svovaf)
7529
+ * @since 1.1.0
7530
+ *
7531
+ * @param string $message
7532
+ * @param string $id
7533
+ * @param string $title
7534
+ * @param string $type
7535
+ */
7536
+ function add_sticky_admin_message( $message, $id, $title = '', $type = 'success' ) {
7537
+ $this->_admin_notices->add_sticky( $message, $id, $title, $type );
7538
+ }
7539
+
7540
+ /* Plugin Auto-Updates (@since 1.0.4)
7541
+ ------------------------------------------------------------------------------------------------------------------*/
7542
+ /**
7543
+ * @var string[]
7544
+ */
7545
+ private static $_auto_updated_plugins;
7546
+
7547
+ /**
7548
+ * @todo TEST IF IT WORKS!!!
7549
+ *
7550
+ * Include plugins for automatic updates based on stored settings.
7551
+ *
7552
+ * @see http://wordpress.stackexchange.com/questions/131394/how-do-i-exclude-plugins-from-getting-automatically-updated/131404#131404
7553
+ *
7554
+ * @author Vova Feldman (@svovaf)
7555
+ * @since 1.0.4
7556
+ *
7557
+ * @param bool $update Whether to update (not used for plugins)
7558
+ * @param object $item The plugin's info
7559
+ *
7560
+ * @return bool
7561
+ */
7562
+ static function _include_plugins_in_auto_update( $update, $item ) {
7563
+ // Before version 3.8.2 the $item was the file name of the plugin,
7564
+ // while in 3.8.2 statistics were added (https://core.trac.wordpress.org/changeset/27905).
7565
+ $by_slug = ( (int) str_replace( '.', '', get_bloginfo( 'version' ) ) >= 382 );
7566
+
7567
+ if ( ! isset( self::$_auto_updated_plugins ) ) {
7568
+ $plugins = self::$_accounts->get_option( 'plugins', array() );
7569
+
7570
+ $identifiers = array();
7571
+ foreach ( $plugins as $p ) {
7572
+ /**
7573
+ * @var FS_Plugin $p
7574
+ */
7575
+ if ( isset( $p->auto_update ) && $p->auto_update ) {
7576
+ $identifiers[] = ( $by_slug ? $p->slug : plugin_basename( $p->file ) );
7577
+ }
7578
+ }
7579
+
7580
+ self::$_auto_updated_plugins = $identifiers;
7581
+ }
7582
+
7583
+ if ( in_array( $by_slug ? $item->slug : $item, self::$_auto_updated_plugins ) ) {
7584
+ return true;
7585
+ }
7586
+
7587
+ // Pass update decision to next filters
7588
+ return $update;
7589
+ }
7590
+
7591
+ #region Versioning ------------------------------------------------------------------
7592
+
7593
+ /**
7594
+ * Check if Freemius in SDK upgrade mode.
7595
+ *
7596
+ * @author Vova Feldman (@svovaf)
7597
+ * @since 1.0.9
7598
+ *
7599
+ * @return bool
7600
+ */
7601
+ function is_sdk_upgrade_mode() {
7602
+ return isset( $this->_storage->sdk_upgrade_mode ) ?
7603
+ $this->_storage->sdk_upgrade_mode :
7604
+ false;
7605
+ }
7606
+
7607
+ /**
7608
+ * Turn SDK upgrade mode off.
7609
+ *
7610
+ * @author Vova Feldman (@svovaf)
7611
+ * @since 1.0.9
7612
+ *
7613
+ * @return bool
7614
+ */
7615
+ function set_sdk_upgrade_complete() {
7616
+ $this->_storage->sdk_upgrade_mode = false;
7617
+ }
7618
+
7619
+ /**
7620
+ * Check if plugin upgrade mode.
7621
+ *
7622
+ * @author Vova Feldman (@svovaf)
7623
+ * @since 1.0.9
7624
+ *
7625
+ * @return bool
7626
+ */
7627
+ function is_plugin_upgrade_mode() {
7628
+ return isset( $this->_storage->plugin_upgrade_mode ) ?
7629
+ $this->_storage->plugin_upgrade_mode :
7630
+ false;
7631
+ }
7632
+
7633
+ /**
7634
+ * Turn plugin upgrade mode off.
7635
+ *
7636
+ * @author Vova Feldman (@svovaf)
7637
+ * @since 1.0.9
7638
+ *
7639
+ * @return bool
7640
+ */
7641
+ function set_plugin_upgrade_complete() {
7642
+ $this->_storage->plugin_upgrade_mode = false;
7643
+ }
7644
+
7645
+ #endregion ------------------------------------------------------------------
7646
+
7647
+ #region Marketing ------------------------------------------------------------------
7648
+
7649
+ /**
7650
+ * Check if current user purchased any other plugins before.
7651
+ *
7652
+ * @author Vova Feldman (@svovaf)
7653
+ * @since 1.0.9
7654
+ *
7655
+ * @return bool
7656
+ */
7657
+ function has_purchased_before() {
7658
+ // TODO: Implement has_purchased_before() method.
7659
+ }
7660
+
7661
+ /**
7662
+ * Check if current user classified as an agency.
7663
+ *
7664
+ * @author Vova Feldman (@svovaf)
7665
+ * @since 1.0.9
7666
+ *
7667
+ * @return bool
7668
+ */
7669
+ function is_agency() {
7670
+ // TODO: Implement is_agency() method.
7671
+ }
7672
+
7673
+ /**
7674
+ * Check if current user classified as a developer.
7675
+ *
7676
+ * @author Vova Feldman (@svovaf)
7677
+ * @since 1.0.9
7678
+ *
7679
+ * @return bool
7680
+ */
7681
+ function is_developer() {
7682
+ // TODO: Implement is_developer() method.
7683
+ }
7684
+
7685
+ /**
7686
+ * Check if current user classified as a business.
7687
+ *
7688
+ * @author Vova Feldman (@svovaf)
7689
+ * @since 1.0.9
7690
+ *
7691
+ * @return bool
7692
+ */
7693
+ function is_business() {
7694
+ // TODO: Implement is_business() method.
7695
+ }
7696
+
7697
+ #endregion ------------------------------------------------------------------
7698
+ }
lib/freemius/includes/class-fs-api.php ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.4
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Class FS_Api
15
+ *
16
+ * Wraps Freemius API SDK to handle:
17
+ * 1. Clock sync.
18
+ * 2. Fallback to HTTP when HTTPS fails.
19
+ * 3. Adds caching layer to GET requests.
20
+ * 4. Adds consistency for failed requests by using last cached version.
21
+ */
22
+ class FS_Api {
23
+ /**
24
+ * @var FS_Api[]
25
+ */
26
+ private static $_instances = array();
27
+
28
+ /**
29
+ * @var FS_Option_Manager Freemius options, options-manager.
30
+ */
31
+ private static $_options;
32
+
33
+ /**
34
+ * @var FS_Option_Manager API Caching layer
35
+ */
36
+ private static $_cache;
37
+
38
+ /**
39
+ * @var int Clock diff in seconds between current server to API server.
40
+ */
41
+ private static $_clock_diff;
42
+
43
+ /**
44
+ * @var Freemius_Api
45
+ */
46
+ private $_api;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_slug;
52
+
53
+ /**
54
+ * @var FS_Logger
55
+ * @since 1.0.4
56
+ */
57
+ private $_logger;
58
+
59
+ /**
60
+ * @param string $slug
61
+ * @param string $scope 'app', 'developer', 'user' or 'install'.
62
+ * @param number $id Element's id.
63
+ * @param string $public_key Public key.
64
+ * @param bool $is_sandbox
65
+ * @param bool|string $secret_key Element's secret key.
66
+ *
67
+ * @return FS_Api
68
+ */
69
+ static function instance( $slug, $scope, $id, $public_key, $is_sandbox, $secret_key = false ) {
70
+ $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
71
+
72
+ if ( ! isset( self::$_instances[ $identifier ] ) ) {
73
+ if ( 0 === count( self::$_instances ) ) {
74
+ self::_init();
75
+ }
76
+
77
+ self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox );
78
+ }
79
+
80
+ return self::$_instances[ $identifier ];
81
+ }
82
+
83
+ private static function _init() {
84
+ if ( ! class_exists( 'Freemius_Api' ) ) {
85
+ require_once( WP_FS__DIR_SDK . '/Freemius.php' );
86
+ }
87
+
88
+ self::$_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true );
89
+ self::$_cache = FS_Option_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME, true );
90
+
91
+ self::$_clock_diff = self::$_options->get_option( 'api_clock_diff', 0 );
92
+ Freemius_Api::SetClockDiff( self::$_clock_diff );
93
+
94
+ if ( self::$_options->get_option( 'api_force_http', false ) ) {
95
+ Freemius_Api::SetHttp();
96
+ }
97
+ }
98
+
99
+ /**
100
+ * @param string $slug
101
+ * @param string $scope 'app', 'developer', 'user' or 'install'.
102
+ * @param number $id Element's id.
103
+ * @param string $public_key Public key.
104
+ * @param bool|string $secret_key Element's secret key.
105
+ * @param bool $is_sandbox
106
+ */
107
+ private function __construct( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox ) {
108
+ $this->_api = new Freemius_Api( $scope, $id, $public_key, $secret_key, $is_sandbox );
109
+
110
+ $this->_slug = $slug;
111
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
112
+ }
113
+
114
+ /**
115
+ * Find clock diff between server and API server, and store the diff locally.
116
+ *
117
+ * @param bool|int $diff
118
+ *
119
+ * @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
120
+ */
121
+ private function _sync_clock_diff( $diff = false ) {
122
+ $this->_logger->entrance();
123
+
124
+ // Sync clock and store.
125
+ $new_clock_diff = ( false === $diff ) ?
126
+ $this->_api->FindClockDiff() :
127
+ $diff;
128
+
129
+ if ( $new_clock_diff === self::$_clock_diff ) {
130
+ return false;
131
+ }
132
+
133
+ self::$_clock_diff = $new_clock_diff;
134
+
135
+ // Update API clock's diff.
136
+ $this->_api->SetClockDiff( self::$_clock_diff );
137
+
138
+ // Store new clock diff in storage.
139
+ self::$_options->set_option( 'api_clock_diff', self::$_clock_diff, true );
140
+
141
+ return $new_clock_diff;
142
+ }
143
+
144
+ /**
145
+ * Override API call to enable retry with servers' clock auto sync method.
146
+ *
147
+ * @param string $path
148
+ * @param string $method
149
+ * @param array $params
150
+ * @param bool $retry Is in retry or first call attempt.
151
+ *
152
+ * @return array|mixed|string|void
153
+ */
154
+ private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
155
+ $this->_logger->entrance();
156
+
157
+ $result = $this->_api->Api( $path, $method, $params );
158
+
159
+ if ( null !== $result &&
160
+ isset( $result->error ) &&
161
+ 'request_expired' === $result->error->code
162
+ ) {
163
+ if ( ! $retry ) {
164
+ $diff = isset( $result->error->timestamp ) ?
165
+ ( time() - strtotime( $result->error->timestamp ) ) :
166
+ false;
167
+
168
+ // Try to sync clock diff.
169
+ if ( false !== $this->_sync_clock_diff( $diff ) ) {
170
+ // Retry call with new synced clock.
171
+ return $this->_call( $path, $method, $params, true );
172
+ }
173
+ }
174
+ }
175
+
176
+ if ( null !== $result && isset( $result->error ) ) {
177
+ // Log API errors.
178
+ $this->_logger->error( $result->error->message );
179
+ }
180
+
181
+ return $result;
182
+ }
183
+
184
+ /**
185
+ * Override API call to wrap it in servers' clock sync method.
186
+ *
187
+ * @param string $path
188
+ * @param string $method
189
+ * @param array $params
190
+ *
191
+ * @return array|mixed|string|void
192
+ * @throws Freemius_Exception
193
+ */
194
+ function call( $path, $method = 'GET', $params = array() ) {
195
+ return $this->_call( $path, $method, $params );
196
+ }
197
+
198
+ /**
199
+ * Get API request URL signed via query string.
200
+ *
201
+ * @param string $path
202
+ *
203
+ * @return string
204
+ */
205
+ function get_signed_url( $path ) {
206
+ return $this->_api->GetSignedUrl( $path );
207
+ }
208
+
209
+ /**
210
+ * @param string $path
211
+ * @param bool $flush
212
+ * @param int $expiration (optional) Time until expiration in seconds from now, defaults to 24 hours
213
+ *
214
+ * @return stdClass|mixed
215
+ */
216
+ function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
217
+ $cache_key = $this->get_cache_key( $path );
218
+
219
+ // Always flush during development.
220
+ if ( WP_FS__DEV_MODE || $this->_api->IsSandbox() ) {
221
+ $flush = true;
222
+ }
223
+
224
+ // Get result from cache.
225
+ $cache_entry = self::$_cache->get_option( $cache_key, false );
226
+
227
+ $fetch = false;
228
+ if ( $flush ||
229
+ false === $cache_entry ||
230
+ ! isset( $cache_entry->timestamp ) ||
231
+ ! is_numeric( $cache_entry->timestamp ) ||
232
+ $cache_entry->timestamp < WP_FS__SCRIPT_START_TIME
233
+ ) {
234
+ $fetch = true;
235
+ }
236
+
237
+ if ( $fetch ) {
238
+ $result = $this->call( $path );
239
+
240
+ if ( ! is_object( $result ) || isset( $result->error ) ) {
241
+ if ( is_object( $cache_entry ) &&
242
+ isset( $cache_entry->result ) &&
243
+ ! isset( $cache_entry->result->error )
244
+ ) {
245
+ // If there was an error during a newer data fetch,
246
+ // fallback to older data version.
247
+ $result = $cache_entry->result;
248
+ } else {
249
+ // If no older data version, return result without
250
+ // caching the error.
251
+ return $result;
252
+ }
253
+ }
254
+
255
+ $cache_entry = new stdClass();
256
+ $cache_entry->result = $result;
257
+ $cache_entry->timestamp = WP_FS__SCRIPT_START_TIME + $expiration;
258
+ self::$_cache->set_option( $cache_key, $cache_entry, true );
259
+ }
260
+
261
+ return $cache_entry->result;
262
+ }
263
+
264
+ private function get_cache_key( $path, $method = 'GET', $params = array() ) {
265
+ $canonized = $this->_api->CanonizePath( $path );
266
+ // $exploded = explode('/', $canonized);
267
+ // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
268
+ return $method . ':' . $canonized . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
269
+ }
270
+
271
+ /**
272
+ * Test API connectivity.
273
+ *
274
+ * @since 1.0.9 If fails, try to fallback to HTTP.
275
+ *
276
+ * @param null|string $unique_anonymous_id
277
+ *
278
+ * @return bool True if successful connectivity to the API.
279
+ */
280
+ function test( $unique_anonymous_id = null ) {
281
+ $this->_logger->entrance();
282
+
283
+ if ( ! function_exists( 'curl_version' ) ) {
284
+ // cUrl extension is not active.
285
+ return false;
286
+ }
287
+
288
+ $test = is_null( $unique_anonymous_id ) ?
289
+ $this->_api->Test() :
290
+ $this->_api->Test( $this->_call( 'ping.json?uid=' . $unique_anonymous_id ) );
291
+
292
+ if ( false === $test && $this->_api->IsHttps() ) {
293
+ // Fallback to HTTP, since HTTPS fails.
294
+ $this->_api->SetHttp();
295
+
296
+ self::$_options->set_option( 'api_force_http', true, true );
297
+
298
+ $test = is_null( $unique_anonymous_id ) ?
299
+ $this->_api->Test() :
300
+ $this->_api->Test( $this->_call( 'ping.json?uid=' . $unique_anonymous_id ) );
301
+ }
302
+
303
+ return $test;
304
+ }
305
+
306
+ /**
307
+ * Ping API for connectivity test, and return result object.
308
+ *
309
+ * @author Vova Feldman (@svovaf)
310
+ * @since 1.0.9
311
+ *
312
+ * @param null|string $unique_anonymous_id
313
+ * @param bool $is_update False if new plugin installation.
314
+ *
315
+ * @return object
316
+ */
317
+ function ping( $unique_anonymous_id = null, $is_update = false ) {
318
+ return is_null( $unique_anonymous_id ) ?
319
+ $this->_api->Ping() :
320
+ $this->_call( 'ping.json?' . http_build_query( array(
321
+ 'uid' => $unique_anonymous_id,
322
+ 'is_update' => $is_update,
323
+ ) ) );
324
+ }
325
+
326
+ /**
327
+ * Check if valid ping request result.
328
+ *
329
+ * @author Vova Feldman (@svovaf)
330
+ * @since 1.1.1
331
+ *
332
+ * @param mixed $pong
333
+ *
334
+ * @return bool
335
+ */
336
+ function is_valid_ping( $pong ) {
337
+ return $this->_api->Test( $pong );
338
+ }
339
+
340
+ function get_url( $path = '' ) {
341
+ return $this->_api->GetUrl( $path );
342
+ }
343
+
344
+ /**
345
+ * Clear API cache.
346
+ *
347
+ * @author Vova Feldman (@svovaf)
348
+ * @since 1.0.9
349
+ */
350
+ static function clear_cache() {
351
+ self::$_cache = FS_Option_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME, true );
352
+ self::$_cache->clear( true );
353
+ }
354
+ }
lib/freemius/includes/class-fs-logger.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Logger {
14
+ private $_id;
15
+ private $_on = false;
16
+ private $_echo = false;
17
+ private $_file_start = 0;
18
+
19
+ private static $LOGGERS = array();
20
+ private static $LOG = array();
21
+ private static $CNT = 0;
22
+ private static $_HOOKED_FOOTER = false;
23
+
24
+ private function __construct( $id, $on = false, $echo = false ) {
25
+ $this->_id = $id;
26
+
27
+ $bt = debug_backtrace();
28
+ $caller = $bt[2];
29
+
30
+ $this->_file_start = strpos( $caller['file'], 'plugins' ) + strlen( 'plugins/' );
31
+
32
+ if ( $on ) {
33
+ $this->on();
34
+ }
35
+ if ( $echo ) {
36
+ $this->echo_on();
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @param string $id
42
+ * @param bool $on
43
+ * @param bool $echo
44
+ *
45
+ * @return FS_Logger
46
+ */
47
+ public static function get_logger( $id, $on = false, $echo = false ) {
48
+ $id = strtolower( $id );
49
+
50
+ if ( ! isset( self::$LOGGERS[ $id ] ) ) {
51
+ self::$LOGGERS[ $id ] = new FS_Logger( $id, $on, $echo );
52
+ }
53
+
54
+ return self::$LOGGERS[ $id ];
55
+ }
56
+
57
+ private static function _hook_footer() {
58
+ if ( self::$_HOOKED_FOOTER ) {
59
+ return;
60
+ }
61
+
62
+ if ( is_admin() ) {
63
+ add_action( 'admin_footer', 'FS_Logger::dump', 100 );
64
+ } else {
65
+ add_action( 'wp_footer', 'FS_Logger::dump', 100 );
66
+ }
67
+ }
68
+
69
+ function is_on() {
70
+ return $this->_on;
71
+ }
72
+
73
+ function on() {
74
+ $this->_on = true;
75
+
76
+ self::_hook_footer();
77
+ }
78
+
79
+ function echo_on() {
80
+ $this->_on;
81
+
82
+ $this->_echo = true;
83
+ }
84
+
85
+ function is_echo_on() {
86
+ return $this->_echo;
87
+ }
88
+
89
+
90
+ private function _log( &$message, $type = 'log', $wrapper ) {
91
+ if ( ! $this->is_on() ) {
92
+ return;
93
+ }
94
+
95
+ $bt = debug_backtrace();
96
+ $depth = $wrapper ? 3 : 2;
97
+ while ( $depth < count( $bt ) - 1 && 'eval' === $bt[ $depth ]['function'] ) {
98
+ $depth ++;
99
+ }
100
+
101
+ $caller = $bt[ $depth ];
102
+
103
+ $log = array_merge( $caller, array(
104
+ 'cnt' => self::$CNT ++,
105
+ 'logger' => $this,
106
+ 'timestamp' => date( WP_FS__LOG_DATETIME_FORMAT . ':u' ),
107
+ 'type' => $type,
108
+ 'msg' => $message,
109
+ ) );
110
+
111
+ self::$LOG[] = $log;
112
+
113
+ if ( $this->is_echo_on() ) {
114
+ echo self::_format_html( $log ) . "\n";
115
+ }
116
+ }
117
+
118
+ function log( $message, $wrapper = false ) {
119
+ $this->_log( $message, 'log', $wrapper );
120
+ }
121
+
122
+ function info( $message, $wrapper = false ) {
123
+ $this->_log( $message, 'info', $wrapper );
124
+ }
125
+
126
+ function warn( $message, $wrapper = false ) {
127
+ $this->_log( $message, 'warn', $wrapper );
128
+ }
129
+
130
+ function error( $message, $wrapper = false ) {
131
+ $this->_log( $message, 'error', $wrapper );
132
+ }
133
+
134
+ function entrance( $message = '', $wrapper = false ) {
135
+ $msg = 'Entrance' . ( empty( $message ) ? '' : ' > ' ) . $message;
136
+
137
+ $this->_log( $msg, 'log', $wrapper );
138
+ }
139
+
140
+ function departure( $message = '', $wrapper = false ) {
141
+ $msg = 'Departure' . ( empty( $message ) ? '' : ' > ' ) . $message;
142
+
143
+ $this->_log( $msg, 'log', $wrapper );
144
+ }
145
+
146
+ private static function _format( $log, $show_type = true ) {
147
+ return '[' . str_pad( $log['cnt'], strlen( self::$CNT ), '0', STR_PAD_LEFT ) . '] [' . $log['logger']->_id . '] ' . ( $show_type ? '[' . $log['type'] . ']' : '' ) . $log['function'] . ' >> ' . $log['msg'] . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ') ' : '' ) . ' [' . $log['timestamp'] . ']';
148
+ }
149
+
150
+ private static function _format_html( $log ) {
151
+ return '<div style="font-size: 11px; padding: 3px; background: #ccc; margin-bottom: 3px;">[' . $log['cnt'] . '] [' . $log['logger']->_id . '] [' . $log['type'] . '] <b><code style="color: blue;">' . $log['function'] . '</code> >> <b style="color: darkorange;">' . $log['msg'] . '</b></b>' . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ')' : '' ) . ' [' . $log['timestamp'] . ']</div>';
152
+ }
153
+
154
+ static function dump() {
155
+ ?>
156
+ <!-- BEGIN: Freemius PHP Console Log -->
157
+ <script type="text/javascript">
158
+ <?php
159
+ foreach (self::$LOG as $log)
160
+ {
161
+ echo 'console.' . $log['type'] . '(' . json_encode(self::_format($log, false)) . ')' . "\n";
162
+ }
163
+ ?>
164
+ </script>
165
+ <!-- END: Freemius PHP Console Log -->
166
+ <?php
167
+ }
168
+ }
lib/freemius/includes/class-fs-plugin-updater.php ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.4
7
+ *
8
+ * @link https://github.com/easydigitaldownloads/EDD-License-handler/blob/master/EDD_SL_Plugin_Updater.php
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
+
15
+ // Uncomment this line for testing.
16
+ // set_site_transient( 'update_plugins', null );
17
+
18
+ class FS_Plugin_Updater {
19
+
20
+ /**
21
+ * @var Freemius
22
+ * @since 1.0.4
23
+ */
24
+ private $_fs;
25
+ /**
26
+ * @var FS_Logger
27
+ * @since 1.0.4
28
+ */
29
+ private $_logger;
30
+
31
+ function __construct( Freemius $freemius ) {
32
+ $this->_fs = $freemius;
33
+
34
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
35
+
36
+ $this->_filters();
37
+ }
38
+
39
+ /**
40
+ * Initiate required filters.
41
+ *
42
+ * @author Vova Feldman (@svovaf)
43
+ * @since 1.0.4
44
+ */
45
+ private function _filters() {
46
+ // Override request for plugin information
47
+ add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
48
+
49
+ // WP 3.0+
50
+ add_filter( 'pre_set_site_transient_update_plugins', array(
51
+ &$this,
52
+ 'pre_set_site_transient_update_plugins_filter'
53
+ ) );
54
+
55
+ if ( ! WP_FS__IS_PRODUCTION_MODE ) {
56
+ add_filter( 'http_request_host_is_external', array(
57
+ $this,
58
+ 'http_request_host_is_external_filter'
59
+ ), 10, 3 );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
65
+ * During development mode we want to be able updating plugin versions via our localhost repository. This
66
+ * filter white-list all domains including "api.freemius".
67
+ *
68
+ * @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
69
+ *
70
+ * @author Vova Feldman (@svovaf)
71
+ * @since 1.0.4
72
+ *
73
+ * @param bool $allow
74
+ * @param string $host
75
+ * @param string $url
76
+ *
77
+ * @return bool
78
+ */
79
+ function http_request_host_is_external_filter( $allow, $host, $url ) {
80
+ return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
81
+ }
82
+
83
+ /**
84
+ * Check for Updates at the defined API endpoint and modify the update array.
85
+ *
86
+ * This function dives into the update api just when WordPress creates its update array,
87
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
88
+ * It is reassembled from parts of the native WordPress plugin update code.
89
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
90
+ *
91
+ * @author Vova Feldman (@svovaf)
92
+ * @since 1.0.4
93
+ *
94
+ * @uses FS_Api
95
+ *
96
+ * @param stdClass $transient_data Update array build by WordPress.
97
+ *
98
+ * @return array Modified update array with custom plugin data.
99
+ */
100
+ function pre_set_site_transient_update_plugins_filter( $transient_data ) {
101
+ $this->_logger->entrance();
102
+
103
+ if ( empty( $transient_data ) ||
104
+ defined( 'WP_FS__UNINSTALL_MODE' )
105
+ ) {
106
+ return $transient_data;
107
+ }
108
+
109
+ // Get plugin's newest update.
110
+ $new_version = $this->_fs->get_update();
111
+
112
+ if ( is_object( $new_version ) ) {
113
+ $this->_logger->log( 'Found newer plugin version ' . $new_version->version );
114
+
115
+ $plugin_details = new stdClass();
116
+ $plugin_details->slug = $this->_fs->get_slug();
117
+ $plugin_details->new_version = $new_version->version;
118
+ $plugin_details->url = WP_FS__ADDRESS;
119
+ $plugin_details->package = $new_version->url;
120
+ $plugin_details->plugin = $this->_fs->get_plugin_basename();
121
+
122
+ // Add plugin to transient data.
123
+ $transient_data->response[ $this->_fs->get_plugin_basename() ] = $plugin_details;
124
+ }
125
+
126
+ return $transient_data;
127
+ }
128
+
129
+ /**
130
+ * Try to fetch plugin's info from .org repository.
131
+ *
132
+ * @author Vova Feldman (@svovaf)
133
+ * @since 1.0.5
134
+ *
135
+ * @param string $action
136
+ * @param array $args
137
+ *
138
+ * @return bool|mixed
139
+ */
140
+ private function _fetch_plugin_info_from_repository( $action, $args ) {
141
+ $url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
142
+ if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
143
+ $url = set_url_scheme( $url, 'https' );
144
+ }
145
+
146
+ $args = array(
147
+ 'timeout' => 15,
148
+ 'body' => array(
149
+ 'action' => $action,
150
+ 'request' => serialize( $args )
151
+ )
152
+ );
153
+
154
+ $request = wp_remote_post( $url, $args );
155
+
156
+ if ( is_wp_error( $request ) ) {
157
+ return false;
158
+ }
159
+
160
+ $res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
161
+
162
+ if ( ! is_object( $res ) && ! is_array( $res ) ) {
163
+ return false;
164
+ }
165
+
166
+ return $res;
167
+ }
168
+
169
+ /**
170
+ * Updates information on the "View version x.x details" page with custom data.
171
+ *
172
+ * @author Vova Feldman (@svovaf)
173
+ * @since 1.0.4
174
+ *
175
+ * @uses FS_Api
176
+ *
177
+ * @param object $data
178
+ * @param string $action
179
+ * @param mixed $args
180
+ *
181
+ * @return object
182
+ */
183
+ function plugins_api_filter( $data, $action = '', $args = null ) {
184
+ $this->_logger->entrance();
185
+
186
+ if ( ( 'plugin_information' !== $action ) ||
187
+ ! isset( $args->slug )
188
+ ) {
189
+ return $data;
190
+ }
191
+
192
+ $addon = false;
193
+ $is_addon = false;
194
+
195
+ if ( $this->_fs->get_slug() !== $args->slug ) {
196
+ $addon = $this->_fs->get_addon_by_slug( $args->slug );
197
+
198
+ if ( ! is_object( $addon ) ) {
199
+ return $data;
200
+ }
201
+
202
+ $is_addon = true;
203
+ }
204
+
205
+ $plugin_in_repo = false;
206
+ if ( ! $is_addon ) {
207
+ // Try to fetch info from .org repository.
208
+ $data = $this->_fetch_plugin_info_from_repository( $action, $args );
209
+
210
+ $plugin_in_repo = ( false !== $data );
211
+ }
212
+
213
+ if ( ! $plugin_in_repo ) {
214
+ $data = $args;
215
+
216
+ // Fetch as much as possible info from local files.
217
+ $plugin_local_data = $this->_fs->get_plugin_data();
218
+ $data->name = $plugin_local_data['Name'];
219
+ $data->author = $plugin_local_data['Author'];
220
+ $data->sections = array(
221
+ 'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.',
222
+ );
223
+
224
+ // @todo Store extra plugin info on Freemius or parse readme.txt markup.
225
+ /*$info = $this->_fs->get_api_site_scope()->call('/information.json');
226
+
227
+ if ( !isset($info->error) ) {
228
+ $data = $info;
229
+ }*/
230
+ }
231
+
232
+ // Get plugin's newest update.
233
+ $new_version = $this->_fs->_fetch_latest_version( $is_addon ? $addon->id : false );
234
+
235
+ if ( $is_addon ) {
236
+ $data->name = $addon->title . ' ' . __fs( 'addon' );
237
+ $data->slug = $addon->slug;
238
+ $data->url = WP_FS__ADDRESS;
239
+ $data->package = $new_version->url;
240
+ }
241
+
242
+ if ( ! $plugin_in_repo ) {
243
+ $data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
244
+ $data->requires = $new_version->requires_platform_version;
245
+ $data->tested = $new_version->tested_up_to_version;
246
+ }
247
+
248
+ $data->version = $new_version->version;
249
+ $data->download_link = $new_version->url;
250
+
251
+ return $data;
252
+ }
253
+ }
lib/freemius/includes/class-fs-security.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ define( 'WP_FS__SECURITY_PARAMS_PREFIX', 's_' );
14
+
15
+ class FS_Security {
16
+ /**
17
+ * @var FS_Security
18
+ * @since 1.0.3
19
+ */
20
+ private static $_instance;
21
+ /**
22
+ * @var FS_Logger
23
+ * @since 1.0.3
24
+ */
25
+ private static $_logger;
26
+
27
+ public static function instance() {
28
+ if ( ! isset( self::$_instance ) ) {
29
+ self::$_instance = new FS_Security();
30
+ self::$_logger = FS_Logger::get_logger( WP_FS__SLUG, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
31
+ }
32
+
33
+ return self::$_instance;
34
+ }
35
+
36
+ private function __construct() {
37
+ }
38
+
39
+ function get_secure_token( FS_Scope_Entity $entity, $timestamp, $action = '' ) {
40
+ return md5(
41
+ $timestamp .
42
+ $entity->id .
43
+ $entity->secret_key .
44
+ $entity->public_key .
45
+ $action
46
+ );
47
+ }
48
+
49
+ function get_context_params( FS_Scope_Entity $entity, $timestamp = false, $action = '' ) {
50
+ if ( false === $timestamp ) {
51
+ $timestamp = time();
52
+ }
53
+
54
+ return array(
55
+ 's_ctx_type' => $entity->get_type(),
56
+ 's_ctx_id' => $entity->id,
57
+ 's_ctx_ts' => $timestamp,
58
+ 's_ctx_secure' => $this->get_secure_token( $entity, $timestamp, $action ),
59
+ );
60
+ }
61
+ }
lib/freemius/includes/entities/class-fs-entity.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Get object's public variables.
15
+ *
16
+ * @author Vova Feldman (@svovaf)
17
+ * @since 1.0.0
18
+ *
19
+ * @param object $object
20
+ *
21
+ * @return array
22
+ */
23
+ function fs_get_object_public_vars( $object ) {
24
+ return get_object_vars( $object );
25
+ }
26
+
27
+ class FS_Entity {
28
+ /**
29
+ * @var number
30
+ */
31
+ public $id;
32
+ /**
33
+ * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.
34
+ */
35
+ public $updated;
36
+ /**
37
+ * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.
38
+ */
39
+ public $created;
40
+
41
+ /**
42
+ * @param bool|stdClass $entity
43
+ */
44
+ function __construct( $entity = false ) {
45
+ if ( ! ( $entity instanceof stdClass ) ) {
46
+ return;
47
+ }
48
+
49
+ $props = fs_get_object_public_vars( $this );
50
+
51
+ foreach ( $props as $key => $def_value ) {
52
+ $this->{$key} = isset( $entity->{$key} ) ?
53
+ $entity->{$key} :
54
+ $def_value;
55
+ }
56
+ }
57
+
58
+ static function get_type() {
59
+ return 'type';
60
+ }
61
+
62
+ /**
63
+ * @author Vova Feldman (@svovaf)
64
+ * @since 1.0.6
65
+ *
66
+ * @param FS_Entity $entity1
67
+ * @param FS_Entity $entity2
68
+ *
69
+ * @return bool
70
+ */
71
+ static function equals( $entity1, $entity2 ) {
72
+ if ( is_null( $entity1 ) && is_null( $entity2 ) ) {
73
+ return true;
74
+ } else if ( is_object( $entity1 ) && is_object( $entity2 ) ) {
75
+ return ( $entity1->id == $entity2->id );
76
+ } else if ( is_object( $entity1 ) ) {
77
+ return is_null( $entity1->id );
78
+ } else {
79
+ return is_null( $entity2->id );
80
+ }
81
+ }
82
+
83
+ private $_is_updated = false;
84
+
85
+ /**
86
+ * Update object property.
87
+ *
88
+ * @author Vova Feldman (@svovaf)
89
+ * @since 1.0.9
90
+ *
91
+ * @param string|array[string]mixed $key
92
+ * @param string|bool $val
93
+ *
94
+ * @return bool
95
+ */
96
+ function update( $key, $val = false ) {
97
+ if ( ! is_array( $key ) ) {
98
+ $key = array( $key => $val );
99
+ }
100
+
101
+ $is_updated = false;
102
+
103
+ foreach ( $key as $k => $v ) {
104
+ if ( $this->{$k} === $v ) {
105
+ continue;
106
+ }
107
+
108
+ if ( ( is_string( $this->{$k} ) && is_numeric( $v ) ||
109
+ ( is_numeric( $this->{$k} ) && is_string( $v ) ) ) &&
110
+ $this->{$k} == $v
111
+ ) {
112
+ continue;
113
+ }
114
+
115
+ // Update value.
116
+ $this->{$k} = $v;
117
+
118
+ $is_updated = true;
119
+ }
120
+
121
+ $this->_is_updated = $is_updated;
122
+
123
+ return $is_updated;
124
+ }
125
+
126
+ /**
127
+ * Checks if entity was updated.
128
+ *
129
+ * @author Vova Feldman (@svovaf)
130
+ * @since 1.0.9
131
+ *
132
+ * @return bool
133
+ */
134
+ function is_updated() {
135
+ return $this->_is_updated;
136
+ }
137
+
138
+ /**
139
+ * @param $id
140
+ *
141
+ * @author Vova Feldman (@svovaf)
142
+ * @since 1.1.2
143
+ *
144
+ * @return bool
145
+ */
146
+ static function is_valid_id($id){
147
+ return is_numeric($id);
148
+ }
149
+ }
lib/freemius/includes/entities/class-fs-plugin-info.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin_Info extends FS_Entity {
14
+ public $plugin_id;
15
+ public $description;
16
+ public $short_description;
17
+ public $banner_url;
18
+ public $card_banner_url;
19
+ public $selling_point_0;
20
+ public $selling_point_1;
21
+ public $selling_point_2;
22
+ public $screenshots;
23
+
24
+ /**
25
+ * @param stdClass|bool $plugin_info
26
+ */
27
+ function __construct( $plugin_info = false ) {
28
+ parent::__construct( $plugin_info );
29
+ }
30
+
31
+ static function get_type() {
32
+ return 'plugin';
33
+ }
34
+ }
lib/freemius/includes/entities/class-fs-plugin-license.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.5
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin_License extends FS_Entity {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var number
19
+ */
20
+ public $plugin_id;
21
+ /**
22
+ * @var number
23
+ */
24
+ public $user_id;
25
+ /**
26
+ * @var number
27
+ */
28
+ public $plan_id;
29
+ /**
30
+ * @var number
31
+ */
32
+ public $pricing_id;
33
+ /**
34
+ * @var int
35
+ */
36
+ public $quota;
37
+ /**
38
+ * @var int
39
+ */
40
+ public $activated;
41
+ /**
42
+ * @var int
43
+ */
44
+ public $activated_local;
45
+ /**
46
+ * @var string
47
+ */
48
+ public $expiration;
49
+ /**
50
+ * @var bool $is_free_localhost Defaults to true. If true, allow unlimited localhost installs with the same
51
+ * license.
52
+ */
53
+ public $is_free_localhost;
54
+ /**
55
+ * @var bool $is_block_features Defaults to true. If false, don't block features after license expiry - only
56
+ * block updates and support.
57
+ */
58
+ public $is_block_features;
59
+ /**
60
+ * @var bool
61
+ */
62
+ public $is_cancelled;
63
+
64
+ #endregion Properties
65
+
66
+ /**
67
+ * @param stdClass|bool $license
68
+ */
69
+ function __construct( $license = false ) {
70
+ parent::__construct( $license );
71
+ }
72
+
73
+ static function get_type() {
74
+ return 'license';
75
+ }
76
+
77
+ /**
78
+ * Check how many site activations left.
79
+ *
80
+ * @author Vova Feldman (@svovaf)
81
+ * @since 1.0.5
82
+ *
83
+ * @return int
84
+ */
85
+ function left() {
86
+ if ( $this->is_expired() ) {
87
+ return 0;
88
+ }
89
+
90
+ return ( $this->quota - $this->activated - ( $this->is_free_localhost ? 0 : $this->activated_local ) );
91
+ }
92
+
93
+ /**
94
+ * @author Vova Feldman (@svovaf)
95
+ * @since 1.0.5
96
+ *
97
+ * @return bool
98
+ */
99
+ function is_expired() {
100
+ return ! $this->is_lifetime() && ( strtotime( $this->expiration ) < WP_FS__SCRIPT_START_TIME );
101
+ }
102
+
103
+ /**
104
+ * @author Vova Feldman (@svovaf)
105
+ * @since 1.0.6
106
+ *
107
+ * @return bool
108
+ */
109
+ function is_lifetime() {
110
+ return is_null( $this->expiration );
111
+ }
112
+
113
+ /**
114
+ * Check if license is fully utilized.
115
+ *
116
+ * @author Vova Feldman (@svovaf)
117
+ * @since 1.0.6
118
+ *
119
+ * @param bool $is_localhost
120
+ *
121
+ * @return bool
122
+ */
123
+ function is_utilized( $is_localhost = null ) {
124
+ if ( is_null( $is_localhost ) ) {
125
+ $is_localhost = WP_FS__IS_LOCALHOST_FOR_SERVER;
126
+ }
127
+
128
+ return ! ( $this->is_free_localhost && $is_localhost ) &&
129
+ ( $this->quota <= $this->activated + ( $this->is_free_localhost ? 0 : $this->activated_local ) );
130
+ }
131
+
132
+ /**
133
+ * Check if license's plan features are enabled.
134
+ *
135
+ * - Either if plan not expired
136
+ * - If expired, based on the configuration to block features or not.
137
+ *
138
+ * @author Vova Feldman (@svovaf)
139
+ * @since 1.0.6
140
+ *
141
+ * @return bool
142
+ */
143
+ function is_features_enabled() {
144
+ return ( ! $this->is_block_features || ! $this->is_expired() );
145
+ }
146
+
147
+ /**
148
+ * Subscription considered to be new without any payments
149
+ * if the license expires in less than 24 hours
150
+ * from the license creation.
151
+ *
152
+ * @author Vova Feldman (@svovaf)
153
+ * @since 1.0.9
154
+ *
155
+ * @return bool
156
+ */
157
+ function is_first_payment_pending() {
158
+ return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->expiration ) - strtotime( $this->created ) );
159
+ }
160
+ }
lib/freemius/includes/entities/class-fs-plugin-plan.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.5
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin_Plan extends FS_Entity {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ public $title;
21
+ /**
22
+ * @var string
23
+ */
24
+ public $name;
25
+ /**
26
+ * @var int Trial days.
27
+ */
28
+ public $trial_period;
29
+ /**
30
+ * @var string If true, require payment for trial.
31
+ */
32
+ public $is_require_subscription;
33
+
34
+ #endregion Properties
35
+
36
+ /**
37
+ * @param object|bool $plan
38
+ */
39
+ function __construct( $plan = false ) {
40
+ parent::__construct( $plan );
41
+
42
+ if ( is_object( $plan ) ) {
43
+ $this->name = strtolower( $plan->name );
44
+ }
45
+ }
46
+
47
+ static function get_type() {
48
+ return 'plan';
49
+ }
50
+
51
+ /**
52
+ * @author Vova Feldman (@svovaf)
53
+ * @since 1.0.9
54
+ *
55
+ * @return bool
56
+ */
57
+ function is_free() {
58
+ return ( 'free' === $this->name );
59
+ }
60
+
61
+ /**
62
+ * @author Vova Feldman (@svovaf)
63
+ * @since 1.0.9
64
+ *
65
+ * @return bool
66
+ */
67
+ function has_trial() {
68
+ return ! $this->is_free() &&
69
+ is_numeric( $this->trial_period ) && ( $this->trial_period > 0 );
70
+ }
71
+ }
lib/freemius/includes/entities/class-fs-plugin-tag.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.4
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin_Tag extends FS_Entity {
14
+ public $version;
15
+ public $url;
16
+
17
+ function __construct( $tag = false ) {
18
+ parent::__construct( $tag );
19
+ }
20
+
21
+ static function get_type() {
22
+ return 'tag';
23
+ }
24
+ }
lib/freemius/includes/entities/class-fs-plugin.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin extends FS_Scope_Entity {
14
+ /**
15
+ * @since 1.0.6
16
+ * @var null|number
17
+ */
18
+ public $parent_plugin_id;
19
+ /**
20
+ * @var string
21
+ */
22
+ public $title;
23
+ /**
24
+ * @var string
25
+ */
26
+ public $slug;
27
+
28
+ #region Install Specific Properties
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ public $file;
34
+ /**
35
+ * @var string
36
+ */
37
+ public $version;
38
+ /**
39
+ * @var bool
40
+ */
41
+ public $auto_update;
42
+ /**
43
+ * @var FS_Plugin_Info
44
+ */
45
+ public $info;
46
+ /**
47
+ * @since 1.0.9
48
+ *
49
+ * @var bool
50
+ */
51
+ public $is_premium;
52
+ /**
53
+ * @since 1.0.9
54
+ *
55
+ * @var bool
56
+ */
57
+ public $is_live;
58
+
59
+ #endregion Install Specific Properties
60
+
61
+ /**
62
+ * @param stdClass|bool $plugin
63
+ */
64
+ function __construct( $plugin = false ) {
65
+ parent::__construct( $plugin );
66
+
67
+ $this->is_premium = false;
68
+ $this->is_live = true;
69
+
70
+ if ( isset( $plugin->info ) && is_object( $plugin->info ) ) {
71
+ $this->info = new FS_Plugin_Info( $plugin->info );
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check if plugin is an add-on (has parent).
77
+ *
78
+ * @author Vova Feldman (@svovaf)
79
+ * @since 1.0.6
80
+ *
81
+ * @return bool
82
+ */
83
+ function is_addon() {
84
+ return isset( $this->parent_plugin_id ) && is_numeric( $this->parent_plugin_id );
85
+ }
86
+
87
+ static function get_type() {
88
+ return 'plugin';
89
+ }
90
+ }
lib/freemius/includes/entities/class-fs-scope-entity.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.4
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Scope_Entity extends FS_Entity {
14
+ /**
15
+ * @var string
16
+ */
17
+ public $public_key;
18
+ /**
19
+ * @var string
20
+ */
21
+ public $secret_key;
22
+
23
+ /**
24
+ * @param bool|stdClass $scope_entity
25
+ */
26
+ function __construct( $scope_entity = false ) {
27
+ parent::__construct( $scope_entity );
28
+ }
29
+ }
lib/freemius/includes/entities/class-fs-site.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Site extends FS_Scope_Entity {
14
+ /**
15
+ * @var string
16
+ */
17
+ public $slug;
18
+ /**
19
+ * @var number
20
+ */
21
+ public $user_id;
22
+ /**
23
+ * @var string
24
+ */
25
+ public $title;
26
+ /**
27
+ * @var string
28
+ */
29
+ public $url;
30
+ /**
31
+ * @var string
32
+ */
33
+ public $version;
34
+ /**
35
+ * @var string E.g. en-GB
36
+ */
37
+ public $language;
38
+ /**
39
+ * @var string E.g. UTF-8
40
+ */
41
+ public $charset;
42
+ /**
43
+ * @var string Platform version (e.g WordPress version).
44
+ */
45
+ public $platform_version;
46
+ /**
47
+ * @var string Programming language version (e.g PHP version).
48
+ */
49
+ public $programming_language_version;
50
+ /**
51
+ * @var FS_Plugin_Plan $plan
52
+ */
53
+ public $plan;
54
+ /**
55
+ * @var number|null
56
+ */
57
+ public $license_id;
58
+ /**
59
+ * @var number|null
60
+ */
61
+ public $trial_plan_id;
62
+ /**
63
+ * @var string|null
64
+ */
65
+ public $trial_ends;
66
+ /**
67
+ * @since 1.0.9
68
+ *
69
+ * @var bool
70
+ */
71
+ public $is_premium = false;
72
+
73
+ /**
74
+ * @param stdClass|bool $site
75
+ */
76
+ function __construct( $site = false ) {
77
+ $this->plan = new FS_Plugin_Plan();
78
+
79
+ parent::__construct( $site );
80
+
81
+ if ( is_object( $site ) && isset( $site->plan_id ) ) {
82
+ $this->plan->id = $site->plan_id;
83
+ }
84
+ }
85
+
86
+ static function get_type() {
87
+ return 'install';
88
+ }
89
+
90
+ function is_localhost() {
91
+ // The server has no way to verify if localhost unless localhost appears in domain.
92
+ return WP_FS__IS_LOCALHOST_FOR_SERVER;
93
+ // return (substr($_SERVER['REMOTE_ADDR'], 0, 4) == '127.' || $_SERVER['REMOTE_ADDR'] == '::1');
94
+ }
95
+
96
+ /**
97
+ * Check if site in trial.
98
+ *
99
+ * @author Vova Feldman (@svovaf)
100
+ * @since 1.0.9
101
+ *
102
+ * @return bool
103
+ */
104
+ function is_trial() {
105
+ return is_numeric( $this->trial_plan_id ) && ( strtotime( $this->trial_ends ) > WP_FS__SCRIPT_START_TIME );
106
+ }
107
+
108
+ /**
109
+ * Check if user already utilized the trial with the current install.
110
+ *
111
+ * @author Vova Feldman (@svovaf)
112
+ * @since 1.0.9
113
+ *
114
+ * @return bool
115
+ */
116
+ function is_trial_utilized() {
117
+ return is_numeric( $this->trial_plan_id );
118
+ }
119
+ }
lib/freemius/includes/entities/class-fs-subscription.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.9
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Subscription extends FS_Entity {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var number
19
+ */
20
+ public $user_id;
21
+ /**
22
+ * @var number
23
+ */
24
+ public $install_id;
25
+ /**
26
+ * @var number
27
+ */
28
+ public $plan_id;
29
+ /**
30
+ * @var number
31
+ */
32
+ public $license_id;
33
+ /**
34
+ * @var float
35
+ */
36
+ public $total_gross;
37
+ /**
38
+ * @var float
39
+ */
40
+ public $amount_per_cycle;
41
+ /**
42
+ * @var int # of months
43
+ */
44
+ public $billing_cycle;
45
+ /**
46
+ * @var float
47
+ */
48
+ public $outstanding_balance;
49
+ /**
50
+ * @var int
51
+ */
52
+ public $failed_payments;
53
+ /**
54
+ * @var string
55
+ */
56
+ public $gateway;
57
+ /**
58
+ * @var string
59
+ */
60
+ public $external_id;
61
+ /**
62
+ * @var string|null
63
+ */
64
+ public $trial_ends;
65
+ /**
66
+ * @var string|null Datetime of the next payment, or null if cancelled
67
+ */
68
+ public $next_payment;
69
+ /**
70
+ * @var string|null
71
+ */
72
+ public $vat_id;
73
+ /**
74
+ * @var string Two characters country code
75
+ */
76
+ public $country_code;
77
+
78
+ #endregion Properties
79
+
80
+ /**
81
+ * @param object|bool $subscription
82
+ */
83
+ function __construct( $subscription = false ) {
84
+ parent::__construct( $subscription );
85
+ }
86
+
87
+ static function get_type() {
88
+ return 'subscription';
89
+ }
90
+
91
+ /**
92
+ * Check if subscription is active.
93
+ *
94
+ * @author Vova Feldman (@svovaf)
95
+ * @since 1.0.9
96
+ *
97
+ * @return bool
98
+ */
99
+ function is_active() {
100
+ return ! empty( $this->next_payment ) &&
101
+ ( strtotime( $this->next_payment ) > WP_FS__SCRIPT_START_TIME );
102
+ }
103
+
104
+ /**
105
+ * Subscription considered to be new without any payments
106
+ * if the next payment should be made within less than 24 hours
107
+ * from the subscription creation.
108
+ *
109
+ * @author Vova Feldman (@svovaf)
110
+ * @since 1.0.9
111
+ *
112
+ * @return bool
113
+ */
114
+ function is_first_payment_pending() {
115
+ return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->next_payment ) - strtotime( $this->created ) );
116
+ }
117
+ }
lib/freemius/includes/entities/class-fs-user.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_User extends FS_Scope_Entity {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ public $email;
21
+ /**
22
+ * @var string
23
+ */
24
+ public $first;
25
+ /**
26
+ * @var string
27
+ */
28
+ public $last;
29
+ /**
30
+ * @var bool
31
+ */
32
+ public $is_verified;
33
+ /**
34
+ * @var string|null
35
+ */
36
+ public $customer_id;
37
+ /**
38
+ * @var float
39
+ */
40
+ public $gross;
41
+
42
+ #endregion Properties
43
+
44
+ /**
45
+ * @param object|bool $user
46
+ */
47
+ function __construct( $user = false ) {
48
+ parent::__construct( $user );
49
+ }
50
+
51
+ function get_name() {
52
+ return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );
53
+ }
54
+
55
+ function is_verified() {
56
+ return ( isset( $this->is_verified ) && true === $this->is_verified );
57
+ }
58
+
59
+ static function get_type() {
60
+ return 'user';
61
+ }
62
+ }
lib/freemius/includes/fs-core-functions.php ADDED
@@ -0,0 +1,461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ global $fs_core_logger;
14
+
15
+ $fs_core_logger = FS_Logger::get_logger( WP_FS__SLUG . '_core', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
16
+
17
+ function fs_dummy() {
18
+ }
19
+
20
+ /* Url.
21
+ --------------------------------------------------------------------------------------------*/
22
+ function fs_get_url_daily_cache_killer() {
23
+ return date( '\YY\Mm\Dd' );
24
+ }
25
+
26
+ /* Templates / Views.
27
+ --------------------------------------------------------------------------------------------*/
28
+ function fs_get_template_path( $path ) {
29
+ return WP_FS__DIR_TEMPLATES . '/' . trim( $path, '/' );
30
+ }
31
+
32
+ function fs_include_template( $path, &$params = null ) {
33
+ $VARS = &$params;
34
+ include( fs_get_template_path( $path ) );
35
+ }
36
+
37
+ function fs_include_once_template( $path, &$params = null ) {
38
+ $VARS = &$params;
39
+ include_once( fs_get_template_path( $path ) );
40
+ }
41
+
42
+ function fs_require_template( $path, &$params = null ) {
43
+ $VARS = &$params;
44
+ require( fs_get_template_path( $path ) );
45
+ }
46
+
47
+ function fs_require_once_template( $path, &$params = null ) {
48
+ $VARS = &$params;
49
+ require_once( fs_get_template_path( $path ) );
50
+ }
51
+
52
+ function fs_get_template( $path, &$params = null ) {
53
+ ob_start();
54
+
55
+ $VARS = &$params;
56
+ require_once( fs_get_template_path( $path ) );
57
+
58
+ return ob_get_clean();
59
+ }
60
+
61
+ function __fs( $key ) {
62
+ global $fs_text;
63
+
64
+ if ( ! isset( $fs_text ) ) {
65
+ require_once( dirname( __FILE__ ) . '/i18n.php' );
66
+ }
67
+
68
+ return isset( $fs_text[ $key ] ) ? $fs_text[ $key ] : $key;
69
+ }
70
+
71
+ function _efs( $key ) {
72
+ echo __fs( $key );
73
+ }
74
+
75
+ /* Scripts and styles including.
76
+ --------------------------------------------------------------------------------------------*/
77
+ function fs_enqueue_local_style( $handle, $path, $deps = array(), $ver = false, $media = 'all' ) {
78
+ global $fs_core_logger;
79
+ if ( $fs_core_logger->is_on() ) {
80
+ $fs_core_logger->info( 'handle = ' . $handle . '; path = ' . $path . ';' );
81
+ $fs_core_logger->info( 'plugin_basename = ' . plugins_url( WP_FS__DIR_CSS . trim( $path, '/' ) ) );
82
+ $fs_core_logger->info( 'plugins_url = ' . plugins_url( plugin_basename( WP_FS__DIR_CSS . '/' . trim( $path, '/' ) ) ) );
83
+ }
84
+
85
+ wp_enqueue_style( $handle, plugins_url( plugin_basename( WP_FS__DIR_CSS . '/' . trim( $path, '/' ) ) ), $deps, $ver, $media );
86
+ }
87
+
88
+ function fs_enqueue_local_script( $handle, $path, $deps = array(), $ver = false, $in_footer = 'all' ) {
89
+ global $fs_core_logger;
90
+ if ( $fs_core_logger->is_on() ) {
91
+ $fs_core_logger->info( 'handle = ' . $handle . '; path = ' . $path . ';' );
92
+ $fs_core_logger->info( 'plugin_basename = ' . plugins_url( WP_FS__DIR_JS . trim( $path, '/' ) ) );
93
+ $fs_core_logger->info( 'plugins_url = ' . plugins_url( plugin_basename( WP_FS__DIR_JS . '/' . trim( $path, '/' ) ) ) );
94
+ }
95
+
96
+ wp_enqueue_script( $handle, plugins_url( plugin_basename( WP_FS__DIR_JS . '/' . trim( $path, '/' ) ) ), $deps, $ver, $in_footer );
97
+ }
98
+
99
+ function fs_img_url( $path ) {
100
+ return plugins_url( plugin_basename( WP_FS__DIR_IMG . '/' . trim( $path, '/' ) ) );
101
+ }
102
+
103
+ /* Request handlers.
104
+ --------------------------------------------------------------------------------------------*/
105
+ /**
106
+ * @param string $key
107
+ * @param mixed $def
108
+ *
109
+ * @return mixed
110
+ */
111
+ function fs_request_get( $key, $def = false ) {
112
+ return isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : $def;
113
+ }
114
+
115
+ function fs_request_has( $key ) {
116
+ return isset( $_REQUEST[ $key ] );
117
+ }
118
+
119
+ function fs_request_get_bool( $key, $def = false ) {
120
+ return ( isset( $_REQUEST[ $key ] ) && ( 1 == $_REQUEST[ $key ] || 'true' === strtolower( $_REQUEST[ $key ] ) ) ) ? true : $def;
121
+ }
122
+
123
+ function fs_request_is_post() {
124
+ return ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
125
+ }
126
+
127
+ function fs_request_is_get() {
128
+ return ( 'get' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
129
+ }
130
+
131
+ function fs_get_action( $action_key = 'action' ) {
132
+ if ( ! empty( $_REQUEST[ $action_key ] ) ) {
133
+ return strtolower( $_REQUEST[ $action_key ] );
134
+ }
135
+
136
+ if ( 'action' == $action_key ) {
137
+ $action_key = 'fs_action';
138
+
139
+ if ( ! empty( $_REQUEST[ $action_key ] ) ) {
140
+ return strtolower( $_REQUEST[ $action_key ] );
141
+ }
142
+ }
143
+
144
+ return false;
145
+ }
146
+
147
+ function fs_request_is_action( $action, $action_key = 'action' ) {
148
+ return ( strtolower( $action ) === fs_get_action( $action_key ) );
149
+ }
150
+
151
+ function fs_is_plugin_page( $menu_slug ) {
152
+ return ( is_admin() && $_REQUEST['page'] === $menu_slug );
153
+ }
154
+
155
+ /**
156
+ * Get client IP.
157
+ *
158
+ * @author Vova Feldman (@svovaf)
159
+ * @since 1.1.2
160
+ *
161
+ * @return string|null
162
+ */
163
+ function fs_get_ip() {
164
+ $fields = array(
165
+ 'HTTP_CF_CONNECTING_IP',
166
+ 'HTTP_CLIENT_IP',
167
+ 'HTTP_X_FORWARDED_FOR',
168
+ 'HTTP_X_FORWARDED',
169
+ 'HTTP_FORWARDED_FOR',
170
+ 'HTTP_FORWARDED',
171
+ 'REMOTE_ADDR',
172
+ );
173
+
174
+ foreach ( $fields as $ip_field ) {
175
+ if ( ! empty( $_SERVER[ $ip_field ] ) ) {
176
+ return $_SERVER[ $ip_field ];
177
+ }
178
+ }
179
+
180
+ return null;
181
+ }
182
+
183
+ /* Core UI.
184
+ --------------------------------------------------------------------------------------------*/
185
+ function fs_ui_action_button( $slug, $page, $action, $title, $params = array(), $is_primary = true ) {
186
+ ?><a class="button<?php if ( $is_primary ) {
187
+ echo ' button-primary';
188
+ } ?>"
189
+ href="<?php echo wp_nonce_url( freemius( $slug )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ) ?>"><?php echo $title ?></a><?php
190
+ }
191
+
192
+ function fs_ui_action_link( $slug, $page, $action, $title, $params = array() ) {
193
+ ?><a class=""
194
+ href="<?php echo wp_nonce_url( freemius( $slug )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ) ?>"><?php echo $title ?></a><?php
195
+ }
196
+
197
+ /* Core Redirect (copied from BuddyPress).
198
+ --------------------------------------------------------------------------------------------*/
199
+ /**
200
+ * Redirects to another page, with a workaround for the IIS Set-Cookie bug.
201
+ *
202
+ * @link http://support.microsoft.com/kb/q176113/
203
+ * @since 1.5.1
204
+ * @uses apply_filters() Calls 'wp_redirect' hook on $location and $status.
205
+ *
206
+ * @param string $location The path to redirect to
207
+ * @param int $status Status code to use
208
+ *
209
+ * @return bool False if $location is not set
210
+ */
211
+ function fs_redirect( $location, $status = 302 ) {
212
+ global $is_IIS;
213
+
214
+ if ( headers_sent() ) {
215
+ return false;
216
+ }
217
+
218
+ if ( ! $location ) // allows the wp_redirect filter to cancel a redirect
219
+ {
220
+ return false;
221
+ }
222
+
223
+ $location = fs_sanitize_redirect( $location );
224
+
225
+ if ( $is_IIS ) {
226
+ header( "Refresh: 0;url=$location" );
227
+ } else {
228
+ if ( php_sapi_name() != 'cgi-fcgi' ) {
229
+ status_header( $status );
230
+ } // This causes problems on IIS and some FastCGI setups
231
+ header( "Location: $location" );
232
+ }
233
+
234
+ return true;
235
+ }
236
+
237
+ /**
238
+ * Sanitizes a URL for use in a redirect.
239
+ *
240
+ * @since 2.3
241
+ *
242
+ * @param string $location
243
+ *
244
+ * @return string redirect-sanitized URL
245
+ */
246
+ function fs_sanitize_redirect( $location ) {
247
+ $location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location );
248
+ $location = fs_kses_no_null( $location );
249
+
250
+ // remove %0d and %0a from location
251
+ $strip = array( '%0d', '%0a' );
252
+ $found = true;
253
+ while ( $found ) {
254
+ $found = false;
255
+ foreach ( (array) $strip as $val ) {
256
+ while ( strpos( $location, $val ) !== false ) {
257
+ $found = true;
258
+ $location = str_replace( $val, '', $location );
259
+ }
260
+ }
261
+ }
262
+
263
+ return $location;
264
+ }
265
+
266
+ /**
267
+ * Removes any NULL characters in $string.
268
+ *
269
+ * @since 1.0.0
270
+ *
271
+ * @param string $string
272
+ *
273
+ * @return string
274
+ */
275
+ function fs_kses_no_null( $string ) {
276
+ $string = preg_replace( '/\0+/', '', $string );
277
+ $string = preg_replace( '/(\\\\0)+/', '', $string );
278
+
279
+ return $string;
280
+ }
281
+
282
+ /*function fs_error_handler($errno, $errstr, $errfile, $errline)
283
+ {
284
+ if (false === strpos($errfile, 'freemius/'))
285
+ {
286
+ // @todo Dump Freemius errors to local log.
287
+ }
288
+
289
+ // switch ($errno) {
290
+ // case E_USER_ERROR:
291
+ // break;
292
+ // case E_WARNING:
293
+ // case E_USER_WARNING:
294
+ // break;
295
+ // case E_NOTICE:
296
+ // case E_USER_NOTICE:
297
+ // break;
298
+ // default:
299
+ // break;
300
+ // }
301
+ }
302
+
303
+ set_error_handler('fs_error_handler');*/
304
+
305
+ if ( function_exists( 'wp_normalize_path' ) ) {
306
+ /**
307
+ * Normalize a filesystem path.
308
+ *
309
+ * Replaces backslashes with forward slashes for Windows systems, and ensures
310
+ * no duplicate slashes exist.
311
+ *
312
+ * @param string $path Path to normalize.
313
+ *
314
+ * @return string Normalized path.
315
+ */
316
+ function fs_normalize_path( $path ) {
317
+ return wp_normalize_path( $path );
318
+ }
319
+ } else {
320
+ function fs_normalize_path( $path ) {
321
+ $path = str_replace( '\\', '/', $path );
322
+ $path = preg_replace( '|/+|', '/', $path );
323
+
324
+ return $path;
325
+ }
326
+ }
327
+
328
+ function fs_nonce_url( $actionurl, $action = - 1, $name = '_wpnonce' ) {
329
+ // $actionurl = str_replace( '&amp;', '&', $actionurl );
330
+ return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
331
+ }
332
+
333
+ /**
334
+ * Check if string starts with.
335
+ *
336
+ * @author Vova Feldman (@svovaf)
337
+ * @since 1.1.3
338
+ *
339
+ * @param string $haystack
340
+ * @param string $needle
341
+ *
342
+ * @return bool
343
+ */
344
+ function fs_starts_with( $haystack, $needle ) {
345
+ $length = strlen( $needle );
346
+
347
+ return ( substr( $haystack, 0, $length ) === $needle );
348
+ }
349
+
350
+ #region Url Canonization ------------------------------------------------------------------
351
+
352
+ /**
353
+ * @author Vova Feldman (@svovaf)
354
+ * @since 1.1.3
355
+ *
356
+ * @param string $url
357
+ * @param bool $omit_host
358
+ * @param array $ignore_params
359
+ *
360
+ * @return string
361
+ */
362
+ function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
363
+ $parsed_url = parse_url( strtolower( $url ) );
364
+
365
+ // if ( ! isset( $parsed_url['host'] ) ) {
366
+ // return $url;
367
+ // }
368
+
369
+ $canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
370
+
371
+ if ( isset( $parsed_url['query'] ) ) {
372
+ parse_str( $parsed_url['query'], $queryString );
373
+ $canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
374
+ }
375
+
376
+ return $canonical;
377
+ }
378
+
379
+ /**
380
+ * @author Vova Feldman (@svovaf)
381
+ * @since 1.1.3
382
+ *
383
+ * @param array $params
384
+ * @param array $ignore_params
385
+ * @param bool $params_prefix
386
+ *
387
+ * @return string
388
+ */
389
+ function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
390
+ if ( ! is_array( $params ) || 0 === count( $params ) ) {
391
+ return '';
392
+ }
393
+
394
+ // Urlencode both keys and values
395
+ $keys = fs_urlencode_rfc3986( array_keys( $params ) );
396
+ $values = fs_urlencode_rfc3986( array_values( $params ) );
397
+ $params = array_combine( $keys, $values );
398
+
399
+ // Parameters are sorted by name, using lexicographical byte value ordering.
400
+ // Ref: Spec: 9.1.1 (1)
401
+ uksort( $params, 'strcmp' );
402
+
403
+ $pairs = array();
404
+ foreach ( $params as $parameter => $value ) {
405
+ $lower_param = strtolower( $parameter );
406
+
407
+ // Skip ignore params.
408
+ if ( in_array( $lower_param, $ignore_params ) || ( false !== $params_prefix && startsWith( $lower_param, $params_prefix ) ) ) {
409
+ continue;
410
+ }
411
+
412
+ if ( is_array( $value ) ) {
413
+ // If two or more parameters share the same name, they are sorted by their value
414
+ // Ref: Spec: 9.1.1 (1)
415
+ natsort( $value );
416
+ foreach ( $value as $duplicate_value ) {
417
+ $pairs[] = $lower_param . '=' . $duplicate_value;
418
+ }
419
+ } else {
420
+ $pairs[] = $lower_param . '=' . $value;
421
+ }
422
+ }
423
+
424
+ if ( 0 === count( $pairs ) ) {
425
+ return '';
426
+ }
427
+
428
+ return implode( "&", $pairs );
429
+ }
430
+
431
+ /**
432
+ * @author Vova Feldman (@svovaf)
433
+ * @since 1.1.3
434
+ *
435
+ * @param string|string[] $input
436
+ *
437
+ * @return array|mixed|string
438
+ */
439
+ function fs_urlencode_rfc3986( $input ) {
440
+ if ( is_array( $input ) ) {
441
+ return array_map( 'fs_urlencode_rfc3986', $input );
442
+ } else if ( is_scalar( $input ) ) {
443
+ return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
444
+ }
445
+
446
+ return '';
447
+ }
448
+
449
+ #endregion Url Canonization ------------------------------------------------------------------
450
+
451
+ function fs_download_image( $from, $to ) {
452
+ $ch = curl_init( $from );
453
+ $fp = fopen( fs_normalize_path( $to ), 'wb' );
454
+ curl_setopt( $ch, CURLOPT_FILE, $fp );
455
+ curl_setopt( $ch, CURLOPT_HEADER, 0 );
456
+ curl_exec( $ch );
457
+ curl_close( $ch );
458
+ fclose( $fp );
459
+ }
460
+
461
+
lib/freemius/includes/fs-plugin-functions.php ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.6
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Display plugin information in dialog box form.
15
+ *
16
+ * @since 2.7.0
17
+ */
18
+ function fs_install_plugin_information() {
19
+ global $tab;
20
+
21
+ if ( empty( $_REQUEST['plugin'] ) ) {
22
+ return;
23
+ }
24
+
25
+ $args = array(
26
+ 'slug' => wp_unslash( $_REQUEST['plugin'] ),
27
+ 'is_ssl' => is_ssl(),
28
+ 'fields' => array( 'banners' => true, 'reviews' => true )
29
+ );
30
+
31
+ if ( is_array( $args ) ) {
32
+ $args = (object) $args;
33
+ }
34
+
35
+ if ( ! isset( $args->per_page ) ) {
36
+ $args->per_page = 24;
37
+ }
38
+
39
+ if ( ! isset( $args->locale ) ) {
40
+ $args->locale = get_locale();
41
+ }
42
+
43
+ $api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
44
+
45
+ if ( is_wp_error( $api ) ) {
46
+ wp_die( $api );
47
+ }
48
+
49
+ $plugins_allowedtags = array(
50
+ 'a' => array(
51
+ 'href' => array(),
52
+ 'title' => array(),
53
+ 'target' => array(),
54
+ // Add image style for screenshots.
55
+ 'class' => array()
56
+ ),
57
+ 'style' => array(),
58
+ 'abbr' => array( 'title' => array() ),
59
+ 'acronym' => array( 'title' => array() ),
60
+ 'code' => array(),
61
+ 'pre' => array(),
62
+ 'em' => array(),
63
+ 'strong' => array(),
64
+ 'div' => array( 'class' => array() ),
65
+ 'span' => array( 'class' => array() ),
66
+ 'p' => array(),
67
+ 'ul' => array(),
68
+ 'ol' => array(),
69
+ 'li' => array( 'class' => array() ),
70
+ 'i' => array( 'class' => array() ),
71
+ 'h1' => array(),
72
+ 'h2' => array(),
73
+ 'h3' => array(),
74
+ 'h4' => array(),
75
+ 'h5' => array(),
76
+ 'h6' => array(),
77
+ 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
78
+ // 'table' => array(),
79
+ // 'td' => array(),
80
+ // 'tr' => array(),
81
+ // 'th' => array(),
82
+ // 'thead' => array(),
83
+ // 'tbody' => array(),
84
+ );
85
+
86
+ $plugins_section_titles = array(
87
+ 'description' => _x( 'Description', 'Plugin installer section title' ),
88
+ 'installation' => _x( 'Installation', 'Plugin installer section title' ),
89
+ 'faq' => _x( 'FAQ', 'Plugin installer section title' ),
90
+ 'screenshots' => _x( 'Screenshots', 'Plugin installer section title' ),
91
+ 'changelog' => _x( 'Changelog', 'Plugin installer section title' ),
92
+ 'reviews' => _x( 'Reviews', 'Plugin installer section title' ),
93
+ 'other_notes' => _x( 'Other Notes', 'Plugin installer section title' ),
94
+ 'features' => __fs( 'features-and-pricing' ),
95
+ );
96
+
97
+ // Sanitize HTML
98
+ // foreach ( (array) $api->sections as $section_name => $content ) {
99
+ // $api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
100
+ // }
101
+
102
+ foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
103
+ if ( isset( $api->$key ) ) {
104
+ $api->$key = wp_kses( $api->$key, $plugins_allowedtags );
105
+ }
106
+ }
107
+
108
+ $_tab = esc_attr( $tab );
109
+
110
+ $section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
111
+ if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
112
+ $section_titles = array_keys( (array) $api->sections );
113
+ $section = array_shift( $section_titles );
114
+ }
115
+
116
+ iframe_header( __( 'Plugin Install' ) );
117
+
118
+ $_with_banner = '';
119
+
120
+ // var_dump($api->banners);
121
+ if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
122
+ $_with_banner = 'with-banner';
123
+ $low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
124
+ $high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
125
+ ?>
126
+ <style type="text/css">
127
+ #plugin-information-title.with-banner
128
+ {
129
+ background-image: url( <?php echo esc_url( $low ); ?> );
130
+ }
131
+
132
+ @media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
133
+ {
134
+ #plugin-information-title.with-banner
135
+ {
136
+ background-image: url( <?php echo esc_url( $high ); ?> );
137
+ }
138
+ }
139
+ </style>
140
+ <?php
141
+ }
142
+
143
+ echo '<div id="plugin-information-scrollable">';
144
+ echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
145
+ echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
146
+
147
+ foreach ( (array) $api->sections as $section_name => $content ) {
148
+ if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
149
+ continue;
150
+ }
151
+
152
+ if ( isset( $plugins_section_titles[ $section_name ] ) ) {
153
+ $title = $plugins_section_titles[ $section_name ];
154
+ } else {
155
+ $title = ucwords( str_replace( '_', ' ', $section_name ) );
156
+ }
157
+
158
+ $class = ( $section_name === $section ) ? ' class="current"' : '';
159
+ $href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
160
+ $href = esc_url( $href );
161
+ $san_section = esc_attr( $section_name );
162
+ echo "\t<a name='$san_section' href='$href' $class>$title</a>\n";
163
+ }
164
+
165
+ echo "</div>\n";
166
+
167
+ ?>
168
+ <div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
169
+ <div class="fyi">
170
+ <?php if ( isset( $api->plans ) ) : ?>
171
+ <div class="plugin-information-pricing">
172
+ <?php foreach ($api->plans as $plan) : ?>
173
+ <h3 data-plan="<?php echo $plan->id ?>"><?php printf( __fs( 'x-plan' ), $plan->title ) ?></h3>
174
+ <ul>
175
+ <?php $billing_cycle = 'annual' ?>
176
+ <?php if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) : ?>
177
+ <?php $pricing = $plan->pricing[0] ?>
178
+ <li><label><?php _efs( 'price' ) ?>: $<?php
179
+ if ( isset( $pricing->annual_price ) ) {
180
+ echo $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
181
+ $billing_cycle = 'annual';
182
+ } else if ( isset( $pricing->monthly_price ) ) {
183
+ echo $pricing->monthly_price . ' / mo';
184
+ $billing_cycle = 'monthly';
185
+ } else if ( isset( $pricing->lifetime_price ) ) {
186
+ echo $pricing->lifetime_price;
187
+ $billing_cycle = 'lifetime';
188
+ }
189
+ ?></label></li>
190
+ <?php else : ?>
191
+ <?php $first = true;
192
+ foreach ( $plan->pricing as $pricing ) : ?>
193
+ <li><label><input name="pricing-<?php echo $plan->id ?>" type="radio"
194
+ value="<?php echo $pricing->id ?>"<?php checked( $first, true ) ?>><?php
195
+ switch ( $pricing->licenses ) {
196
+ case '1':
197
+ _efs( 'license-single-site' );
198
+ break;
199
+ case null:
200
+ _efs( 'license-unlimited' );
201
+ break;
202
+ default:
203
+ printf( __fs( 'license-x-sites' ), $pricing->licenses );
204
+ break;
205
+ }
206
+ ?> - $<?php
207
+ if ( isset( $pricing->annual_price ) ) {
208
+ echo $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
209
+ $billing_cycle = 'annual';
210
+ } else if ( isset( $pricing->monthly_price ) ) {
211
+ echo $pricing->monthly_price . ' / mo';
212
+ $billing_cycle = 'monthly';
213
+ } else if ( isset( $pricing->lifetime_price ) ) {
214
+ echo $pricing->lifetime_price;
215
+ $billing_cycle = 'lifetime';
216
+ }
217
+ ?></label></li>
218
+ <?php $first = false; endforeach ?>
219
+ <?php endif ?>
220
+ </ul>
221
+ <?php echo ' <a class="button button-primary right" href="' . esc_url( add_query_arg( array(
222
+ 'plugin_id' => $plan->plugin_id,
223
+ 'plan_id' => $plan->id,
224
+ 'pricing_id' => $plan->pricing[0]->id,
225
+ 'billing_cycle' => $billing_cycle,
226
+ ), $api->checkout_link ) ) . '" target="_parent">' . __fs( 'purchase' ) . '</a>' ?>
227
+ </div>
228
+ <?php endforeach ?>
229
+ <?php wp_enqueue_script( 'jquery' ); ?>
230
+ <script type="text/javascript">
231
+ (function ($) {
232
+ $('.plugin-information-pricing input[type=radio]').click(function () {
233
+ var checkout_url = '<?php echo esc_url_raw(add_query_arg(array(
234
+ 'plugin_id' => $plan->plugin_id,
235
+ 'billing_cycle' => $billing_cycle,
236
+ ), $api->checkout_link)) ?>&plan_id=' +
237
+ $(this).parents('.plugin-information-pricing').find('h3').attr('data-plan') +
238
+ '&pricing_id=' + $(this).val();
239
+
240
+ $('.plugin-information-pricing .button, #plugin-information-footer .button').attr('href', checkout_url);
241
+ });
242
+ })(jQuery);
243
+ </script>
244
+ <?php endif ?>
245
+ <div>
246
+ <h3><?php _efs( 'details' ) ?></h3>
247
+ <ul>
248
+ <?php if ( ! empty( $api->version ) ) { ?>
249
+ <li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li>
250
+ <?php }
251
+ if ( ! empty( $api->author ) ) { ?>
252
+ <li>
253
+ <strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
254
+ </li>
255
+ <?php }
256
+ if ( ! empty( $api->last_updated ) ) { ?>
257
+ <li><strong><?php _e( 'Last Updated:' ); ?></strong> <span
258
+ title="<?php echo $api->last_updated; ?>">
259
+ <?php printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?>
260
+ </span></li>
261
+ <?php }
262
+ if ( ! empty( $api->requires ) ) { ?>
263
+ <li>
264
+ <strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php printf( __( '%s or higher' ), $api->requires ); ?>
265
+ </li>
266
+ <?php }
267
+ if ( ! empty( $api->tested ) ) { ?>
268
+ <li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?></li>
269
+ <?php }
270
+ if ( ! empty( $api->downloaded ) ) { ?>
271
+ <li>
272
+ <strong><?php _e( 'Downloaded:' ); ?></strong> <?php printf( _n( '%s time', '%s times', $api->downloaded ), number_format_i18n( $api->downloaded ) ); ?>
273
+ </li>
274
+ <?php }
275
+ if ( ! empty( $api->slug ) && empty( $api->external ) ) { ?>
276
+ <li><a target="_blank"
277
+ href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php _e( 'WordPress.org Plugin Page &#187;' ); ?></a>
278
+ </li>
279
+ <?php }
280
+ if ( ! empty( $api->homepage ) ) { ?>
281
+ <li><a target="_blank"
282
+ href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage &#187;' ); ?></a>
283
+ </li>
284
+ <?php }
285
+ if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) { ?>
286
+ <li><a target="_blank"
287
+ href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
288
+ </li>
289
+ <?php } ?>
290
+ </ul>
291
+ </div>
292
+ <?php if ( ! empty( $api->rating ) ) { ?>
293
+ <h3><?php _e( 'Average Rating' ); ?></h3>
294
+ <?php wp_star_rating( array(
295
+ 'rating' => $api->rating,
296
+ 'type' => 'percent',
297
+ 'number' => $api->num_ratings
298
+ ) ); ?>
299
+ <small><?php printf( _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?></small>
300
+ <?php
301
+ }
302
+
303
+ if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
304
+ foreach ( $api->ratings as $key => $ratecount ) {
305
+ // Avoid div-by-zero.
306
+ $_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
307
+ ?>
308
+ <div class="counter-container">
309
+ <span class="counter-label"><a
310
+ href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
311
+ target="_blank"
312
+ title="<?php echo esc_attr( sprintf( _n( 'Click to see reviews that provided a rating of %d star', 'Click to see reviews that provided a rating of %d stars', $key ), $key ) ); ?>"><?php printf( _n( '%d star', '%d stars', $key ), $key ); ?></a></span>
313
+ <span class="counter-back">
314
+ <span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span>
315
+ </span>
316
+ <span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
317
+ </div>
318
+ <?php
319
+ }
320
+ }
321
+ if ( ! empty( $api->contributors ) ) {
322
+ ?>
323
+ <h3><?php _e( 'Contributors' ); ?></h3>
324
+ <ul class="contributors">
325
+ <?php
326
+ foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
327
+ if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
328
+ continue;
329
+ }
330
+ if ( empty( $contrib_username ) ) {
331
+ $contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
332
+ }
333
+ $contrib_username = sanitize_user( $contrib_username );
334
+ if ( empty( $contrib_profile ) ) {
335
+ echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</li>";
336
+ } else {
337
+ echo "<li><a href='{$contrib_profile}' target='_blank'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</a></li>";
338
+ }
339
+ }
340
+ ?>
341
+ </ul>
342
+ <?php if ( ! empty( $api->donate_link ) ) { ?>
343
+ <a target="_blank"
344
+ href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
345
+ <?php } ?>
346
+ <?php } ?>
347
+ </div>
348
+ <div id="section-holder" class="wrap">
349
+ <?php
350
+ if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
351
+ echo '<div class="notice notice-warning"><p>' . '<strong>' . __( 'Warning:' ) . '</strong> ' . __( 'This plugin has not been tested with your current version of WordPress.' ) . '</p></div>';
352
+ } else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
353
+ echo '<div class="notice notice-warning"><p>' . '<strong>' . __( 'Warning:' ) . '</strong> ' . __( 'This plugin has not been marked as compatible with your version of WordPress.' ) . '</p></div>';
354
+ }
355
+
356
+ foreach ( (array) $api->sections as $section_name => $content ) {
357
+ $content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
358
+ $content = links_add_target( $content, '_blank' );
359
+
360
+ $san_section = esc_attr( $section_name );
361
+
362
+ $display = ( $section_name === $section ) ? 'block' : 'none';
363
+
364
+ echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
365
+ echo $content;
366
+ echo "\t</div>\n";
367
+ }
368
+ echo "</div>\n";
369
+ echo "</div>\n";
370
+ echo "</div>\n"; // #plugin-information-scrollable
371
+ echo "<div id='$tab-footer'>\n";
372
+ if ( ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
373
+
374
+ if ( ! empty( $api->checkout_link ) && isset( $api->plans ) && 0 < is_array( $api->plans ) ) {
375
+ echo ' <a class="button button-primary right" href="' . esc_url( add_query_arg( array(
376
+ 'plugin_id' => $plan->plugin_id,
377
+ 'plan_id' => $plan->id,
378
+ 'pricing_id' => $plan->pricing[0]->id,
379
+ 'billing_cycle' => $billing_cycle,
380
+ ), $api->checkout_link ) ) . '" target="_parent">' . __fs( 'purchase' ) . '</a>';
381
+
382
+ // @todo Add Cart concept.
383
+ // echo ' <a class="button right" href="' . $status['url'] . '" target="_parent">' . __( 'Add to Cart' ) . '</a>';
384
+
385
+ } else if ( ! empty( $api->download_link ) ) {
386
+ $status = install_plugin_install_status( $api );
387
+ switch ( $status['status'] ) {
388
+ case 'install':
389
+ if ( $status['url'] ) {
390
+ echo '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>';
391
+ }
392
+ break;
393
+ case 'update_available':
394
+ if ( $status['url'] ) {
395
+ echo '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) . '</a>';
396
+ }
397
+ break;
398
+ case 'newer_installed':
399
+ echo '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed' ), $status['version'] ) . '</a>';
400
+ break;
401
+ case 'latest_installed':
402
+ echo '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>';
403
+ break;
404
+ }
405
+ }
406
+ }
407
+ echo "</div>\n";
408
+
409
+ iframe_footer();
410
+ exit;
411
+ }
lib/freemius/includes/i18n.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ global $fs_text;
3
+
4
+ $fs_text = array(
5
+ 'account' => __( 'Account', 'freemius' ),
6
+ 'addon' => __( 'Add On', 'freemius' ),
7
+ 'contact-us' => __( 'Contact Us', 'freemius' ),
8
+ 'change-ownership' => __( 'Change Ownership', 'freemius' ),
9
+ 'support' => __( 'Support', 'freemius' ),
10
+ 'support-forum' => __( 'Support Forum', 'freemius' ),
11
+ 'add-ons' => __( 'Add Ons', 'freemius' ),
12
+ 'upgrade' => _x( 'Upgrade', 'verb', 'freemius' ),
13
+ 'awesome' => __( 'Awesome', 'freemius' ),
14
+ 'pricing' => __( 'Pricing', 'noun', 'freemius' ),
15
+ 'price' => _x( 'Price', 'noun', 'freemius' ),
16
+ 'unlimited-updates' => __( 'Unlimited Updates', 'freemius' ),
17
+ 'downgrade' => _x( 'Downgrade', 'verb', 'freemius' ),
18
+ 'free-trial' => __( 'Free Trial', 'freemius' ),
19
+ 'details' => __( 'Details', 'freemius' ),
20
+ 'account-details' => __( 'Account Details', 'freemius' ),
21
+ 'delete' => _x( 'Delete', 'verb', 'freemius' ),
22
+ 'delete-account' => __( 'Delete Account', 'freemius' ),
23
+ 'dismiss' => __( 'Dismiss', 'as close a window', 'freemius' ),
24
+ 'plan' => _x( 'Plan', 'as product pricing plan', 'freemius' ),
25
+ 'change-plan' => __( 'Change Plan', 'freemius' ),
26
+ 'download-x-version' => _x( 'Download %s Version', 'as download professional version', 'freemius' ),
27
+ 'download-x-version-now' => _x( 'Download %s version now', 'as download professional version now', 'freemius' ),
28
+ 'download-latest' => _x( 'Download Latest', 'as download latest version', 'freemius' ),
29
+ 'you-have-x-license' => _x( 'You have a %s license.', 'E.g. you have a professional license.', 'freemius' ),
30
+ 'new' => __( 'New', 'freemius' ),
31
+ 'free' => __( 'Free', 'freemius' ),
32
+ 'trial' => _x( 'Trial', 'as trial plan', 'freemius' ),
33
+ 'purchase' => _x( 'Purchase', 'verb', 'freemius' ),
34
+ 'license-single-site' => __( 'Single Site License', 'freemius' ),
35
+ 'license-unlimited' => __( 'Unlimited Licenses', 'freemius' ),
36
+ 'license-x-sites' => __( 'Up to %s Sites', 'freemius' ),
37
+ 'x-plan' => _x( '%s Plan', 'e.g. Professional Plan', 'freemius' ),
38
+ 'you-are-step-away' => __( 'You are just one step away - %s', 'freemius' ),
39
+ 'activate-x-now' => _x( 'Complete "%s" Activation Now', '%s - plugin name. As complete "Jetpack" activation now', 'freemius' ),
40
+ 'few-plugin-tweaks' => __( 'We made a few tweaks to the plugin, %s', 'freemius' ),
41
+ 'optin-x-now' => __( 'Opt-in to make "%s" Better!', 'freemius' ),
42
+ 'error' => __( 'Error', 'freemius' ),
43
+ 'failed-finding-main-path' => __( 'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.', 'freemius' ),
44
+ #region Account
45
+
46
+ 'expiration' => _x( 'Expiration', 'as expiration date', 'freemius' ),
47
+ 'not-verified' => __( 'not verified', 'freemius' ),
48
+ 'verify-email' => __( 'Verify Email', 'freemius' ),
49
+ 'expires-in' => _x( 'Expires in %s', 'e.g. expires in 2 months', 'freemius' ),
50
+ 'renews-in' => _x( 'Auto renews in %s', 'e.g. auto renews in 2 months', 'freemius' ),
51
+ 'no-expiration' => __( 'No expiration', 'freemius' ),
52
+ 'expired' => __( 'Expired', 'freemius' ),
53
+ 'in-x' => __( 'In %s', 'freemius' ),
54
+ 'version' => _x( 'Version', 'as plugin version', 'freemius' ),
55
+ 'name' => __( 'Name', 'freemius' ),
56
+ 'email' => __( 'Email', 'freemius' ),
57
+ 'verified' => __( 'Verified', 'freemius' ),
58
+ 'plugin' => __( 'Plugin', 'freemius' ),
59
+ 'title' => __( 'Title', 'freemius' ),
60
+ 'slug' => _x( 'Slug', 'as WP plugin slug', 'freemius' ),
61
+ 'id' => __( 'ID', 'freemius' ),
62
+ 'users' => __( 'Users', 'freemius' ),
63
+ 'plugin-installs' => __( 'Plugin Installs', 'freemius' ),
64
+ 'sites' => _x( 'Sites', 'like websites', 'freemius' ),
65
+ 'user-id' => __( 'User ID', 'freemius' ),
66
+ 'site-id' => __( 'Site ID', 'freemius' ),
67
+ 'public-key' => __( 'Public Key', 'freemius' ),
68
+ 'secret-key' => __( 'Secret Key', 'freemius' ),
69
+ 'no-secret' => _x( 'No Secret', 'as secret encryption key missing', 'freemius' ),
70
+ 'no-id' => __( 'No ID', 'freemius' ),
71
+ 'sync-license' => _x( 'Sync License', 'as synchronize license', 'freemius' ),
72
+ 'deactivate-license' => __( 'Deactivate License', 'freemius' ),
73
+ 'activate' => __( 'Activate', 'freemius' ),
74
+ 'deactivate' => __( 'Deactivate', 'freemius' ),
75
+ 'active' => _x( 'Active', 'active mode', 'freemius' ),
76
+ 'install-now' => __( 'Install Now', 'freemius' ),
77
+ 'install-update-now' => __( 'Install Update Now', 'freemius' ),
78
+ 'more-information-about-x' => __( 'More information about %s', 'freemius' ),
79
+ 'localhost' => __( 'Localhost', 'freemius' ),
80
+ 'activate-x-plan' => _x( 'Activate %s Plan', 'as activate Professional plan', 'freemius' ),
81
+ 'what-is-your-x' => __( 'What is your %s?', 'freemius' ),
82
+ 'activate-this-addon' => __( 'Activate this add-on', 'freemius' ),
83
+ 'deactivate-license-confirm' => __( 'Deactivating your license will block all premium features, but will enable you to activate the license on another site. Are you sure you want to proceed?', 'freemius' ),
84
+ 'delete-account-x-confirm' => __( 'Deleting the account will automatically deactivate your %s plan license so you can use it on other sites. If you want to terminate the recurring payments as well, click the "Cancel" button, and first "Downgrade" your account. Are you sure you would like to continue with the deletion?', 'freemius' ),
85
+ 'delete-account-confirm' => __( 'Deletion is not temporary. Only delete if you no longer want to use this plugin anymore. Are you sure you would like to continue with the deletion?', 'freemius' ),
86
+ 'downgrade-x-confirm' => __( 'Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s.', 'freemius' ),
87
+ 'after-downgrade-non-blocking' => __( 'You can still enjoy all %s features but you will not have access to plugin updates and support.', 'freemius' ),
88
+ 'after-downgrade-blocking' => __( 'Once your license expire you can still use the Free version but you will NOT have access to the %s features.', 'freemius' ),
89
+ 'proceed-confirmation' => __( 'Are you sure you want to proceed?', 'freemius' ),
90
+ #endregion Account
91
+
92
+ 'add-ons-for-x' => __( 'Add Ons for %s', 'freemius' ),
93
+ #region Plugin Deactivation
94
+ 'deactivation-share-reason' => __( 'If you have a moment, please let us know why you are deactivating', 'freemius' ),
95
+ 'deactivation-modal-button-deactivate' => __( 'Deactivate', 'freemius' ),
96
+ 'deactivation-modal-button-confirm' => __( 'Yes - Deactivate', 'freemius' ),
97
+ 'deactivation-modal-button-submit' => __( 'Submit & Deactivate', 'freemius' ),
98
+ 'deactivation-modal-button-cancel' => _x( 'Cancel', 'the text of the cancel button of the plugin deactivation dialog box.', 'freemius' ),
99
+ 'reason-no-longer-needed' => __( 'I no longer need the plugin', 'freemius' ),
100
+ 'reason-found-a-better-plugin' => __( 'I found a better plugin', 'freemius' ),
101
+ 'reason-needed-for-a-short-period' => __( 'I only needed the plugin for a short period', 'freemius' ),
102
+ 'reason-broke-my-site' => __( 'The plugin broke my site', 'freemius' ),
103
+ 'reason-suddenly-stopped-working' => __( 'The plugin suddenly stopped working', 'freemius' ),
104
+ 'reason-cant-pay-anymore' => __( "I can't pay for it anymore", 'freemius' ),
105
+ 'reason-other' => _x( 'Other', 'the text of the "other" reason for deactivating the plugin that is shown in the modal box.', 'freemius' ),
106
+ 'placeholder-plugin-name' => __( "What's the plugin's name?", 'freemius' ),
107
+ 'placeholder-comfortable-price' => __( 'What price would you feel comfortable paying?', 'freemius' ),
108
+ 'reason-couldnt-make-it-work' => __( "I couldn't understand how to make it work", 'freemius' ),
109
+ 'reason-great-but-need-specific-feature' => __( "The plugin is great, but I need specific feature that you don't support", 'freemius' ),
110
+ 'reason-not-working' => __( 'The plugin is not working', 'freemius' ),
111
+ 'reason-not-what-i-was-looking-for' => __( "It's not what I was looking for", 'freemius' ),
112
+ 'reason-didnt-work-as-expected' => __( "The plugin didn't work as expected", 'freemius' ),
113
+ 'placeholder-feature' => __( 'What feature?', 'freemius' ),
114
+ 'placeholder-share-what-didnt-work' => __( "Kindly share what didn't work so we can fix it for future users...", 'freemius' ),
115
+ 'placeholder-what-youve-been-looking-for' => __( "What you've been looking for?", 'freemius' ),
116
+ 'placeholder-what-did-you-expect' => __( "What did you expect?", 'freemius' ),
117
+ 'reason-didnt-work' => __( "The plugin didn't work", 'freemius' ),
118
+ 'reason-dont-like-to-share-my-information' => __( "I don't like to share my information with you", 'freemius' ),
119
+ #endregion Plugin Deactivation
120
+
121
+ #region Connect
122
+ 'hey-x' => _x( 'Hey %s,', 'greeting', 'freemius' ),
123
+ 'thanks-x' => _x( 'Thanks %s!', 'a greeting. E.g. Thanks John!', 'freemius' ),
124
+ 'connect-message' => __( 'In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s', 'freemius' ),
125
+ 'pending-activation-message' => __( 'You should receive an activation email for %s to your mailbox at %s. Please make sure you click the activation button in that email to complete the install.', 'freemius' ),
126
+ 'what-permissions' => __( 'What permissions are being granted?', 'freemius' ),
127
+ 'permissions-profile' => __( 'Your Profile Overview', 'freemius' ),
128
+ 'permissions-profile_desc' => __( 'Name and email address', 'freemius' ),
129
+ 'permissions-site' => __( 'Your Site Overview', 'freemius' ),
130
+ 'permissions-site_desc' => __( 'Site address and WordPress version', 'freemius' ),
131
+ 'permissions-events' => __( 'Current Plugin Events', 'freemius' ),
132
+ 'permissions-events_desc' => __( 'Activation, deactivation and uninstall', 'freemius' ),
133
+ 'privacy-policy' => __( 'Privacy Policy', 'freemius' ),
134
+ 'tos' => __( 'Terms of Service', 'freemius' ),
135
+ 'activating' => _x( 'Activating', 'as activating plugin', 'freemius' ),
136
+ 'opt-in-connect' => _x( 'Allow & Continue', 'button label', 'freemius' ),
137
+ 'skip' => _x( 'Skip', 'verb', 'freemius' ),
138
+ 'resend-activation-email' => __( 'Re-send activation email', 'freemius' ),
139
+ #endregion Connect
140
+
141
+ #region Screenshots
142
+ 'screenshots' => __( 'Screenshots', 'freemius' ),
143
+ 'view-full-size-x' => __( 'Click to view full-size screenshot %d', 'freemius' ),
144
+ #endregion Screenshots
145
+
146
+ #region Debug
147
+ 'addons-of-x' => __( 'Add Ons of Plugin %s', 'freemius' ),
148
+ 'delete-all-confirm' => __( 'Are you sure you want to delete the all Freemius data?', 'freemius' ),
149
+ 'delete-all-accounts' => __( 'Delete All Accounts', 'freemius' ),
150
+ #endregion Debug
151
+
152
+ #region Expressions
153
+ 'congrats' => _x( 'Congrats', 'as congratulations', 'freemius' ),
154
+ 'oops' => _x( 'Oops', 'exclamation', 'freemius' ),
155
+ 'yee-haw' => _x( 'Yee-haw', 'interjection expressing joy or exuberance', 'freemius' ),
156
+ 'woot' => _x( 'W00t', '(especially in electronic communication) used to express elation, enthusiasm, or triumph.', 'freemius' ),
157
+ 'right-on' => _x( 'Right on', 'a positive response', 'freemius' ),
158
+ 'hmm' => _x( 'Hmm', 'something somebody says when they are thinking about what you have just said. ', 'freemius' ),
159
+ 'ok' => __( 'O.K', 'freemius' ),
160
+ 'hey' => _x( 'Hey', 'exclamation', 'freemius' ),
161
+ 'heads-up' => _x( 'Heads up', 'advance notice of something that will need attention.', 'freemius' ),
162
+ #endregion Expressions
163
+
164
+ #region Admin Notices
165
+ 'you-have-latest' => __( 'Seems like you got the latest release.', 'freemius' ),
166
+ 'you-are-good' => __( 'You are all good!', 'freemius' ),
167
+ 'user-exist-message' => __( 'Sorry, we could not complete the email update. Another user with the same email is already registered.', 'freemius' ),
168
+ 'user-exist-message_ownership' => __( 'If you would like to give up the ownership of the plugin\'s account to %s click the Change Ownership button.', 'freemius' ),
169
+ 'email-updated-message' => __( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.', 'freemius' ),
170
+ 'name-updated-message' => __( 'Your name was successfully updated.', 'freemius' ),
171
+ 'x-updated' => __( 'You have successfully updated your %s.', 'freemius' ),
172
+ 'name-update-failed-message' => __( 'Please provide your full name.', 'freemius' ),
173
+ 'verification-email-sent-message' => __( 'Verification mail was just sent to %s. If you can\'t find it after 5 min, please check your spam box.', 'freemius' ),
174
+ 'addons-info-external-message' => __( 'Just letting you know that the add-ons information of %s is being pulled from external server.', 'freemius' ),
175
+ 'no-cc-required' => __( 'No credit card required', 'freemius' ),
176
+ 'premium-activated-message' => __( 'Premium plugin version was successfully activated.', 'freemius' ),
177
+ 'successful-version-upgrade-message' => __( 'The upgrade of %s was successfully completed.', 'freemius' ),
178
+ 'activation-with-plan-x-message' => __( 'Your account was successfully activated with the %s plan.', 'freemius' ),
179
+ 'download-latest-x-version' => __( 'Download the latest %s version now', 'freemius' ),
180
+ 'download-latest-version' => __( 'Download the latest version now', 'freemius' ),
181
+ 'addon-successfully-purchased-message' => _x( '%s Add-on was successfully purchased.', '%s - product name, e.g. Facebook add-on was successfully...', 'freemius' ),
182
+ 'addon-successfully-upgraded-message' => __( 'Your %s Add-on plan was successfully upgraded.', 'freemius' ),
183
+ 'email-verified-message' => __( 'Your email has been successfully verified - you are AWESOME!', 'freemius' ),
184
+ 'plan-upgraded-message' => __( 'Your plan was successfully upgraded.', 'freemius' ),
185
+ 'plan-changed-to-x-message' => __( 'Your plan was successfully changed to %s.', 'freemius' ),
186
+ 'license-expired-blocking-message' => __( 'Your license has expired. You can still continue using the free plugin forever.', 'freemius' ),
187
+ 'trial-started-message' => __( 'Your trial has been successfully started.', 'freemius' ),
188
+ 'license-activated-message' => __( 'Your license was successfully activated.', 'freemius' ),
189
+ 'no-active-license-message' => __( 'It looks like your site currently don\'t have an active license.', 'freemius' ),
190
+ 'license-deactivation-message' => __( 'Your license was successfully deactivated, you are back to the %s plan.', 'freemius' ),
191
+ 'license-deactivation-failed-message' => __( 'It looks like the license deactivation failed.', 'freemius' ),
192
+ 'license-activation-failed-message' => __( 'It looks like the license could not be activated.', 'freemius' ),
193
+ 'server-error-message' => __( 'Error received from the server:', 'freemius' ),
194
+ 'trial-expired-message' => __( 'Your trial has expired. You can still continue using all our free features.', 'freemius' ),
195
+ 'plan-x-downgraded-message' => __( 'Your plan was successfully downgraded. Your %s plan license will expire in %s.', 'freemius' ),
196
+ 'plan-downgraded-failure-message' => __( 'Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes.', 'freemius' ),
197
+ 'trial-cancel-no-trial-message' => __( 'It looks like you are not in trial mode anymore so there\'s nothing to cancel :)', 'freemius' ),
198
+ 'trial-cancel-message' => __( 'Your %s Plan trial was successfully cancelled.', 'freemius' ),
199
+ 'version-x-released' => _x( 'Version %s was released.', '%s - numeric version number', 'freemius' ),
200
+ 'please-download-x' => __( 'Please download %s.', 'freemius' ),
201
+ 'latest-x-version' => _x( 'the latest %s version here', '%s - plan name, as the latest professional version here', 'freemius' ),
202
+ 'trial-x-promotion-message' => __( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.', 'freemius' ),
203
+ 'start-free-trial' => _x( 'Start free trial', 'call to action', 'freemius' ),
204
+ 'trial-cancel-failure-message' => __( 'Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes.', 'freemius' ),
205
+ 'no-commitment-for-x-days' => __( 'No commitment for %s days - cancel anytime!', 'freemius' ),
206
+ 'license-expired-non-blocking-message' => __( 'Your license has expired. You can still continue using all the %s features, but you\'ll need to renew your license to continue getting updates and support.', 'freemius' ),
207
+ 'could-not-activate-x' => __( 'Couldn\'t activate %s.', 'freemius' ),
208
+ 'contact-us-with-error-message' => __( 'Please contact us with the following message:', 'freemius' ),
209
+ 'plan-did-not-change-message' => __( 'It looks like your plan did\'t change. If you did upgrade, it\'s probably an issue on our side - sorry.', 'freemius' ),
210
+ 'contact-us-here' => __( 'Please contact us here', 'freemius' ),
211
+ 'plan-did-not-change-email-message' => __( 'I have upgraded my account but when I try to Sync the License, the plan remains %s.', 'freemius' ),
212
+ #endregion Admin Notices
213
+ #region Connectivity Issues
214
+ 'connectivity-test-fails-message' => __( 'From unknown reason, the API connectivity test fails.', 'freemius' ),
215
+ 'curl-missing-message' => __( 'We use PHP cURL library for the API calls, which is a very common library and usually installed out of the box. Unfortunately, cURL is not installed on your server.', 'freemius' ),
216
+ 'cloudflare-blocks-connection-message' => __( 'From unknown reason, CloudFlare, the firewall we use, blocks the connection.', 'freemius' ),
217
+ 'x-requires-access-to-api' => _x( '%s requires an access to our API.', 'as pluginX requires an access to our API', 'freemius' ),
218
+ 'squid-blocks-connection-message' => __( 'It looks like your server is using Squid ACL (access control lists), which blocks the connection.', 'freemius' ),
219
+ 'squid-no-clue-title' => __( 'I don\'t know what is Squid or ACL, help me!', 'freemius' ),
220
+ 'squid-no-clue-desc' => __( 'We\'ll make sure to contact your hosting company and resolve the issue. You will get a follow-up email to %s once we have an update.' ),
221
+ 'sysadmin-title' => __( 'I\'m a system administrator', 'freemius' ),
222
+ 'squid-sysadmin-desc' => __( 'Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again.' ),
223
+ 'curl-missing-no-clue-title' => __( 'I don\'t know what is cURL or how to install it, help me!', 'freemius' ),
224
+ 'curl-missing-no-clue-desc' => __( 'We\'ll make sure to contact your hosting company and resolve the issue. You will get a follow-up email to %s once we have an update.' ),
225
+ 'curl-missing-sysadmin-desc' => __( 'Great, please install cURL and enable it in your php.ini file. To make sure it was successfully activated, use \'phpinfo()\'. Once activated, deactivate the plugin and reactivate it back again.' ),
226
+ 'happy-to-resolve-issue-asap' => __( 'We are sure it\'s an issue on our side and more than happy to resolve it for you ASAP if you give us a chance.', 'freemius' ),
227
+ 'fix-issue-title' => __( 'Yes - I\'m giving you a chance to fix it', 'freemius' ),
228
+ 'fix-issue-desc' => __( 'We will do our best to whitelist your server and resolve this issue ASAP. You will get a follow-up email to %s once we have an update.', 'freemius' ),
229
+ 'install-previous-title' => __( 'Let\'s try your previous version', 'freemius' ),
230
+ 'install-previous-desc' => __( 'Uninstall this version and install the previous one.', 'freemius' ),
231
+ 'deactivate-plugin-title' => __( 'That\'s exhausting, please deactivate', 'freemius' ),
232
+ 'deactivate-plugin-desc' => __( 'We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future.', 'freemius' ),
233
+ 'fix-request-sent-message' => __( 'Thank for giving us the chance to fix it! A message was just sent to our technical staff. We will get back to you as soon as we have an update to %s. Appreciate your patience.', 'freemius' ),
234
+ 'server-blocking-access' => _x( 'Your server is blocking the access to Freemius\' API, which is crucial for %1s license synchronization. Please contact your host to whitelist %2s', '%1s - plugin title, %2s - API domain', 'freemius' ),
235
+ 'wrong-authentication-param-message' => __( 'It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again.', 'freemius' ),
236
+ #endregion Connectivity Issues
237
+ #region Change Owner
238
+ 'change-owner-request-sent-x' => __( 'Please check your mailbox, you should receive an email via %s to confirm the ownership change. From security reasons, you must confirm the change within the next 15 min. If you cannot find the email, please check your spam folder.', 'freemius' ),
239
+ 'change-owner-request_owner-confirmed' => __( 'Thanks for confirming the ownership change. An email was just sent to %s for final approval.', 'freemius' ),
240
+ 'change-owner-request_candidate-confirmed' => __( '%s is the new owner of the account.', 'freemius' ),
241
+ #endregion Change Owner
242
+ 'freemius-debug' => __( 'Freemius Debug', 'freemius' ),
243
+ 'addon-x-cannot-run-without-y' => _x( '%s cannot run without %s.', 'addonX cannot run without pluginY', 'freemius' ),
244
+ 'addon-x-cannot-run-without-parent' => _x( '%s cannot run without the plugin.', 'addonX cannot run...', 'freemius' ),
245
+ 'plugin-x-activation-message' => _x( '%s activation was successfully completed.', 'pluginX activation was successfully...', 'freemius' ),
246
+ 'features-and-pricing' => _x( 'Features & Pricing', 'Plugin installer section title', 'freemius' ),
247
+ );
lib/freemius/includes/managers/class-fs-admin-menu-manager.php ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.1.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Admin_Menu_Manager {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ protected $_plugin_slug;
21
+
22
+ /**
23
+ * @since 1.0.6
24
+ *
25
+ * @var string
26
+ */
27
+ private $_menu_slug;
28
+ /**
29
+ * @since 1.1.3
30
+ *
31
+ * @var string
32
+ */
33
+ private $_parent_slug;
34
+ /**
35
+ * @since 1.1.3
36
+ *
37
+ * @var string
38
+ */
39
+ private $_parent_type;
40
+ /**
41
+ * @since 1.1.3
42
+ *
43
+ * @var string
44
+ */
45
+ private $_type;
46
+ /**
47
+ * @since 1.1.3
48
+ *
49
+ * @var bool
50
+ */
51
+ private $_is_top_level;
52
+ /**
53
+ * @since 1.1.3
54
+ *
55
+ * @var bool
56
+ */
57
+ private $_is_override_exact;
58
+ /**
59
+ * @since 1.1.3
60
+ *
61
+ * @var string[]bool
62
+ */
63
+ private $_default_submenu_items;
64
+ /**
65
+ * @since 1.1.3
66
+ *
67
+ * @var string
68
+ */
69
+ private $_first_time_path;
70
+
71
+ #endregion Properties
72
+
73
+ /**
74
+ * @var FS_Logger
75
+ */
76
+ protected $_logger;
77
+
78
+ #region Singleton
79
+
80
+ /**
81
+ * @var FS_Admin_Menu_Manager[]
82
+ */
83
+ private static $_instances = array();
84
+
85
+ /**
86
+ * @param string $plugin_slug
87
+ *
88
+ * @return FS_Admin_Notice_Manager
89
+ */
90
+ static function instance( $plugin_slug ) {
91
+ if ( ! isset( self::$_instances[ $plugin_slug ] ) ) {
92
+ self::$_instances[ $plugin_slug ] = new FS_Admin_Menu_Manager( $plugin_slug );
93
+ }
94
+
95
+ return self::$_instances[ $plugin_slug ];
96
+ }
97
+
98
+ protected function __construct( $plugin_slug ) {
99
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $plugin_slug . '_admin_menu', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
100
+
101
+ $this->_plugin_slug = $plugin_slug;
102
+ }
103
+
104
+ #endregion Singleton
105
+
106
+ #region Helpers
107
+
108
+ private function get_option( &$options, $key, $default = false ) {
109
+ return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
110
+ }
111
+
112
+ private function get_bool_option( &$options, $key, $default = false ) {
113
+ return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
114
+ }
115
+
116
+ #endregion Helpers
117
+
118
+ /**
119
+ * @param array $menu
120
+ * @param bool $is_addon
121
+ */
122
+ function init( $menu, $is_addon = false ) {
123
+ $this->_menu_slug = $menu['slug'];
124
+
125
+ $this->_default_submenu_items = array();
126
+ // @deprecated
127
+ $this->_type = 'page';
128
+ $this->_is_top_level = true;
129
+ $this->_is_override_exact = false;
130
+ $this->_parent_slug = false;
131
+ // @deprecated
132
+ $this->_parent_type = 'page';
133
+
134
+ if ( ! $is_addon && isset( $menu ) ) {
135
+ $this->_default_submenu_items = array(
136
+ 'contact' => $this->get_bool_option( $menu, 'contact', true ),
137
+ 'support' => $this->get_bool_option( $menu, 'support', true ),
138
+ 'account' => $this->get_bool_option( $menu, 'account', true ),
139
+ 'pricing' => $this->get_bool_option( $menu, 'pricing', true ),
140
+ 'addons' => $this->get_bool_option( $menu, 'addons', true ),
141
+ );
142
+
143
+ // @deprecated
144
+ $this->_type = $this->get_option( $menu, 'type', 'page' );
145
+ $this->_is_override_exact = $this->get_bool_option( $menu, 'override_exact' );
146
+
147
+ if ( isset( $menu['parent'] ) ) {
148
+ $this->_parent_slug = $this->get_option( $menu['parent'], 'slug' );
149
+ // @deprecated
150
+ $this->_parent_type = $this->get_option( $menu['parent'], 'type', 'page' );
151
+
152
+ // If parent's slug is different, then it's NOT a top level menu item.
153
+ $this->_is_top_level = ( $this->_parent_slug === $this->_menu_slug );
154
+ } else {
155
+ /**
156
+ * If no parent then top level if:
157
+ * - Has custom admin menu ('page')
158
+ * - CPT menu type ('cpt')
159
+ */
160
+ // $this->_is_top_level = in_array( $this->_type, array(
161
+ // 'cpt',
162
+ // 'page'
163
+ // ) );
164
+ }
165
+
166
+ $this->_first_time_path = $this->get_option( $menu, 'first-path', false );
167
+ if ( ! empty( $this->_first_time_path ) && is_string( $this->_first_time_path ) ) {
168
+ $this->_first_time_path = admin_url( $this->_first_time_path, 'admin' );
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Check if top level menu.
175
+ *
176
+ * @author Vova Feldman (@svovaf)
177
+ * @since 1.1.3
178
+ *
179
+ * @return bool False if submenu item.
180
+ */
181
+ function is_top_level() {
182
+ return $this->_is_top_level;
183
+ }
184
+
185
+ /**
186
+ * Check if the page should be override on exact URL match.
187
+ *
188
+ * @author Vova Feldman (@svovaf)
189
+ * @since 1.1.3
190
+ *
191
+ * @return bool False if submenu item.
192
+ */
193
+ function is_override_exact() {
194
+ return $this->_is_override_exact;
195
+ }
196
+
197
+
198
+ /**
199
+ * Get the path of the page the user should be forwarded to after first activation.
200
+ *
201
+ * @author Vova Feldman (@svovaf)
202
+ * @since 1.1.3
203
+ *
204
+ * @return string
205
+ */
206
+ function get_first_time_path() {
207
+ return $this->_first_time_path;
208
+ }
209
+
210
+ /**
211
+ * Check if plugin's menu item is part of a custom top level menu.
212
+ *
213
+ * @author Vova Feldman (@svovaf)
214
+ * @since 1.1.3
215
+ *
216
+ * @return bool
217
+ */
218
+ function has_custom_parent() {
219
+ return ! $this->_is_top_level && is_string( $this->_parent_slug );
220
+ }
221
+
222
+ /**
223
+ * @author Vova Feldman (@svovaf)
224
+ * @since 1.1.3
225
+ *
226
+ * @return string
227
+ */
228
+ // function slug(){
229
+ // return $this->_menu_slug;
230
+ // }
231
+
232
+ /**
233
+ * @author Vova Feldman (@svovaf)
234
+ * @since 1.1.3
235
+ *
236
+ * @param string $id
237
+ * @param bool $default
238
+ *
239
+ * @return bool
240
+ */
241
+ function is_submenu_item_visible( $id, $default = true ) {
242
+ return $this->get_bool_option( $this->_default_submenu_items, $id, $default );
243
+ }
244
+
245
+ /**
246
+ * Calculates admin settings menu slug.
247
+ * If plugin's menu slug is a file (e.g. CPT), uses plugin's slug as the menu slug.
248
+ *
249
+ * @author Vova Feldman (@svovaf)
250
+ * @since 1.1.3
251
+ *
252
+ * @param string $page
253
+ *
254
+ * @return string
255
+ */
256
+ function get_slug( $page = '' ) {
257
+ return ( ( false === strpos( $this->_menu_slug, '.php?' ) ) ?
258
+ $this->_menu_slug :
259
+ $this->_plugin_slug ) . ( empty( $page ) ? '' : ( '-' . $page ) );
260
+ }
261
+
262
+ /**
263
+ * @author Vova Feldman (@svovaf)
264
+ * @since 1.1.3
265
+ *
266
+ * @return string
267
+ */
268
+ function get_parent_slug() {
269
+ return $this->_parent_slug;
270
+ }
271
+
272
+ /**
273
+ * @author Vova Feldman (@svovaf)
274
+ * @since 1.1.3
275
+ *
276
+ * @return string
277
+ */
278
+ function get_type() {
279
+ return $this->_type;
280
+ }
281
+
282
+ /**
283
+ * @author Vova Feldman (@svovaf)
284
+ * @since 1.1.3
285
+ *
286
+ * @return bool
287
+ */
288
+ function is_cpt() {
289
+ return ( 0 === strpos( $this->_menu_slug, 'edit.php?post_type=' ) ||
290
+ // Back compatibility.
291
+ 'cpt' === $this->_type
292
+ );
293
+ }
294
+
295
+ /**
296
+ * @author Vova Feldman (@svovaf)
297
+ * @since 1.1.3
298
+ *
299
+ * @return string
300
+ */
301
+ function get_parent_type() {
302
+ return $this->_parent_type;
303
+ }
304
+
305
+ /**
306
+ * @author Vova Feldman (@svovaf)
307
+ * @since 1.1.3
308
+ *
309
+ * @return string
310
+ */
311
+ function get_raw_slug() {
312
+ return $this->_menu_slug;
313
+ }
314
+
315
+ /**
316
+ * Get plugin's original menu slug.
317
+ *
318
+ * @author Vova Feldman (@svovaf)
319
+ * @since 1.1.3
320
+ *
321
+ * @return string
322
+ */
323
+ function get_original_menu_slug() {
324
+ if ( 'cpt' === $this->_type ) {
325
+ return add_query_arg( array(
326
+ 'post_type' => $this->_menu_slug
327
+ ), 'edit.php' );
328
+ }
329
+
330
+ if ( false === strpos( $this->_menu_slug, '.php?' ) ) {
331
+ return $this->_menu_slug;
332
+ } else {
333
+ return $this->_plugin_slug;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * @author Vova Feldman (@svovaf)
339
+ * @since 1.1.3
340
+ *
341
+ * @return string
342
+ */
343
+ function get_top_level_menu_slug() {
344
+ return $this->has_custom_parent() ?
345
+ $this->get_parent_slug() :
346
+ $this->get_raw_slug();
347
+ }
348
+
349
+ /**
350
+ * Is user on plugin's admin activation page.
351
+ *
352
+ * @author Vova Feldman (@svovaf)
353
+ * @since 1.0.8
354
+ *
355
+ * @return bool
356
+ */
357
+ function is_activation_page() {
358
+ return isset( $_GET['page'] ) &&
359
+ ( ( strtolower( $this->_menu_slug ) === strtolower( $_GET['page'] ) ) ||
360
+ ( strtolower( $this->_plugin_slug ) === strtolower( $_GET['page'] ) ) );
361
+ }
362
+
363
+ #region Submenu Override
364
+
365
+ /**
366
+ * Override submenu's action.
367
+ *
368
+ * @author Vova Feldman (@svovaf)
369
+ * @since 1.1.0
370
+ *
371
+ * @param string $parent_slug
372
+ * @param string $menu_slug
373
+ * @param callable $function
374
+ *
375
+ * @return false|string If submenu exist, will return the hook name.
376
+ */
377
+ function override_submenu_action( $parent_slug, $menu_slug, $function ) {
378
+ global $submenu;
379
+
380
+ $menu_slug = plugin_basename( $menu_slug );
381
+ $parent_slug = plugin_basename( $parent_slug );
382
+
383
+ if ( ! isset( $submenu[ $parent_slug ] ) ) {
384
+ // Parent menu not exist.
385
+ return false;
386
+ }
387
+
388
+ $found_submenu_item = false;
389
+ foreach ( $submenu[ $parent_slug ] as $submenu_item ) {
390
+ if ( $menu_slug === $submenu_item[2] ) {
391
+ $found_submenu_item = $submenu_item;
392
+ break;
393
+ }
394
+ }
395
+
396
+ if ( false === $found_submenu_item ) {
397
+ // Submenu item not found.
398
+ return false;
399
+ }
400
+
401
+ // Remove current function.
402
+ $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );
403
+ remove_all_actions( $hookname );
404
+
405
+ // Attach new action.
406
+ add_action( $hookname, $function );
407
+
408
+ return $hookname;
409
+ }
410
+
411
+ #endregion Submenu Override
412
+
413
+ #region Top level menu Override
414
+
415
+ /**
416
+ * Find plugin's admin dashboard main menu item.
417
+ *
418
+ * @author Vova Feldman (@svovaf)
419
+ * @since 1.0.2
420
+ *
421
+ * @return string[]|false
422
+ */
423
+ private function find_top_level_menu() {
424
+ global $menu;
425
+
426
+ $position = - 1;
427
+ $found_menu = false;
428
+
429
+ $menu_slug = $this->get_raw_slug();
430
+
431
+ $hook_name = get_plugin_page_hookname( $menu_slug, '' );
432
+ foreach ( $menu as $pos => $m ) {
433
+ if ( $menu_slug === $m[2] ) {
434
+ $position = $pos;
435
+ $found_menu = $m;
436
+ break;
437
+ }
438
+ }
439
+
440
+ if ( false === $found_menu ) {
441
+ return false;
442
+ }
443
+
444
+ return array(
445
+ 'menu' => $found_menu,
446
+ 'position' => $position,
447
+ 'hook_name' => $hook_name
448
+ );
449
+ }
450
+
451
+ /**
452
+ * Remove all sub-menu items.
453
+ *
454
+ * @author Vova Feldman (@svovaf)
455
+ * @since 1.0.7
456
+ *
457
+ * @return bool If submenu with plugin's menu slug was found.
458
+ */
459
+ private function remove_all_submenu_items() {
460
+ global $submenu;
461
+
462
+ $menu_slug = $this->get_raw_slug();
463
+
464
+ if ( ! isset( $submenu[ $menu_slug ] ) ) {
465
+ return false;
466
+ }
467
+
468
+ $submenu[ $menu_slug ] = array();
469
+
470
+ return true;
471
+ }
472
+
473
+ /**
474
+ *
475
+ * @author Vova Feldman (@svovaf)
476
+ * @since 1.0.9
477
+ *
478
+ * @return array[string]mixed
479
+ */
480
+ function remove_menu_item() {
481
+ $this->_logger->entrance();
482
+
483
+ // Find main menu item.
484
+ $menu = $this->find_top_level_menu();
485
+
486
+ if ( false === $menu ) {
487
+ return false;
488
+ }
489
+
490
+ // Remove it with its actions.
491
+ remove_all_actions( $menu['hook_name'] );
492
+
493
+ // Remove all submenu items.
494
+ $this->remove_all_submenu_items();
495
+
496
+ return $menu;
497
+ }
498
+
499
+ /**
500
+ *
501
+ * @author Vova Feldman (@svovaf)
502
+ * @since 1.1.4
503
+ *
504
+ * @param callable $function
505
+ *
506
+ * @return array[string]mixed
507
+ */
508
+ function override_menu_item( $function ) {
509
+ $found_menu = $this->remove_menu_item();
510
+
511
+ if ( false === $found_menu ) {
512
+ return false;
513
+ }
514
+
515
+ if ( ! $this->is_top_level() || ! $this->is_cpt() ) {
516
+ $menu_slug = plugin_basename( $this->get_slug() );
517
+
518
+ $hookname = get_plugin_page_hookname( $menu_slug, '' );
519
+
520
+ // Override menu action.
521
+ add_action( $hookname, $function );
522
+ } else {
523
+ global $menu;
524
+
525
+ // Create new top-level menu action.
526
+ $hookname = add_menu_page(
527
+ $found_menu['menu'][3],
528
+ $found_menu['menu'][0],
529
+ 'manage_options',
530
+ $this->get_slug(),
531
+ $function,
532
+ $found_menu['menu'][6],
533
+ $found_menu['position']
534
+ );
535
+
536
+ // Remove original CPT menu.
537
+ unset( $menu[ $found_menu['position'] ] );
538
+ }
539
+
540
+ return $hookname;
541
+ }
542
+
543
+ #endregion Top level menu Override
544
+ }
lib/freemius/includes/managers/class-fs-admin-notice-manager.php ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.7
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Admin_Notice_Manager {
14
+ /**
15
+ * @var string
16
+ */
17
+ protected $_slug;
18
+ /**
19
+ * @var string
20
+ */
21
+ protected $_title;
22
+ /**
23
+ * @var array[]
24
+ */
25
+ private $_admin_messages = array();
26
+ /**
27
+ * @var FS_Key_Value_Storage
28
+ */
29
+ private $_sticky_storage;
30
+ /**
31
+ * @var FS_Plugin_Manager[]
32
+ */
33
+ private static $_instances = array();
34
+ /**
35
+ * @var FS_Logger
36
+ */
37
+ protected $_logger;
38
+
39
+ /**
40
+ * @param string $slug
41
+ * @param string $title
42
+ *
43
+ * @return FS_Admin_Notice_Manager
44
+ */
45
+ static function instance( $slug, $title = '' ) {
46
+ if ( ! isset( self::$_instances[ $slug ] ) ) {
47
+ self::$_instances[ $slug ] = new FS_Admin_Notice_Manager( $slug, $title );
48
+ }
49
+
50
+ return self::$_instances[ $slug ];
51
+ }
52
+
53
+ protected function __construct( $slug, $title = '' ) {
54
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_data', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
55
+
56
+ $this->_slug = $slug;
57
+ $this->_title = ! empty( $title ) ? $title : '';
58
+ $this->_sticky_storage = FS_Key_Value_Storage::instance( 'admin_notices', $this->_slug );
59
+
60
+ if ( is_admin() ) {
61
+ if ( 0 < count( $this->_sticky_storage ) ) {
62
+ // If there are sticky notices for the current slug, add a callback
63
+ // to the AJAX action that handles message dismiss.
64
+ add_action( "wp_ajax_{$slug}_dismiss_notice_action", array(
65
+ &$this,
66
+ 'dismiss_notice_ajax_callback'
67
+ ) );
68
+
69
+ foreach ( $this->_sticky_storage as $id => $msg ) {
70
+ // Add admin notice.
71
+ $this->add(
72
+ $msg['message'],
73
+ $msg['title'],
74
+ $msg['type'],
75
+ true,
76
+ $msg['all'],
77
+ $msg['id'],
78
+ false
79
+ );
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Remove sticky message by ID.
87
+ *
88
+ * @author Vova Feldman (@svovaf)
89
+ * @since 1.0.7
90
+ *
91
+ */
92
+ function dismiss_notice_ajax_callback() {
93
+ $this->_sticky_storage->remove( $_POST['message_id'] );
94
+ wp_die();
95
+ }
96
+
97
+ /**
98
+ * Rendered sticky message dismiss JavaScript.
99
+ *
100
+ * @author Vova Feldman (@svovaf)
101
+ * @since 1.0.7
102
+ */
103
+ static function _add_sticky_dismiss_javascript() {
104
+ $params = array();
105
+ fs_require_once_template( 'sticky-admin-notice-js.php', $params );
106
+ }
107
+
108
+ private static $_added_sticky_javascript = false;
109
+
110
+ /**
111
+ * Hook to the admin_footer to add sticky message dismiss JavaScript handler.
112
+ *
113
+ * @author Vova Feldman (@svovaf)
114
+ * @since 1.0.7
115
+ */
116
+ private static function has_sticky_messages() {
117
+ if ( ! self::$_added_sticky_javascript ) {
118
+ add_action( 'admin_footer', array( 'FS_Admin_Notice_Manager', '_add_sticky_dismiss_javascript' ) );
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Handle admin_notices by printing the admin messages stacked in the queue.
124
+ *
125
+ * @author Vova Feldman (@svovaf)
126
+ * @since 1.0.4
127
+ *
128
+ */
129
+ function _admin_notices_hook() {
130
+ $notice_type = 'admin_notices';
131
+
132
+ if ( ! isset( $this->_admin_messages[ $notice_type ] ) || ! is_array( $this->_admin_messages[ $notice_type ] ) ) {
133
+ return;
134
+ }
135
+
136
+ foreach ( $this->_admin_messages[ $notice_type ] as $id => $msg ) {
137
+ fs_require_template( 'admin-notice.php', $msg );
138
+
139
+ if ( $msg['sticky'] ) {
140
+ self::has_sticky_messages();
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Handle all_admin_notices by printing the admin messages stacked in the queue.
147
+ *
148
+ * @author Vova Feldman (@svovaf)
149
+ * @since 1.0.4
150
+ *
151
+ */
152
+ function _all_admin_notices_hook() {
153
+ $notice_type = 'all_admin_notices';
154
+
155
+ if ( ! isset( $this->_admin_messages[ $notice_type ] ) || ! is_array( $this->_admin_messages[ $notice_type ] ) ) {
156
+ return;
157
+ }
158
+
159
+ foreach ( $this->_admin_messages[ $notice_type ] as $id => $msg ) {
160
+ fs_require_template( 'all-admin-notice.php', $msg );
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Enqueue common stylesheet to style admin notice.
166
+ *
167
+ * @author Vova Feldman (@svovaf)
168
+ * @since 1.0.7
169
+ */
170
+ function _enqueue_styles() {
171
+ fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
172
+ }
173
+
174
+ /**
175
+ * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
176
+ *
177
+ * @author Vova Feldman (@svovaf)
178
+ * @since 1.0.4
179
+ *
180
+ * @param string $message
181
+ * @param string $title
182
+ * @param string $type
183
+ * @param bool $is_sticky
184
+ * @param bool $all_admin
185
+ * @param string $id Message ID
186
+ * @param bool $store_if_sticky
187
+ *
188
+ * @uses add_action()
189
+ */
190
+ function add( $message, $title = '', $type = 'success', $is_sticky = false, $all_admin = false, $id = '', $store_if_sticky = true ) {
191
+ $key = ( $all_admin ? 'all_admin_notices' : 'admin_notices' );
192
+
193
+ if ( ! isset( $this->_admin_messages[ $key ] ) ) {
194
+ $this->_admin_messages[ $key ] = array();
195
+
196
+ add_action( $key, array( &$this, "_{$key}_hook" ) );
197
+ add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_styles' ) );
198
+
199
+ }
200
+
201
+ if ( '' === $id ) {
202
+ $id = md5( $title . ' ' . $message . ' ' . $type );
203
+ }
204
+
205
+ $message_object = array(
206
+ 'message' => $message,
207
+ 'title' => $title,
208
+ 'type' => $type,
209
+ 'sticky' => $is_sticky,
210
+ 'id' => $id,
211
+ 'all' => $all_admin,
212
+ 'slug' => $this->_slug,
213
+ 'plugin' => $this->_title,
214
+ );
215
+
216
+ if ( $is_sticky && $store_if_sticky ) {
217
+ $this->_sticky_storage->{$id} = $message_object;
218
+ }
219
+
220
+ $this->_admin_messages[ $key ][ $id ] = $message_object;
221
+ }
222
+
223
+ /**
224
+ * @author Vova Feldman (@svovaf)
225
+ * @since 1.0.7
226
+ *
227
+ * @param string $ids
228
+ */
229
+ function remove_sticky( $ids ) {
230
+ if ( ! is_array( $ids ) ) {
231
+ $ids = array( $ids );
232
+ }
233
+
234
+ foreach ( $ids as $id ) {
235
+ // Remove from sticky storage.
236
+ $this->_sticky_storage->remove( $id );
237
+
238
+ // Remove from current admin messages.
239
+ if ( isset( $this->_admin_messages['all_admin_notices'] ) && isset( $this->_admin_messages['all_admin_notices'][ $id ] ) ) {
240
+ unset( $this->_admin_messages['all_admin_notices'][ $id ] );
241
+ }
242
+ if ( isset( $this->_admin_messages['admin_notices'] ) && isset( $this->_admin_messages['admin_notices'][ $id ] ) ) {
243
+ unset( $this->_admin_messages['admin_notices'][ $id ] );
244
+ }
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Check if sticky message exists by id.
250
+ *
251
+ * @author Vova Feldman (@svovaf)
252
+ * @since 1.0.9
253
+ *
254
+ * @param $id
255
+ *
256
+ * @return bool
257
+ */
258
+ function has_sticky( $id ) {
259
+ return isset( $this->_sticky_storage[ $id ] );
260
+ }
261
+
262
+ /**
263
+ * Adds sticky admin notification.
264
+ *
265
+ * @author Vova Feldman (@svovaf)
266
+ * @since 1.0.7
267
+ *
268
+ * @param string $message
269
+ * @param string $id Message ID
270
+ * @param string $title
271
+ * @param string $type
272
+ * @param bool $all_admin
273
+ */
274
+ function add_sticky( $message, $id, $title = '', $type = 'success', $all_admin = false ) {
275
+ $this->add( $message, $title, $type, true, $all_admin, $id );
276
+ }
277
+
278
+ /**
279
+ * Clear all sticky messages.
280
+ *
281
+ * @author Vova Feldman (@svovaf)
282
+ * @since 1.0.8
283
+ */
284
+ function clear_all_sticky() {
285
+ $this->_sticky_storage->clear_all();
286
+ }
287
+
288
+ /**
289
+ * Add admin message to all admin messages queue, and hook to all_admin_notices if not yet hooked.
290
+ *
291
+ * @author Vova Feldman (@svovaf)
292
+ * @since 1.0.4
293
+ *
294
+ * @param string $message
295
+ * @param string $title
296
+ * @param string $type
297
+ * @param bool $is_sticky
298
+ * @param string $id Message ID
299
+ */
300
+ function add_all( $message, $title = '', $type = 'success', $is_sticky = false, $id = '' ) {
301
+ $this->add( $message, $title, $type, $is_sticky, true, $id );
302
+ }
303
+ }
lib/freemius/includes/managers/class-fs-key-value-storage.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.7
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable {
14
+ /**
15
+ * @var string
16
+ */
17
+ protected $_id;
18
+ /**
19
+ * @var string
20
+ */
21
+ protected $_slug;
22
+ /**
23
+ * @var array
24
+ */
25
+ protected $_data;
26
+
27
+ /**
28
+ * @var FS_Plugin_Manager[]
29
+ */
30
+ private static $_instances = array();
31
+ /**
32
+ * @var FS_Logger
33
+ */
34
+ protected $_logger;
35
+
36
+ /**
37
+ * @param string $id
38
+ * @param string $slug
39
+ *
40
+ * @return FS_Key_Value_Storage
41
+ */
42
+ static function instance( $id, $slug ) {
43
+ $key = $id . ':' . $slug;
44
+ if ( ! isset( self::$_instances[ $key ] ) ) {
45
+ self::$_instances[ $key ] = new FS_Key_Value_Storage( $id, $slug );
46
+ }
47
+
48
+ return self::$_instances[ $key ];
49
+ }
50
+
51
+ protected function __construct( $id, $slug ) {
52
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
53
+
54
+ $this->_slug = $slug;
55
+ $this->_id = $id;
56
+ $this->load();
57
+ }
58
+
59
+ protected function get_option_manager() {
60
+ return FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
61
+ }
62
+
63
+ protected function get_all_data() {
64
+ return $this->get_option_manager()->get_option( $this->_id, array() );
65
+ }
66
+
67
+ /**
68
+ * Load plugin data from local DB.
69
+ *
70
+ * @author Vova Feldman (@svovaf)
71
+ * @since 1.0.7
72
+ */
73
+ function load() {
74
+ $all_plugins_data = $this->get_all_data();
75
+ $this->_data = isset( $all_plugins_data[ $this->_slug ] ) ?
76
+ $all_plugins_data[ $this->_slug ] :
77
+ array();
78
+ }
79
+
80
+ /**
81
+ * @author Vova Feldman (@svovaf)
82
+ * @since 1.0.7
83
+ *
84
+ * @param string $key
85
+ * @param mixed $value
86
+ * @param bool $flush
87
+ */
88
+ function store( $key, $value, $flush = true ) {
89
+ if ( array_key_exists( $key, $this->_data ) && $value === $this->_data[ $key ] ) {
90
+ // No need to store data if the value wasn't changed.
91
+ return;
92
+ }
93
+
94
+ $all_data = $this->get_all_data();
95
+
96
+ $this->_data[ $key ] = $value;
97
+
98
+ $all_data[ $this->_slug ] = $this->_data;
99
+
100
+ $options_manager = $this->get_option_manager();
101
+ $options_manager->set_option( $this->_id, $all_data, $flush );
102
+ }
103
+
104
+ /**
105
+ * @author Vova Feldman (@svovaf)
106
+ * @since 1.0.7
107
+ *
108
+ * @param bool $store
109
+ * @param string[] $exceptions Set of keys to keep and not clear.
110
+ */
111
+ function clear_all( $store = true, $exceptions = array() ) {
112
+ $new_data = array();
113
+ foreach ( $exceptions as $key ) {
114
+ if ( isset( $this->_data[ $key ] ) ) {
115
+ $new_data[ $key ] = $this->_data[ $key ];
116
+ }
117
+ }
118
+
119
+ $this->_data = $new_data;
120
+
121
+ if ( $store ) {
122
+ $all_data = $this->get_all_data();
123
+ $all_data[ $this->_slug ] = $this->_data;
124
+ $options_manager = $this->get_option_manager();
125
+ $options_manager->set_option( $this->_id, $all_data, true );
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Delete key-value storage.
131
+ *
132
+ * @author Vova Feldman (@svovaf)
133
+ * @since 1.0.9
134
+ */
135
+ function delete() {
136
+ $this->_data = array();
137
+
138
+ $all_data = $this->get_all_data();
139
+ unset( $all_data[ $this->_slug ] );
140
+ $options_manager = $this->get_option_manager();
141
+ $options_manager->set_option( $this->_id, $all_data, true );
142
+ }
143
+
144
+ /**
145
+ * @author Vova Feldman (@svovaf)
146
+ * @since 1.0.7
147
+ *
148
+ * @param string $key
149
+ * @param bool $store
150
+ */
151
+ function remove( $key, $store = true ) {
152
+ if ( ! array_key_exists( $key, $this->_data ) ) {
153
+ return;
154
+ }
155
+
156
+ unset( $this->_data[ $key ] );
157
+
158
+ if ( $store ) {
159
+ $all_data = $this->get_all_data();
160
+ $all_data[ $this->_slug ] = $this->_data;
161
+ $options_manager = $this->get_option_manager();
162
+ $options_manager->set_option( $this->_id, $all_data, true );
163
+ }
164
+ }
165
+
166
+ /**
167
+ * @author Vova Feldman (@svovaf)
168
+ * @since 1.0.7
169
+ *
170
+ * @param string $key
171
+ * @param mixed $default
172
+ *
173
+ * @return bool|\FS_Plugin
174
+ */
175
+ function get( $key, $default = false ) {
176
+ return array_key_exists( $key, $this->_data ) ?
177
+ $this->_data[ $key ] :
178
+ $default;
179
+ }
180
+
181
+
182
+ /* ArrayAccess + Magic Access (better for refactoring)
183
+ -----------------------------------------------------------------------------------*/
184
+ function __set( $k, $v ) {
185
+ $this->store( $k, $v );
186
+ }
187
+
188
+ function __isset( $k ) {
189
+ return array_key_exists( $k, $this->_data );
190
+ }
191
+
192
+ function __unset( $k ) {
193
+ $this->remove( $k );
194
+ }
195
+
196
+ function __get( $k ) {
197
+ return $this->get( $k, null );
198
+ }
199
+
200
+ function offsetSet( $k, $v ) {
201
+ if ( is_null( $k ) ) {
202
+ throw new Exception( 'Can\'t append value to request params.' );
203
+ } else {
204
+ $this->{$k} = $v;
205
+ }
206
+ }
207
+
208
+ function offsetExists( $k ) {
209
+ return array_key_exists( $k, $this->_data );
210
+ }
211
+
212
+ function offsetUnset( $k ) {
213
+ unset( $this->$k );
214
+ }
215
+
216
+ function offsetGet( $k ) {
217
+ return $this->get( $k, null );
218
+ }
219
+
220
+ /**
221
+ * (PHP 5 &gt;= 5.0.0)<br/>
222
+ * Return the current element
223
+ *
224
+ * @link http://php.net/manual/en/iterator.current.php
225
+ * @return mixed Can return any type.
226
+ */
227
+ public function current() {
228
+ return current( $this->_data );
229
+ }
230
+
231
+ /**
232
+ * (PHP 5 &gt;= 5.0.0)<br/>
233
+ * Move forward to next element
234
+ *
235
+ * @link http://php.net/manual/en/iterator.next.php
236
+ * @return void Any returned value is ignored.
237
+ */
238
+ public function next() {
239
+ return next( $this->_data );
240
+ }
241
+
242
+ /**
243
+ * (PHP 5 &gt;= 5.0.0)<br/>
244
+ * Return the key of the current element
245
+ *
246
+ * @link http://php.net/manual/en/iterator.key.php
247
+ * @return mixed scalar on success, or null on failure.
248
+ */
249
+ public function key() {
250
+ return key( $this->_data );
251
+ }
252
+
253
+ /**
254
+ * (PHP 5 &gt;= 5.0.0)<br/>
255
+ * Checks if current position is valid
256
+ *
257
+ * @link http://php.net/manual/en/iterator.valid.php
258
+ * @return boolean The return value will be casted to boolean and then evaluated.
259
+ * Returns true on success or false on failure.
260
+ */
261
+ public function valid() {
262
+ $key = key( $this->_data );
263
+
264
+ return ( $key !== null && $key !== false );
265
+ }
266
+
267
+ /**
268
+ * (PHP 5 &gt;= 5.0.0)<br/>
269
+ * Rewind the Iterator to the first element
270
+ *
271
+ * @link http://php.net/manual/en/iterator.rewind.php
272
+ * @return void Any returned value is ignored.
273
+ */
274
+ public function rewind() {
275
+ reset( $this->_data );
276
+ }
277
+
278
+ /**
279
+ * (PHP 5 &gt;= 5.1.0)<br/>
280
+ * Count elements of an object
281
+ *
282
+ * @link http://php.net/manual/en/countable.count.php
283
+ * @return int The custom count as an integer.
284
+ * </p>
285
+ * <p>
286
+ * The return value is cast to an integer.
287
+ */
288
+ public function count() {
289
+ return count( $this->_data );
290
+ }
291
+ }
lib/freemius/includes/managers/class-fs-license-manager.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.6
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_License_Manager /*extends FS_Abstract_Manager*/
14
+ {
15
+ //
16
+ //
17
+ // /**
18
+ // * @var FS_License_Manager[]
19
+ // */
20
+ // private static $_instances = array();
21
+ //
22
+ // static function instance( Freemius $fs ) {
23
+ // $slug = strtolower( $fs->get_slug() );
24
+ //
25
+ // if ( ! isset( self::$_instances[ $slug ] ) ) {
26
+ // self::$_instances[ $slug ] = new FS_License_Manager( $slug, $fs );
27
+ // }
28
+ //
29
+ // return self::$_instances[ $slug ];
30
+ // }
31
+ //
32
+ //// private function __construct($slug) {
33
+ //// parent::__construct($slug);
34
+ //// }
35
+ //
36
+ // function entry_id() {
37
+ // return 'licenses';
38
+ // }
39
+ //
40
+ // function sync( $id ) {
41
+ //
42
+ // }
43
+ //
44
+ // /**
45
+ // * @author Vova Feldman (@svovaf)
46
+ // * @since 1.0.5
47
+ // * @uses FS_Api
48
+ // *
49
+ // * @param number|bool $plugin_id
50
+ // *
51
+ // * @return FS_Plugin_License[]|stdClass Licenses or API error.
52
+ // */
53
+ // function api_get_user_plugin_licenses( $plugin_id = false ) {
54
+ // $api = $this->_fs->get_api_user_scope();
55
+ //
56
+ // if ( ! is_numeric( $plugin_id ) ) {
57
+ // $plugin_id = $this->_fs->get_id();
58
+ // }
59
+ //
60
+ // $result = $api->call( "/plugins/{$plugin_id}/licenses.json" );
61
+ //
62
+ // if ( ! isset( $result->error ) ) {
63
+ // for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {
64
+ // $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );
65
+ // }
66
+ //
67
+ // $result = $result->licenses;
68
+ // }
69
+ //
70
+ // return $result;
71
+ // }
72
+ //
73
+ // function api_get_many() {
74
+ //
75
+ // }
76
+ //
77
+ // function api_activate( $id ) {
78
+ //
79
+ // }
80
+ //
81
+ // function api_deactivate( $id ) {
82
+ //
83
+ // }
84
+
85
+ /**
86
+ * @param FS_Plugin_License[] $licenses
87
+ *
88
+ * @return bool
89
+ */
90
+ static function has_premium_license( $licenses ) {
91
+ if ( is_array( $licenses ) ) {
92
+ foreach ( $licenses as $license ) {
93
+ if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
94
+ return true;
95
+ }
96
+ }
97
+ }
98
+
99
+ return false;
100
+ }
101
+ }
lib/freemius/includes/managers/class-fs-option-manager.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * 3-layer lazy options manager.
15
+ * layer 3: Memory
16
+ * layer 2: Cache (if there's any caching plugin and if WP_FS__DEBUG_SDK is FALSE)
17
+ * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB
18
+ * queries.
19
+ *
20
+ * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to
21
+ * explicitly call store().
22
+ *
23
+ * Class Freemius_Option_Manager
24
+ */
25
+ class FS_Option_Manager {
26
+ /**
27
+ * @var string
28
+ */
29
+ private $_id;
30
+ /**
31
+ * @var array
32
+ */
33
+ private $_options;
34
+ /**
35
+ * @var FS_Logger
36
+ */
37
+ private $_logger;
38
+
39
+ /**
40
+ * @var FS_Option_Manager[]
41
+ */
42
+ private static $_MANAGERS = array();
43
+
44
+ /**
45
+ * @author Vova Feldman (@svovaf)
46
+ * @since 1.0.3
47
+ *
48
+ * @param string $id
49
+ * @param bool $load
50
+ */
51
+ private function __construct( $id, $load = false ) {
52
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
53
+
54
+ $this->_logger->entrance();
55
+ $this->_logger->log( 'id = ' . $id );
56
+
57
+ $this->_id = $id;
58
+
59
+ if ( $load ) {
60
+ $this->load();
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @author Vova Feldman (@svovaf)
66
+ * @since 1.0.3
67
+ *
68
+ * @param $id
69
+ * @param $load
70
+ *
71
+ * @return FS_Option_Manager
72
+ */
73
+ static function get_manager( $id, $load = false ) {
74
+ $id = strtolower( $id );
75
+
76
+ if ( ! isset( self::$_MANAGERS[ $id ] ) ) {
77
+ self::$_MANAGERS[ $id ] = new FS_Option_Manager( $id, $load );
78
+ } // If load required but not yet loaded, load.
79
+ else if ( $load && ! self::$_MANAGERS[ $id ]->is_loaded() ) {
80
+ self::$_MANAGERS[ $id ]->load();
81
+ }
82
+
83
+ return self::$_MANAGERS[ $id ];
84
+ }
85
+
86
+ private function _get_option_manager_name() {
87
+ // return WP_FS__SLUG . '_' . $this->_id;
88
+ return $this->_id;
89
+ }
90
+
91
+ /**
92
+ * @author Vova Feldman (@svovaf)
93
+ * @since 1.0.3
94
+ *
95
+ * @param bool $flush
96
+ */
97
+ function load( $flush = false ) {
98
+ $this->_logger->entrance();
99
+
100
+ $option_name = $this->_get_option_manager_name();
101
+
102
+ if ( $flush || ! isset( $this->_options ) ) {
103
+ if ( ! WP_FS__DEBUG_SDK ) {
104
+ $this->_options = wp_cache_get( $option_name, WP_FS__SLUG );
105
+ }
106
+
107
+ // $this->_logger->info('wp_cache_get = ' . var_export($this->_options, true));
108
+
109
+ // if ( is_array( $this->_options ) ) {
110
+ // $this->clear();
111
+ // }
112
+
113
+ $cached = true;
114
+
115
+ if ( empty( $this->_options ) ) {
116
+ $this->_options = get_option( $option_name );
117
+
118
+ if ( is_string( $this->_options ) ) {
119
+ $this->_options = json_decode( $this->_options );
120
+ }
121
+
122
+ // $this->_logger->info('get_option = ' . var_export($this->_options, true));
123
+
124
+ if ( false === $this->_options ) {
125
+ $this->clear();
126
+ }
127
+
128
+ $cached = false;
129
+ }
130
+
131
+ if ( ! WP_FS__DEBUG_SDK && ! $cached ) // Set non encoded cache.
132
+ {
133
+ wp_cache_set( $option_name, $this->_options, WP_FS__SLUG );
134
+ }
135
+ }
136
+ }
137
+
138
+ /**
139
+ * @author Vova Feldman (@svovaf)
140
+ * @since 1.0.3
141
+ *
142
+ * @return bool
143
+ */
144
+ function is_loaded() {
145
+ return isset( $this->_options );
146
+ }
147
+
148
+ /**
149
+ * @author Vova Feldman (@svovaf)
150
+ * @since 1.0.3
151
+ *
152
+ * @return bool
153
+ */
154
+ function is_empty() {
155
+ return ( $this->is_loaded() && false === $this->_options );
156
+ }
157
+
158
+ /**
159
+ * @author Vova Feldman (@svovaf)
160
+ * @since 1.0.6
161
+ *
162
+ * @param bool $flush
163
+ */
164
+ function clear( $flush = false ) {
165
+ $this->_logger->entrance();
166
+
167
+ $this->_options = array();
168
+
169
+ if ( $flush ) {
170
+ $this->store();
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Delete options manager from DB.
176
+ *
177
+ * @author Vova Feldman (@svovaf)
178
+ * @since 1.0.9
179
+ */
180
+ function delete() {
181
+ delete_option( $this->_get_option_manager_name() );
182
+ }
183
+
184
+ /**
185
+ * @author Vova Feldman (@svovaf)
186
+ * @since 1.0.6
187
+ *
188
+ * @param string $option
189
+ *
190
+ * @return bool
191
+ */
192
+ function has_option( $option ) {
193
+ return array_key_exists( $option, $this->_options );
194
+ }
195
+
196
+ /**
197
+ * @author Vova Feldman (@svovaf)
198
+ * @since 1.0.3
199
+ *
200
+ * @param string $option
201
+ * @param mixed $default
202
+ *
203
+ * @return mixed
204
+ */
205
+ function get_option( $option, $default = null ) {
206
+ $this->_logger->entrance( 'option = ' . $option );
207
+
208
+ if ( is_array( $this->_options ) ) {
209
+ return isset( $this->_options[ $option ] ) ? $this->_options[ $option ] : $default;
210
+ } else if ( is_object( $this->_options ) ) {
211
+ return isset( $this->_options->{$option} ) ? $this->_options->{$option} : $default;
212
+ }
213
+
214
+ return $default;
215
+ }
216
+
217
+ /**
218
+ * @author Vova Feldman (@svovaf)
219
+ * @since 1.0.3
220
+ *
221
+ * @param string $option
222
+ * @param mixed $value
223
+ * @param bool $flush
224
+ */
225
+ function set_option( $option, $value, $flush = false ) {
226
+ $this->_logger->entrance( 'option = ' . $option );
227
+
228
+ if ( ! $this->is_loaded() ) {
229
+ $this->clear();
230
+ }
231
+
232
+ if ( is_array( $this->_options ) ) {
233
+ $this->_options[ $option ] = $value;
234
+ } else if ( is_object( $this->_options ) ) {
235
+ $this->_options->{$option} = $value;
236
+ }
237
+
238
+ if ( $flush ) {
239
+ $this->store();
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Unset option.
245
+ *
246
+ * @author Vova Feldman (@svovaf)
247
+ * @since 1.0.3
248
+ *
249
+ * @param string $option
250
+ * @param bool $flush
251
+ */
252
+ function unset_option( $option, $flush = false ) {
253
+ $this->_logger->entrance( 'option = ' . $option );
254
+
255
+ if ( is_array( $this->_options ) ) {
256
+ if ( ! isset( $this->_options[ $option ] ) ) {
257
+ return;
258
+ }
259
+
260
+ unset( $this->_options[ $option ] );
261
+
262
+ } else if ( is_object( $this->_options ) ) {
263
+ if ( ! isset( $this->_options->{$option} ) ) {
264
+ return;
265
+ }
266
+
267
+ unset( $this->_options->{$option} );
268
+ }
269
+
270
+ if ( $flush ) {
271
+ $this->store();
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Dump options to database.
277
+ *
278
+ * @author Vova Feldman (@svovaf)
279
+ * @since 1.0.3
280
+ */
281
+ function store() {
282
+ $this->_logger->entrance();
283
+
284
+ $option_name = $this->_get_option_manager_name();
285
+
286
+ if ( $this->_logger->is_on() ) {
287
+ $this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) );
288
+ }
289
+
290
+ // Update DB.
291
+ update_option( $option_name, $this->_options );
292
+
293
+ if ( ! WP_FS__DEBUG_SDK ) {
294
+ wp_cache_set( $option_name, $this->_options, WP_FS__SLUG );
295
+ }
296
+ }
297
+ }
lib/freemius/includes/managers/class-fs-plan-manager.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.6
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plan_Manager {
14
+ /**
15
+ * @var FS_Plan_Manager
16
+ */
17
+ private static $_instance;
18
+
19
+ /**
20
+ * @return FS_Plan_Manager
21
+ */
22
+ static function instance() {
23
+ if ( ! isset( self::$_instance ) ) {
24
+ self::$_instance = new FS_Plan_Manager();
25
+ }
26
+
27
+ return self::$_instance;
28
+ }
29
+
30
+ private function __construct() {
31
+ }
32
+
33
+ /**
34
+ * @param FS_Plugin_License[] $licenses
35
+ *
36
+ * @return bool
37
+ */
38
+ function has_premium_license( $licenses ) {
39
+ if ( is_array( $licenses ) ) {
40
+ foreach ( $licenses as $license ) {
41
+ if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
42
+ return true;
43
+ }
44
+ }
45
+ }
46
+
47
+ return false;
48
+ }
49
+
50
+ /**
51
+ * Check if plugin has any paid plans.
52
+ *
53
+ * @author Vova Feldman (@svovaf)
54
+ * @since 1.0.7
55
+ *
56
+ * @param FS_Plugin_Plan[] $plans
57
+ *
58
+ * @return bool
59
+ */
60
+ function has_paid_plan( $plans ) {
61
+ if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
62
+ return false;
63
+ }
64
+
65
+ for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
66
+ if ( ! $plans[ $i ]->is_free() ) {
67
+ return true;
68
+ }
69
+ }
70
+
71
+ return false;
72
+ }
73
+
74
+ /**
75
+ * Check if plugin has any free plan, or is it premium only.
76
+ *
77
+ * Note: If no plans configured, assume plugin is free.
78
+ *
79
+ * @author Vova Feldman (@svovaf)
80
+ * @since 1.0.7
81
+ *
82
+ * @param FS_Plugin_Plan[] $plans
83
+ *
84
+ * @return bool
85
+ */
86
+ function has_free_plan( $plans ) {
87
+ if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
88
+ return true;
89
+ }
90
+
91
+ for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
92
+ if ( $plans[ $i ]->is_free() ) {
93
+ return true;
94
+ }
95
+ }
96
+
97
+ return false;
98
+ }
99
+
100
+ /**
101
+ * Find all plans that have trial.
102
+ *
103
+ * @author Vova Feldman (@svovaf)
104
+ * @since 1.0.9
105
+ *
106
+ * @param FS_Plugin_Plan[] $plans
107
+ *
108
+ * @return FS_Plugin_Plan[]
109
+ */
110
+ function get_trial_plans( $plans ) {
111
+ $trial_plans = array();
112
+
113
+ if ( is_array( $plans ) && 0 < count( $plans ) ) {
114
+ for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
115
+ if ( $plans[ $i ]->has_trial() ) {
116
+ $trial_plans[] = $plans[ $i ];
117
+ }
118
+ }
119
+ }
120
+
121
+ return $trial_plans;
122
+ }
123
+
124
+ /**
125
+ * Check if plugin has any trial plan.
126
+ *
127
+ * @author Vova Feldman (@svovaf)
128
+ * @since 1.0.9
129
+ *
130
+ * @param FS_Plugin_Plan[] $plans
131
+ *
132
+ * @return bool
133
+ */
134
+ function has_trial_plan( $plans ) {
135
+ if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
136
+ return true;
137
+ }
138
+
139
+ for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
140
+ if ( $plans[ $i ]->has_trial() ) {
141
+ return true;
142
+ }
143
+ }
144
+
145
+ return false;
146
+ }
147
+ }
lib/freemius/includes/managers/class-fs-plugin-manager.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.6
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Plugin_Manager {
14
+ /**
15
+ * @var string
16
+ */
17
+ protected $_slug;
18
+ /**
19
+ * @var FS_Plugin
20
+ */
21
+ protected $_plugin;
22
+
23
+ /**
24
+ * @var FS_Plugin_Manager[]
25
+ */
26
+ private static $_instances = array();
27
+ /**
28
+ * @var FS_Logger
29
+ */
30
+ protected $_logger;
31
+
32
+ /**
33
+ * @param string $slug
34
+ *
35
+ * @return FS_Plugin_Manager
36
+ */
37
+ static function instance( $slug ) {
38
+ if ( ! isset( self::$_instances[ $slug ] ) ) {
39
+ self::$_instances[ $slug ] = new FS_Plugin_Manager( $slug );
40
+ }
41
+
42
+ return self::$_instances[ $slug ];
43
+ }
44
+
45
+ protected function __construct( $slug ) {
46
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_' . 'plugins', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
47
+
48
+ $this->_slug = $slug;
49
+ $this->load();
50
+ }
51
+
52
+ protected function get_option_manager() {
53
+ return FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
54
+ }
55
+
56
+ protected function get_all_plugins() {
57
+ return $this->get_option_manager()->get_option( 'plugins', array() );
58
+ }
59
+
60
+ /**
61
+ * Load plugin data from local DB.
62
+ *
63
+ * @author Vova Feldman (@svovaf)
64
+ * @since 1.0.6
65
+ */
66
+ function load() {
67
+ $all_plugins = $this->get_all_plugins();
68
+ $this->_plugin = isset( $all_plugins[ $this->_slug ] ) ?
69
+ $all_plugins[ $this->_slug ] :
70
+ null;
71
+ }
72
+
73
+ /**
74
+ * Store plugin on local DB.
75
+ *
76
+ * @author Vova Feldman (@svovaf)
77
+ * @since 1.0.6
78
+ *
79
+ * @param bool|FS_Plugin $plugin
80
+ * @param bool $flush
81
+ *
82
+ * @return bool|\FS_Plugin
83
+ */
84
+ function store( $plugin = false, $flush = true ) {
85
+ $all_plugins = $this->get_all_plugins();
86
+
87
+ if ( false !== $plugin ) {
88
+ $this->_plugin = $plugin;
89
+ }
90
+
91
+ $all_plugins[ $this->_slug ] = $this->_plugin;
92
+
93
+ $options_manager = $this->get_option_manager();
94
+ $options_manager->set_option( 'plugins', $all_plugins, $flush );
95
+
96
+ return $this->_plugin;
97
+ }
98
+
99
+ /**
100
+ * Update local plugin data if different.
101
+ *
102
+ * @author Vova Feldman (@svovaf)
103
+ * @since 1.0.6
104
+ *
105
+ * @param \FS_Plugin $plugin
106
+ * @param bool $store
107
+ *
108
+ * @return bool True if plugin was updated.
109
+ */
110
+ function update( FS_Plugin $plugin, $store = true ) {
111
+ if ( ! ( $this->_plugin instanceof FS_Plugin ) ||
112
+ $this->_plugin->slug != $plugin->slug ||
113
+ $this->_plugin->public_key != $plugin->public_key ||
114
+ $this->_plugin->secret_key != $plugin->secret_key ||
115
+ $this->_plugin->parent_plugin_id != $plugin->parent_plugin_id ||
116
+ $this->_plugin->title != $plugin->title
117
+ ) {
118
+ $this->store( $plugin, $store );
119
+
120
+ return true;
121
+ }
122
+
123
+ return false;
124
+ }
125
+
126
+ /**
127
+ * @author Vova Feldman (@svovaf)
128
+ * @since 1.0.6
129
+ *
130
+ * @param FS_Plugin $plugin
131
+ * @param bool $store
132
+ */
133
+ function set( FS_Plugin $plugin, $store = false ) {
134
+ $this->_plugin = $plugin;
135
+
136
+ if ( $store ) {
137
+ $this->store();
138
+ }
139
+ }
140
+
141
+ /**
142
+ * @author Vova Feldman (@svovaf)
143
+ * @since 1.0.6
144
+ *
145
+ * @return bool|\FS_Plugin
146
+ */
147
+ function get() {
148
+ return isset( $this->_plugin ) ?
149
+ $this->_plugin :
150
+ false;
151
+ }
152
+
153
+
154
+ }
lib/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ class Freemius_ArgumentNotExistException extends Freemius_InvalidArgumentException { }
lib/freemius/includes/sdk/Exceptions/EmptyArgumentException.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ class Freemius_EmptyArgumentException extends Freemius_InvalidArgumentException { }
lib/freemius/includes/sdk/Exceptions/Exception.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Thrown when an API call returns an exception.
4
+ *
5
+ */
6
+ class Freemius_Exception extends Exception
7
+ {
8
+ protected $_result;
9
+ protected $_type;
10
+ protected $_code;
11
+
12
+ /**
13
+ * Make a new API Exception with the given result.
14
+ *
15
+ * @param array $result The result from the API server.
16
+ */
17
+ public function __construct($result)
18
+ {
19
+ $this->_result = $result;
20
+
21
+ $code = 0;
22
+ $message = 'Unknown error, please check GetResult().';
23
+ $type = '';
24
+
25
+ if (isset($result['error']) && is_array($result['error']))
26
+ {
27
+ if (isset($result['error']['code']))
28
+ $code = $result['error']['code'];
29
+ if (isset($result['error']['message']))
30
+ $message = $result['error']['message'];
31
+ if (isset($result['error']['type']))
32
+ $type = $result['error']['type'];
33
+ }
34
+
35
+ $this->_type = $type;
36
+ $this->_code = $code;
37
+
38
+ parent::__construct($message, is_numeric($code) ? $code : 0);
39
+ }
40
+
41
+ /**
42
+ * Return the associated result object returned by the API server.
43
+ *
44
+ * @return array The result from the API server
45
+ */
46
+ public function getResult()
47
+ {
48
+ return $this->_result;
49
+ }
50
+
51
+ public function getStringCode()
52
+ {
53
+ return $this->_code;
54
+ }
55
+
56
+ public function getType()
57
+ {
58
+ return $this->_type;
59
+ }
60
+
61
+ /**
62
+ * To make debugging easier.
63
+ *
64
+ * @return string The string representation of the error
65
+ */
66
+ public function __toString()
67
+ {
68
+ $str = $this->getType() . ': ';
69
+
70
+ if ($this->code != 0)
71
+ $str .= $this->getStringCode() . ': ';
72
+
73
+ return $str . $this->getMessage();
74
+ }
75
+ }
lib/freemius/includes/sdk/Exceptions/InvalidArgumentException.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ class Freemius_InvalidArgumentException extends Freemius_Exception { }
lib/freemius/includes/sdk/Exceptions/OAuthException.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Freemius_OAuthException extends Freemius_Exception
3
+ {
4
+ public function __construct($pResult)
5
+ {
6
+ parent::__construct($pResult);
7
+ }
8
+ }
lib/freemius/includes/sdk/Freemius.php ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2014 Freemius, Inc.
4
+ *
5
+ * Licensed under the GPL v2 (the "License"); you may
6
+ * not use this file except in compliance with the License. You may obtain
7
+ * a copy of the License at
8
+ *
9
+ * http://choosealicense.com/licenses/gpl-v2/
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ * License for the specific language governing permissions and limitations
15
+ * under the License.
16
+ */
17
+
18
+ require_once( dirname( __FILE__ ) . '/FreemiusBase.php' );
19
+
20
+ define( 'FS_SDK__USER_AGENT', 'fs-php-' . Freemius_Api_Base::VERSION );
21
+
22
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_CURL' ) ) {
23
+ define( 'FS_SDK__SIMULATE_NO_CURL', false );
24
+ }
25
+
26
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE' ) ) {
27
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false );
28
+ }
29
+
30
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL' ) ) {
31
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false );
32
+ }
33
+
34
+ define( 'FS_SDK__HAS_CURL', ! FS_SDK__SIMULATE_NO_CURL && function_exists( 'curl_version' ) );
35
+
36
+ if ( ! FS_SDK__HAS_CURL ) {
37
+ $curl_version = array( 'version' => '7.0.0' );
38
+ } else {
39
+ $curl_version = curl_version();
40
+ }
41
+
42
+ define( 'FS_API__PROTOCOL', version_compare( $curl_version['version'], '7.37', '>=' ) ? 'https' : 'http' );
43
+
44
+ if ( ! defined( 'FS_API__ADDRESS' ) ) {
45
+ define( 'FS_API__ADDRESS', '://api.freemius.com' );
46
+ }
47
+ if ( ! defined( 'FS_API__SANDBOX_ADDRESS' ) ) {
48
+ define( 'FS_API__SANDBOX_ADDRESS', '://sandbox-api.freemius.com' );
49
+ }
50
+
51
+ class Freemius_Api extends Freemius_Api_Base {
52
+ /**
53
+ * Default options for curl.
54
+ */
55
+ public static $CURL_OPTS = array(
56
+ CURLOPT_CONNECTTIMEOUT => 10,
57
+ CURLOPT_RETURNTRANSFER => true,
58
+ CURLOPT_TIMEOUT => 60,
59
+ CURLOPT_USERAGENT => FS_SDK__USER_AGENT,
60
+ );
61
+
62
+ /**
63
+ * @param string $pScope 'app', 'developer', 'user' or 'install'.
64
+ * @param number $pID Element's id.
65
+ * @param string $pPublic Public key.
66
+ * @param string|bool $pSecret Element's secret key.
67
+ * @param bool $pSandbox Whether or not to run API in sandbox mode.
68
+ */
69
+ public function __construct( $pScope, $pID, $pPublic, $pSecret = false, $pSandbox = false ) {
70
+ // If secret key not provided, use public key encryption.
71
+ if ( is_bool( $pSecret ) ) {
72
+ $pSecret = $pPublic;
73
+ }
74
+
75
+ parent::Init( $pScope, $pID, $pPublic, $pSecret, $pSandbox );
76
+ }
77
+
78
+ public function GetUrl( $pCanonizedPath = '' ) {
79
+ $address = ( $this->_sandbox ? FS_API__SANDBOX_ADDRESS : FS_API__ADDRESS );
80
+
81
+ if ( ':' === $address[0] ) {
82
+ $address = self::$_protocol . $address;
83
+ }
84
+
85
+ return $address . $pCanonizedPath;
86
+ }
87
+
88
+ /**
89
+ * @var int Clock diff in seconds between current server to API server.
90
+ */
91
+ private static $_clock_diff = 0;
92
+
93
+ /**
94
+ * Set clock diff for all API calls.
95
+ *
96
+ * @since 1.0.3
97
+ *
98
+ * @param $pSeconds
99
+ */
100
+ public static function SetClockDiff( $pSeconds ) {
101
+ self::$_clock_diff = $pSeconds;
102
+ }
103
+
104
+ /**
105
+ * @var string http or https
106
+ */
107
+ private static $_protocol = FS_API__PROTOCOL;
108
+
109
+ /**
110
+ * Set API connection protocol.
111
+ *
112
+ * @since 1.0.4
113
+ */
114
+ public static function SetHttp() {
115
+ self::$_protocol = 'http';
116
+ }
117
+
118
+ /**
119
+ * @since 1.0.4
120
+ *
121
+ * @return bool
122
+ */
123
+ public static function IsHttps() {
124
+ return ( 'https' === self::$_protocol );
125
+ }
126
+
127
+ /**
128
+ * Sign request with the following HTTP headers:
129
+ * Content-MD5: MD5(HTTP Request body)
130
+ * Date: Current date (i.e Sat, 14 Feb 2015 20:24:46 +0000)
131
+ * Authorization: FS {scope_entity_id}:{scope_entity_public_key}:base64encode(sha256(string_to_sign,
132
+ * {scope_entity_secret_key}))
133
+ *
134
+ * @param string $pResourceUrl
135
+ * @param array $opts
136
+ */
137
+ protected function SignRequest( $pResourceUrl, &$opts ) {
138
+ $eol = "\n";
139
+ $content_md5 = '';
140
+ $now = ( time() - self::$_clock_diff );
141
+ $date = date( 'r', $now );
142
+ $content_type = '';
143
+
144
+ if ( isset( $opts[ CURLOPT_POST ] ) && 0 < $opts[ CURLOPT_POST ] ) {
145
+ $content_md5 = md5( $opts[ CURLOPT_POSTFIELDS ] );
146
+ $opts[ CURLOPT_HTTPHEADER ][] = 'Content-MD5: ' . $content_md5;
147
+ $content_type = 'application/json';
148
+ }
149
+
150
+ $opts[ CURLOPT_HTTPHEADER ][] = 'Date: ' . $date;
151
+
152
+ $string_to_sign = implode( $eol, array(
153
+ $opts[ CURLOPT_CUSTOMREQUEST ],
154
+ $content_md5,
155
+ $content_type,
156
+ $date,
157
+ $pResourceUrl
158
+ ) );
159
+
160
+ // If secret and public keys are identical, it means that
161
+ // the signature uses public key hash encoding.
162
+ $auth_type = ( $this->_secret !== $this->_public ) ? 'FS' : 'FSP';
163
+
164
+ // Add authorization header.
165
+ $opts[ CURLOPT_HTTPHEADER ][] = 'Authorization: ' .
166
+ $auth_type . ' ' .
167
+ $this->_id . ':' .
168
+ $this->_public . ':' .
169
+ self::Base64UrlEncode(
170
+ hash_hmac( 'sha256', $string_to_sign, $this->_secret )
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Get API request URL signed via query string.
176
+ *
177
+ * @param string $pPath
178
+ *
179
+ * @throws Freemius_Exception
180
+ *
181
+ * @return string
182
+ */
183
+ function GetSignedUrl( $pPath ) {
184
+ $resource = explode( '?', $this->CanonizePath( $pPath ) );
185
+ $pResourceUrl = $resource[0];
186
+
187
+ $eol = "\n";
188
+ $content_md5 = '';
189
+ $content_type = '';
190
+ $now = ( time() - self::$_clock_diff );
191
+ $date = date( 'r', $now );
192
+
193
+ $string_to_sign = implode( $eol, array(
194
+ 'GET',
195
+ $content_md5,
196
+ $content_type,
197
+ $date,
198
+ $pResourceUrl
199
+ ) );
200
+
201
+ // If secret and public keys are identical, it means that
202
+ // the signature uses public key hash encoding.
203
+ $auth_type = ( $this->_secret !== $this->_public ) ? 'FS' : 'FSP';
204
+
205
+ return $this->GetUrl(
206
+ $pResourceUrl . '?' .
207
+ ( 1 < count( $resource ) && ! empty( $resource[1] ) ? $resource[1] . '&' : '' ) .
208
+ http_build_query( array(
209
+ 'auth_date' => $date,
210
+ 'authorization' => $auth_type . ' ' . $this->_id . ':' .
211
+ $this->_public . ':' .
212
+ self::Base64UrlEncode( hash_hmac(
213
+ 'sha256', $string_to_sign, $this->_secret
214
+ ) )
215
+ ) ) );
216
+ }
217
+
218
+ /**
219
+ * Makes an HTTP request. This method can be overridden by subclasses if
220
+ * developers want to do fancier things or use something other than curl to
221
+ * make the request.
222
+ *
223
+ * @param string $pCanonizedPath The URL to make the request to
224
+ * @param string $pMethod HTTP method
225
+ * @param array $params The parameters to use for the POST body
226
+ * @param null|resource $ch Initialized curl handle
227
+ *
228
+ * @return object[]|object|null
229
+ *
230
+ * @throws Freemius_Exception
231
+ */
232
+ public function MakeRequest( $pCanonizedPath, $pMethod = 'GET', $params = array(), $ch = null ) {
233
+ if ( !FS_SDK__HAS_CURL ) {
234
+ $this->ThrowNoCurlException();
235
+ }
236
+
237
+ // Connectivity errors simulation.
238
+ if ( FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE ) {
239
+ $this->ThrowCloudFlareDDoSException();
240
+ } else if ( FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL ) {
241
+ $this->ThrowSquidAclException();
242
+ }
243
+
244
+ if ( ! $ch ) {
245
+ $ch = curl_init();
246
+ }
247
+
248
+ $opts = self::$CURL_OPTS;
249
+
250
+ if ( ! isset( $opts[ CURLOPT_HTTPHEADER ] ) || ! is_array( $opts[ CURLOPT_HTTPHEADER ] ) ) {
251
+ $opts[ CURLOPT_HTTPHEADER ] = array();
252
+ }
253
+
254
+ if ( 'POST' === $pMethod || 'PUT' === $pMethod ) {
255
+ if ( is_array( $params ) && 0 < count( $params ) ) {
256
+ $opts[ CURLOPT_HTTPHEADER ][] = 'Content-Type: application/json';
257
+ $opts[ CURLOPT_POST ] = count( $params );
258
+ $opts[ CURLOPT_POSTFIELDS ] = json_encode( $params );
259
+ }
260
+
261
+ $opts[ CURLOPT_RETURNTRANSFER ] = true;
262
+ }
263
+
264
+ $opts[ CURLOPT_URL ] = $this->GetUrl( $pCanonizedPath );
265
+ $opts[ CURLOPT_CUSTOMREQUEST ] = $pMethod;
266
+
267
+ $resource = explode( '?', $pCanonizedPath );
268
+
269
+ // Only sign request if not ping.json connectivity test.
270
+ if ( '/v1/ping.json' !== strtolower( substr( $resource[0], - strlen( '/v1/ping.json' ) ) ) ) {
271
+ $this->SignRequest( $resource[0], $opts );
272
+ }
273
+
274
+ // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
275
+ // for 2 seconds if the server does not support this header.
276
+ $opts[ CURLOPT_HTTPHEADER ][] = 'Expect:';
277
+
278
+ if ( 'https' === substr( strtolower( $pCanonizedPath ), 0, 5 ) ) {
279
+ $opts[ CURLOPT_SSL_VERIFYHOST ] = false;
280
+ $opts[ CURLOPT_SSL_VERIFYPEER ] = false;
281
+ }
282
+
283
+ curl_setopt_array( $ch, $opts );
284
+ $result = curl_exec( $ch );
285
+
286
+ /*if (curl_errno($ch) == 60) // CURLE_SSL_CACERT
287
+ {
288
+ self::errorLog('Invalid or no certificate authority found, using bundled information');
289
+ curl_setopt($ch, CURLOPT_CAINFO,
290
+ dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
291
+ $result = curl_exec($ch);
292
+ }*/
293
+
294
+ // With dual stacked DNS responses, it's possible for a server to
295
+ // have IPv6 enabled but not have IPv6 connectivity. If this is
296
+ // the case, curl will try IPv4 first and if that fails, then it will
297
+ // fall back to IPv6 and the error EHOSTUNREACH is returned by the
298
+ // operating system.
299
+ if ( false === $result && empty( $opts[ CURLOPT_IPRESOLVE ] ) ) {
300
+ $matches = array();
301
+ $regex = '/Failed to connect to ([^:].*): Network is unreachable/';
302
+ if ( preg_match( $regex, curl_error( $ch ), $matches ) ) {
303
+ if ( strlen( @inet_pton( $matches[1] ) ) === 16 ) {
304
+ // self::errorLog('Invalid IPv6 configuration on server, Please disable or get native IPv6 on your server.');
305
+ self::$CURL_OPTS[ CURLOPT_IPRESOLVE ] = CURL_IPRESOLVE_V4;
306
+ curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
307
+ $result = curl_exec( $ch );
308
+ }
309
+ }
310
+ }
311
+
312
+ if ( $result === false ) {
313
+ $e = new Freemius_Exception( array(
314
+ 'error' => array(
315
+ 'code' => curl_errno( $ch ),
316
+ 'message' => curl_error( $ch ),
317
+ 'type' => 'CurlException',
318
+ ),
319
+ ) );
320
+
321
+ curl_close( $ch );
322
+ throw $e;
323
+ }
324
+
325
+ curl_close( $ch );
326
+
327
+ if (empty($result))
328
+ return null;
329
+
330
+ $decoded = json_decode( $result );
331
+
332
+ if ( is_null( $decoded ) ) {
333
+ if ( preg_match( '/Please turn JavaScript on/i', $result ) &&
334
+ preg_match( '/text\/javascript/', $result )
335
+ ) {
336
+ $this->ThrowCloudFlareDDoSException( $result );
337
+ } else if ( preg_match( '/Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect./', $result ) &&
338
+ preg_match( '/squid/', $result )
339
+ ) {
340
+ $this->ThrowSquidAclException( $result );
341
+ } else {
342
+ $decoded = (object) array(
343
+ 'error' => (object) array(
344
+ 'type' => 'Unknown',
345
+ 'message' => $result,
346
+ 'code' => 'unknown',
347
+ 'http' => 402
348
+ )
349
+ );
350
+ }
351
+ }
352
+
353
+ return $decoded;
354
+ }
355
+
356
+ /**
357
+ * @param string $pResult
358
+ *
359
+ * @throws Freemius_Exception
360
+ */
361
+ private function ThrowNoCurlException( $pResult = '' ) {
362
+ throw new Freemius_Exception( array(
363
+ 'error' => (object) array(
364
+ 'type' => 'cUrlMissing',
365
+ 'message' => $pResult,
366
+ 'code' => 'curl_missing',
367
+ 'http' => 402
368
+ )
369
+ ) );
370
+ }
371
+
372
+ /**
373
+ * @param string $pResult
374
+ *
375
+ * @throws Freemius_Exception
376
+ */
377
+ private function ThrowCloudFlareDDoSException( $pResult = '' ) {
378
+ throw new Freemius_Exception( array(
379
+ 'error' => (object) array(
380
+ 'type' => 'CloudFlareDDoSProtection',
381
+ 'message' => $pResult,
382
+ 'code' => 'cloudflare_ddos_protection',
383
+ 'http' => 402
384
+ )
385
+ ) );
386
+ }
387
+
388
+ /**
389
+ * @param string $pResult
390
+ *
391
+ * @throws Freemius_Exception
392
+ */
393
+ private function ThrowSquidAclException( $pResult = '' ) {
394
+ throw new Freemius_Exception( array(
395
+ 'error' => (object) array(
396
+ 'type' => 'SquidCacheBlock',
397
+ 'message' => $pResult,
398
+ 'code' => 'squid_cache_block',
399
+ 'http' => 402
400
+ )
401
+ ) );
402
+ }
403
+ }
lib/freemius/includes/sdk/FreemiusBase.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2014 Freemius, Inc.
4
+ *
5
+ * Licensed under the GPL v2 (the "License"); you may
6
+ * not use this file except in compliance with the License. You may obtain
7
+ * a copy of the License at
8
+ *
9
+ * http://choosealicense.com/licenses/gpl-v2/
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ * License for the specific language governing permissions and limitations
15
+ * under the License.
16
+ */
17
+
18
+ define( 'FS_API__VERSION', '1' );
19
+ define( 'FS_SDK__PATH', dirname( __FILE__ ) );
20
+ define( 'FS_SDK__EXCEPTIONS_PATH', FS_SDK__PATH . '/Exceptions/' );
21
+
22
+ if ( ! function_exists( 'json_decode' ) ) {
23
+ throw new Exception( 'Freemius needs the JSON PHP extension.' );
24
+ }
25
+
26
+ // Include all exception files.
27
+ $exceptions = array(
28
+ 'Exception',
29
+ 'InvalidArgumentException',
30
+ 'ArgumentNotExistException',
31
+ 'EmptyArgumentException',
32
+ 'OAuthException'
33
+ );
34
+
35
+ foreach ( $exceptions as $e ) {
36
+ require FS_SDK__EXCEPTIONS_PATH . $e . '.php';
37
+ }
38
+
39
+ abstract class Freemius_Api_Base {
40
+ const VERSION = '1.0.4';
41
+ const FORMAT = 'json';
42
+
43
+ protected $_id;
44
+ protected $_public;
45
+ protected $_secret;
46
+ protected $_scope;
47
+ protected $_sandbox;
48
+
49
+ /**
50
+ * @param string $pScope 'app', 'developer', 'user' or 'install'.
51
+ * @param number $pID Element's id.
52
+ * @param string $pPublic Public key.
53
+ * @param string $pSecret Element's secret key.
54
+ * @param bool $pSandbox Whether or not to run API in sandbox mode.
55
+ */
56
+ public function Init( $pScope, $pID, $pPublic, $pSecret, $pSandbox = false ) {
57
+ $this->_id = $pID;
58
+ $this->_public = $pPublic;
59
+ $this->_secret = $pSecret;
60
+ $this->_scope = $pScope;
61
+ $this->_sandbox = $pSandbox;
62
+ }
63
+
64
+ public function IsSandbox() {
65
+ return $this->_sandbox;
66
+ }
67
+
68
+ function CanonizePath( $pPath ) {
69
+ $pPath = trim( $pPath, '/' );
70
+ $query_pos = strpos( $pPath, '?' );
71
+ $query = '';
72
+
73
+ if ( false !== $query_pos ) {
74
+ $query = substr( $pPath, $query_pos );
75
+ $pPath = substr( $pPath, 0, $query_pos );
76
+ }
77
+
78
+ // Trim '.json' suffix.
79
+ $format_length = strlen( '.' . self::FORMAT );
80
+ $start = $format_length * ( - 1 ); //negative
81
+ if ( substr( strtolower( $pPath ), $start ) === ( '.' . self::FORMAT ) ) {
82
+ $pPath = substr( $pPath, 0, strlen( $pPath ) - $format_length );
83
+ }
84
+
85
+ switch ( $this->_scope ) {
86
+ case 'app':
87
+ $base = '/apps/' . $this->_id;
88
+ break;
89
+ case 'developer':
90
+ $base = '/developers/' . $this->_id;
91
+ break;
92
+ case 'user':
93
+ $base = '/users/' . $this->_id;
94
+ break;
95
+ case 'plugin':
96
+ $base = '/plugins/' . $this->_id;
97
+ break;
98
+ case 'install':
99
+ $base = '/installs/' . $this->_id;
100
+ break;
101
+ default:
102
+ throw new Freemius_Exception( 'Scope not implemented.' );
103
+ }
104
+
105
+ return '/v' . FS_API__VERSION . $base .
106
+ ( ! empty( $pPath ) ? '/' : '' ) . $pPath .
107
+ ( ( false === strpos( $pPath, '.' ) ) ? '.' . self::FORMAT : '' ) . $query;
108
+ }
109
+
110
+ abstract function MakeRequest( $pCanonizedPath, $pMethod = 'GET', $pParams = array() );
111
+
112
+ /**
113
+ * @param string $pPath
114
+ * @param string $pMethod
115
+ * @param array $pParams
116
+ *
117
+ * @return object[]|object|null
118
+ */
119
+ private function _Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
120
+ $pMethod = strtoupper( $pMethod );
121
+
122
+ try {
123
+ $result = $this->MakeRequest( $pPath, $pMethod, $pParams );
124
+ } catch ( Freemius_Exception $e ) {
125
+ // Map to error object.
126
+ $result = (object) $e->getResult();
127
+ } catch ( Exception $e ) {
128
+ // Map to error object.
129
+ $result = (object) array(
130
+ 'error' => array(
131
+ 'type' => 'Unknown',
132
+ 'message' => $e->getMessage() . ' (' . $e->getFile() . ': ' . $e->getLine() . ')',
133
+ 'code' => 'unknown',
134
+ 'http' => 402
135
+ )
136
+ );
137
+ }
138
+
139
+ return $result;
140
+ }
141
+
142
+ /**
143
+ * If successful connectivity to the API endpoint using ping.json endpoint.
144
+ *
145
+ * - OR -
146
+ *
147
+ * Validate if ping result object is valid.
148
+ *
149
+ * @param mixed $pPong
150
+ *
151
+ * @return bool
152
+ */
153
+ public function Test( $pPong = null ) {
154
+ $pong = is_null( $pPong ) ? $this->Ping() : $pPong;
155
+
156
+ return ( is_object( $pong ) && isset( $pong->api ) && 'pong' === $pong->api );
157
+ }
158
+
159
+ /**
160
+ * Ping API to test connectivity.
161
+ *
162
+ * @return object
163
+ */
164
+ public function Ping() {
165
+ return $this->_Api( '/v' . FS_API__VERSION . '/ping.json' );
166
+ }
167
+
168
+ /**
169
+ * Find clock diff between current server to API server.
170
+ *
171
+ * @since 1.0.2
172
+ * @return int Clock diff in seconds.
173
+ */
174
+ public function FindClockDiff() {
175
+ $time = time();
176
+ $pong = $this->_Api( '/v' . FS_API__VERSION . '/ping.json' );
177
+
178
+ return ( $time - strtotime( $pong->timestamp ) );
179
+ }
180
+
181
+ public function Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
182
+ return $this->_Api( $this->CanonizePath( $pPath ), $pMethod, $pParams );
183
+ }
184
+
185
+ /**
186
+ * Base64 encoding that does not need to be urlencode()ed.
187
+ * Exactly the same as base64_encode except it uses
188
+ * - instead of +
189
+ * _ instead of /
190
+ * No padded =
191
+ *
192
+ * @param string $input base64UrlEncoded string
193
+ *
194
+ * @return string
195
+ */
196
+ protected static function Base64UrlDecode( $input ) {
197
+ return base64_decode( strtr( $input, '-_', '+/' ) );
198
+ }
199
+
200
+ /**
201
+ * Base64 encoding that does not need to be urlencode()ed.
202
+ * Exactly the same as base64_encode except it uses
203
+ * - instead of +
204
+ * _ instead of /
205
+ *
206
+ * @param string $input string
207
+ *
208
+ * @return string base64Url encoded string
209
+ */
210
+ protected static function Base64UrlEncode( $input ) {
211
+ $str = strtr( base64_encode( $input ), '+/', '-_' );
212
+ $str = str_replace( '=', '', $str );
213
+
214
+ return $str;
215
+ }
216
+
217
+ }
lib/freemius/includes/sdk/LICENSE.txt ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ {description}
294
+ Copyright (C) {year} {fullname}
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ {signature of Ty Coon}, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
340
+
lib/freemius/start.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Freemius hooks collection:
15
+ * fs_after_license_loaded
16
+ */
17
+
18
+ if ( ! class_exists( 'Freemius' ) ) {
19
+
20
+ // Configuration should be loaded first.
21
+ require_once dirname( __FILE__ ) . '/config.php';
22
+
23
+ // Logger must be loaded before any other.
24
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-logger.php';
25
+
26
+ require_once WP_FS__DIR_INCLUDES . '/fs-core-functions.php';
27
+ // require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';
28
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';
29
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';
30
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';
31
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-key-value-storage.php';
32
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-license-manager.php';
33
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plan-manager.php';
34
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plugin-manager.php';
35
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-entity.php';
36
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-scope-entity.php';
37
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-user.php';
38
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-site.php';
39
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin.php';
40
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-info.php';
41
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-tag.php';
42
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-plan.php';
43
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-license.php';
44
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-subscription.php';
45
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-api.php';
46
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-plugin-updater.php';
47
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-security.php';
48
+ require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php';
49
+ require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';
50
+
51
+ /**
52
+ * Quick shortcut to get Freemius for specified plugin.
53
+ * Used by various templates.
54
+ *
55
+ * @param string $slug
56
+ *
57
+ * @return Freemius
58
+ */
59
+ function freemius( $slug ) {
60
+ return Freemius::instance( $slug );
61
+ }
62
+
63
+ /**
64
+ * @param string $slug
65
+ * @param number $plugin_id
66
+ * @param string $public_key
67
+ * @param bool $is_live Is live or test plugin.
68
+ * @param bool $is_premium Hints freemius if running the premium plugin or not.
69
+ *
70
+ * @return Freemius
71
+ */
72
+ function fs_init( $slug, $plugin_id, $public_key, $is_live = true, $is_premium = true ) {
73
+ $fs = Freemius::instance( $slug );
74
+ $fs->init( $plugin_id, $public_key, $is_live, $is_premium );
75
+
76
+ return $fs;
77
+ }
78
+
79
+ /**
80
+ * @param array [string]string $plugin
81
+ *
82
+ * @return Freemius
83
+ * @throws Freemius_Exception
84
+ */
85
+ function fs_dynamic_init( $plugin ) {
86
+ $fs = Freemius::instance( $plugin['slug'] );
87
+ $fs->dynamic_init( $plugin );
88
+
89
+ return $fs;
90
+ }
91
+
92
+ function fs_dump_log() {
93
+ FS_Logger::dump();
94
+ }
95
+ }
lib/freemius/templates/account.php ADDED
@@ -0,0 +1,442 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ $slug = $VARS['slug'];
10
+ /**
11
+ * @var Freemius $fs
12
+ */
13
+ $fs = freemius( $slug );
14
+
15
+ /**
16
+ * @var FS_Plugin_Tag $update
17
+ */
18
+ $update = $fs->get_update();
19
+
20
+ $is_paying = $fs->is_paying();
21
+ $user = $fs->get_user();
22
+ $site = $fs->get_site();
23
+ $name = $user->get_name();
24
+ $license = $fs->_get_license();
25
+ $subscription = $fs->_get_subscription();
26
+ $plan = $fs->get_plan();
27
+ $is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
28
+ ?>
29
+
30
+ <div class="wrap">
31
+ <h2 class="nav-tab-wrapper">
32
+ <a href="<?php $fs->get_account_url() ?>" class="nav-tab nav-tab-active"><?php _efs( 'account' ) ?></a>
33
+ <?php if ( $fs->_has_addons() ) : ?>
34
+ <a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>" class="nav-tab"><?php _efs( 'add-ons' ) ?></a>
35
+ <?php endif ?>
36
+ <?php if ( $fs->is_not_paying() && $fs->has_paid_plan() ) : ?>
37
+ <a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php _efs( 'upgrade' ) ?></a>
38
+ <?php if ( ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
39
+ <a href="<?php echo $fs->get_trial_url() ?>" class="nav-tab"><?php _efs( 'free-trial' ) ?></a>
40
+ <?php endif ?>
41
+ <?php endif ?>
42
+ </h2>
43
+
44
+ <div id="poststuff">
45
+ <div id="fs_account">
46
+ <div class="has-sidebar has-right-sidebar">
47
+ <div class="has-sidebar-content">
48
+ <div class="postbox">
49
+ <h3><?php _efs( 'account-details' ) ?></h3>
50
+
51
+ <div class="fs-header-actions">
52
+ <ul>
53
+ <li>
54
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
55
+ <input type="hidden" name="fs_action" value="delete_account">
56
+ <?php wp_nonce_field( 'delete_account' ) ?>
57
+ <a href="#" onclick="if (confirm('<?php
58
+ if ( $is_active_subscription ) {
59
+ echo esc_attr( sprintf( __fs( 'delete-account-x-confirm' ), $plan->title ) );
60
+ } else {
61
+ _efs( 'delete-account-confirm' );
62
+ }
63
+ ?>')) this.parentNode.submit(); return false;"><?php _efs( 'delete-account' ) ?></a>
64
+ </form>
65
+ </li>
66
+ <?php if ( $is_paying ) : ?>
67
+ <li>
68
+ &nbsp;•&nbsp;
69
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
70
+ <input type="hidden" name="fs_action" value="deactivate_license">
71
+ <?php wp_nonce_field( 'deactivate_license' ) ?>
72
+ <a href="#"
73
+ onclick="if (confirm('<?php _efs( 'deactivate-license-confirm' ) ?>')) this.parentNode.submit(); return false;"><?php _efs( 'deactivate-license' ) ?></a>
74
+ </form>
75
+ </li>
76
+ <?php if ( ! $license->is_lifetime() &&
77
+ $is_active_subscription
78
+ ) : ?>
79
+ <li>
80
+ &nbsp;•&nbsp;
81
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
82
+ <input type="hidden" name="fs_action" value="downgrade_account">
83
+ <?php wp_nonce_field( 'downgrade_account' ) ?>
84
+ <a href="#"
85
+ onclick="if (confirm('<?php printf( __fs( 'downgrade-x-confirm' ), $plan->title, human_time_diff( time(), strtotime( $license->expiration ) ) ) ?> <?php if ( ! $license->is_block_features ) {
86
+ printf( __fs( 'after-downgrade-non-blocking' ), $plan->title );
87
+ } else {
88
+ printf( __fs( 'after-downgrade-blocking' ), $plan->title );
89
+ }?> <?php _efs( 'proceed-confirmation' ) ?>')) this.parentNode.submit(); return false;"><?php _efs( 'downgrade' ) ?></a>
90
+ </form>
91
+ </li>
92
+ <?php endif ?>
93
+ <li>
94
+ &nbsp;•&nbsp;
95
+ <a href="<?php echo $fs->get_upgrade_url() ?>"><?php _efs( 'change-plan' ) ?></a>
96
+ </li>
97
+ <?php endif ?>
98
+ </ul>
99
+ </div>
100
+ <div class="inside">
101
+ <table id="fs_account_details" cellspacing="0" class="fs-key-value-table">
102
+ <?php
103
+ $profile = array();
104
+ $profile[] = array(
105
+ 'id' => 'user_name',
106
+ 'title' => __fs( 'name' ),
107
+ 'value' => $name
108
+ );
109
+ // if (isset($user->email) && false !== strpos($user->email, '@'))
110
+ $profile[] = array(
111
+ 'id' => 'email',
112
+ 'title' => __fs( 'email' ),
113
+ 'value' => $user->email
114
+ );
115
+ if ( is_numeric( $user->id ) ) {
116
+ $profile[] = array(
117
+ 'id' => 'user_id',
118
+ 'title' => __fs( 'user-id' ),
119
+ 'value' => $user->id
120
+ );
121
+ }
122
+
123
+ $profile[] = array(
124
+ 'id' => 'site_id',
125
+ 'title' => __fs( 'site-id' ),
126
+ 'value' => is_string( $site->id ) ?
127
+ $site->id :
128
+ __fs( 'no-id' )
129
+ );
130
+
131
+ $profile[] = array(
132
+ 'id' => 'site_public_key',
133
+ 'title' => __fs( 'public-key' ),
134
+ 'value' => $site->public_key
135
+ );
136
+
137
+ $profile[] = array(
138
+ 'id' => 'site_secret_key',
139
+ 'title' => __fs( 'secret-key' ),
140
+ 'value' => ( ( is_string( $site->secret_key ) ) ?
141
+ $site->secret_key :
142
+ __fs( 'no-secret' )
143
+ )
144
+ );
145
+
146
+ if ( $fs->is_trial() ) {
147
+ $trial_plan = $fs->get_trial_plan();
148
+
149
+ $profile[] = array(
150
+ 'id' => 'plan',
151
+ 'title' => __fs( 'plan' ),
152
+ 'value' => ( is_string( $trial_plan->name ) ?
153
+ strtoupper( $trial_plan->title ) . ' ' :
154
+ '' ) . strtoupper( __fs( 'trial' ) )
155
+ );
156
+ } else {
157
+ $profile[] = array(
158
+ 'id' => 'plan',
159
+ 'title' => __fs( 'plan' ),
160
+ 'value' => is_string( $site->plan->name ) ?
161
+ strtoupper( $site->plan->title ) :
162
+ strtoupper( __fs( 'free' ) )
163
+ );
164
+ }
165
+
166
+ $profile[] = array(
167
+ 'id' => 'version',
168
+ 'title' => __fs( 'version' ),
169
+ 'value' => $fs->get_plugin_version()
170
+ );
171
+ ?>
172
+ <?php $odd = true;
173
+ foreach ( $profile as $p ) : ?>
174
+ <?php
175
+ if ( 'plan' === $p['id'] && ! $fs->has_paid_plan() ) {
176
+ // If plugin don't have any paid plans, there's no reason
177
+ // to show current plan.
178
+ continue;
179
+ }
180
+ ?>
181
+ <tr class="fs-field-<?php echo $p['id'] ?><?php if ( $odd ) : ?> alternate<?php endif ?>">
182
+ <td>
183
+ <nobr><?php echo $p['title'] ?>:</nobr>
184
+ </td>
185
+ <td>
186
+ <code><?php echo htmlspecialchars( $p['value'] ) ?></code>
187
+ <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
188
+ <label><?php _efs( 'not-verified' ) ?></label>
189
+ <?php endif ?>
190
+ <?php if ( 'plan' === $p['id'] ) : ?>
191
+ <?php if ( $fs->is_trial() ) : ?>
192
+ <label><?php printf( __fs( 'expires-in' ), human_time_diff( time(), strtotime( $site->trial_ends ) ) ) ?></label>
193
+ <?php elseif ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
194
+ <?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
195
+ <label><?php printf( __fs( 'expires-in' ), human_time_diff( time(), strtotime( $license->expiration ) ) ) ?></label>
196
+ <?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
197
+ <label><?php printf( __fs( 'renews-in' ), human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ?></label>
198
+ <?php endif ?>
199
+ <?php endif ?>
200
+ <?php endif ?>
201
+
202
+ </td>
203
+ <td class="fs-right">
204
+ <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
205
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
206
+ <input type="hidden" name="fs_action" value="verify_email">
207
+ <?php wp_nonce_field( 'verify_email' ) ?>
208
+ <input type="submit" class="button button-small"
209
+ value="<?php _efs( 'verify-email' ) ?>">
210
+ </form>
211
+ <?php endif ?>
212
+ <?php if ( 'plan' === $p['id'] ) : ?>
213
+ <div class="button-group">
214
+ <?php $license = $fs->is_not_paying() ? $fs->_get_available_premium_license() : false ?>
215
+ <?php if ( false !== $license && ( $license->left() > 0 || ( $site->is_localhost() && $license->is_free_localhost ) ) ) : ?>
216
+ <?php $premium_plan = $fs->_get_plan_by_id( $license->plan_id ) ?>
217
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
218
+ method="POST">
219
+ <input type="hidden" name="fs_action" value="activate_license">
220
+ <?php wp_nonce_field( 'activate_license' ) ?>
221
+ <input type="submit" class="button button-primary"
222
+ value="<?php printf(
223
+ __fs( 'activate-x-plan' ),
224
+ $premium_plan->title,
225
+ ( $site->is_localhost() && $license->is_free_localhost ) ?
226
+ '[' . __fs( 'localhost' ) . ']' :
227
+ ( 1 < $license->left() ? $license->left() . ' left' : '' )
228
+ ) ?> ">
229
+ </form>
230
+ <?php else : ?>
231
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
232
+ method="POST" class="button-group">
233
+ <input type="submit" class="button"
234
+ value="<?php _efs( 'sync-license' ) ?>">
235
+ <input type="hidden" name="fs_action"
236
+ value="<?php echo $slug ?>_sync_license">
237
+ <?php wp_nonce_field( $slug . '_sync_license' ) ?>
238
+ <a href="<?php echo $fs->get_upgrade_url() ?>"
239
+ class="button<?php if ( ! $is_paying ) {
240
+ echo ' button-primary';
241
+ } ?> button-upgrade"><?php ( ! $is_paying ) ?
242
+ _efs( 'upgrade' ) :
243
+ _efs( 'change-plan' )
244
+ ?></a>
245
+ </form>
246
+ <?php endif ?>
247
+ </div>
248
+ <?php elseif ( 'version' === $p['id'] ) : ?>
249
+ <div class="button-group">
250
+ <?php if ( $is_paying || $fs->is_trial() ) : ?>
251
+ <?php if ( ! $fs->is_allowed_to_install() ) : ?>
252
+ <a target="_blank" class="button button-primary"
253
+ href="<?php echo $fs->_get_latest_download_local_url() ?>"><?php echo sprintf( __fs( 'download-x-version' ), $site->plan->title ) . ( is_object( $update ) ? ' [' . $update->version . ']' : '' ) ?></a>
254
+ <?php elseif ( is_object( $update ) ) : ?>
255
+ <a class="button button-primary"
256
+ href="<?php echo wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . $fs->get_plugin_basename() ), 'upgrade-plugin_' . $fs->get_plugin_basename() ) ?>"><?php echo __fs( 'install-update-now' ) . ' [' . $update->version . ']' ?></a>
257
+ <?php endif ?>
258
+ <?php endif; ?>
259
+ </div>
260
+ <?php
261
+ elseif (/*in_array($p['id'], array('site_secret_key', 'site_id', 'site_public_key')) ||*/
262
+ ( is_string( $user->secret_key ) && in_array( $p['id'], array(
263
+ 'email',
264
+ 'user_name'
265
+ ) ) )
266
+ ) : ?>
267
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"
268
+ onsubmit="var val = prompt('<?php printf( __fs( 'what-is-your-x' ), $p['title'] ) ?>', '<?php echo $p['value'] ?>'); if (null == val || '' === val) return false; jQuery('input[name=fs_<?php echo $p['id'] ?>_<?php echo $slug ?>]').val(val); return true;">
269
+ <input type="hidden" name="fs_action" value="update_<?php echo $p['id'] ?>">
270
+ <input type="hidden" name="fs_<?php echo $p['id'] ?>_<?php echo $slug ?>"
271
+ value="">
272
+ <?php wp_nonce_field( 'update_' . $p['id'] ) ?>
273
+ <input type="submit" class="button button-small"
274
+ value="<?php _ex( 'Edit', 'verb', 'freemius' ) ?>">
275
+ </form>
276
+ <?php endif ?>
277
+ </td>
278
+ </tr>
279
+ <?php $odd = ! $odd; endforeach ?>
280
+ </table>
281
+ </div>
282
+ </div>
283
+ <?php
284
+ $account_addons = $fs->get_account_addons();
285
+ if ( ! is_array( $account_addons ) ) {
286
+ $account_addons = array();
287
+ }
288
+
289
+ $installed_addons = $fs->get_installed_addons();
290
+ $installed_addons_ids = array();
291
+ foreach ( $installed_addons as $fs_addon ) {
292
+ $installed_addons_ids[] = $fs_addon->get_id();
293
+ }
294
+
295
+ $addons_to_show = array_unique( array_merge( $installed_addons_ids, $account_addons ) );
296
+ ?>
297
+ <?php if ( 0 < count( $addons_to_show ) ) : ?>
298
+ <div class="postbox">
299
+ <table id="fs_addons" class="widefat">
300
+ <thead>
301
+ <tr>
302
+ <th></th>
303
+ <th><?php _efs( 'version' ) ?></th>
304
+ <th><?php _efs( 'plan' ) ?></th>
305
+ <th><?php _efs( 'expiration' ) ?></th>
306
+ <th></th>
307
+ <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
308
+ <th></th>
309
+ <?php endif ?>
310
+ </tr>
311
+ </thead>
312
+ <tbody>
313
+ <?php foreach ( $addons_to_show as $addon_id ) : ?>
314
+ <?php
315
+ $addon = $fs->get_addon( $addon_id );
316
+ $is_addon_activated = $fs->is_addon_activated( $addon->slug );
317
+
318
+ $fs_addon = $is_addon_activated ? freemius( $addon->slug ) : false;
319
+ ?>
320
+ <tr>
321
+ <td>
322
+ <?php echo $addon->title ?>
323
+ </td>
324
+ <?php if ( $is_addon_activated ) : ?>
325
+ <?php // Add-on Installed ?>
326
+ <?php $addon_site = $fs_addon->get_site(); ?>
327
+ <td><?php echo $fs_addon->get_plugin_version() ?></td>
328
+ <td><?php echo is_string( $addon_site->plan->name ) ? strtoupper( $addon_site->plan->title ) : 'FREE' ?></td>
329
+ <?php
330
+ $current_license = $fs_addon->_get_license();
331
+ $is_current_license_expired = is_object( $current_license ) && $current_license->is_expired();
332
+ ?>
333
+ <?php if ( $fs_addon->is_not_paying() ) : ?>
334
+ <?php if ( $is_current_license_expired ) : ?>
335
+ <td><?php _efs( 'expired' ) ?></td>
336
+ <?php endif ?>
337
+ <?php $premium_license = $fs_addon->_get_available_premium_license() ?>
338
+ <td<?php if ( ! $is_current_license_expired ) {
339
+ echo ' colspan="2"';
340
+ } ?>>
341
+ <?php if ( is_object( $premium_license ) && ! $premium_license->is_utilized() ) : ?>
342
+ <?php $site = $fs_addon->get_site() ?>
343
+ <?php fs_ui_action_button(
344
+ $slug, 'account',
345
+ 'activate_license',
346
+ sprintf( __fs( 'activate-x-plan' ), $fs_addon->get_plan_title(), ( $site->is_localhost() && $premium_license->is_free_localhost ) ? '[localhost]' : ( 1 < $premium_license->left() ? $premium_license->left() . ' left' : '' ) ),
347
+ array( 'plugin_id' => $addon_id )
348
+ ) ?>
349
+ <?php else : ?>
350
+ <div class="button-group">
351
+ <?php fs_ui_action_button(
352
+ $slug, 'account',
353
+ $slug . '_sync_license',
354
+ __fs( 'sync-license' ),
355
+ array( 'plugin_id' => $addon_id ),
356
+ false
357
+ ) ?>
358
+ <?php echo sprintf( '<a href="%s" class="thickbox button button-primary" aria-label="%s" data-title="%s">%s</a>',
359
+ esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
360
+ '&TB_iframe=true&width=600&height=550' ) ),
361
+ esc_attr( sprintf( __fs( 'more-information-about-x' ), $addon->title ) ),
362
+ esc_attr( $addon->title ),
363
+ __fs( 'upgrade' )
364
+ ) ?>
365
+ </div>
366
+ <?php endif ?>
367
+ </td>
368
+ <?php else : ?>
369
+ <?php if ( is_object( $current_license ) ) : ?>
370
+ <td><?php
371
+ if ( $current_license->is_lifetime() ) {
372
+ _efs( 'no-expiration' );
373
+ } else if ( $current_license->is_expired() ) {
374
+ _efs( 'expired' );
375
+ } else {
376
+ echo sprintf(
377
+ __fs( 'in-x' ),
378
+ human_time_diff( time(), strtotime( $current_license->expiration ) )
379
+ );
380
+ }
381
+ ?></td>
382
+ <td>
383
+ <?php fs_ui_action_button(
384
+ $slug, 'account',
385
+ 'deactivate_license',
386
+ __fs( 'deactivate-license' ),
387
+ array( 'plugin_id' => $addon_id ),
388
+ false
389
+ ) ?>
390
+ </td>
391
+ <?php endif ?>
392
+ <?php endif ?>
393
+ <?php else : ?>
394
+ <?php // Add-on NOT Installed
395
+ ?>
396
+ <td colspan="4">
397
+ <?php if ( $fs->is_addon_installed( $addon->slug ) ) : ?>
398
+ <?php $addon_file = $fs->get_addon_basename( $addon->slug ) ?>
399
+ <a class="button button-primary"
400
+ href="<?php echo wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $addon_file, 'activate-plugin_' . $addon_file ) ?>"
401
+ title="<?php esc_attr( __fs( 'activate-this-addon' ) ) ?>"
402
+ class="edit"><?php _efs( 'activate' ) ?></a>
403
+ <?php else : ?>
404
+ <?php if ( $fs->is_allowed_to_install() ) : ?>
405
+ <a class="button button-primary"
406
+ href="<?php echo wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ) ?>"><?php _efs( 'install-now' ) ?></a>
407
+ <?php else : ?>
408
+ <a target="_blank" class="button button-primary"
409
+ href="<?php echo $fs->_get_latest_download_local_url( $addon_id ) ?>"><?php _efs( 'download-latest' ) ?></a>
410
+ <?php endif ?>
411
+ <?php endif ?>
412
+ </td>
413
+ <?php endif ?>
414
+ <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
415
+ <td>
416
+ <?php
417
+ if ( $is_addon_activated ) {
418
+ fs_ui_action_button(
419
+ $slug, 'account',
420
+ 'delete_account',
421
+ __fs( 'delete' ),
422
+ array( 'plugin_id' => $addon_id ),
423
+ false
424
+ );
425
+ }
426
+ ?>
427
+ </td>
428
+ <?php endif ?>
429
+ </tr>
430
+ <?php endforeach ?>
431
+ </tbody>
432
+ </table>
433
+ </div>
434
+ <?php endif ?>
435
+
436
+ <?php $fs->do_action( 'after_account_details' ) ?>
437
+ </div>
438
+ </div>
439
+ </div>
440
+ </div>
441
+ </div>
442
+ <?php fs_require_template( 'powered-by.php' ) ?>
lib/freemius/templates/add-ons.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ $slug = $VARS['slug'];
10
+ /**
11
+ * @var Freemius
12
+ */
13
+ $fs = freemius( $slug );
14
+
15
+ $open_addon_slug = fs_request_get( 'slug' );
16
+
17
+ $open_addon = false;
18
+
19
+ /**
20
+ * @var FS_Plugin[]
21
+ */
22
+ $addons = $fs->get_addons();
23
+ ?>
24
+ <div id="fs_addons" class="wrap">
25
+ <h2><?php printf( __fs( 'add-ons-for-x' ), $fs->get_plugin_name() ) ?></h2>
26
+
27
+ <div id="poststuff">
28
+ <ul class="fs-cards-list">
29
+ <?php foreach ( $addons as $addon ) : ?>
30
+ <?php
31
+ $open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
32
+
33
+ $price = 0;
34
+ $plans_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans.json" );
35
+ if ( ! isset( $plans_result->error ) ) {
36
+ $plans = $plans_result->plans;
37
+ if ( is_array( $plans ) && 0 < count( $plans ) ) {
38
+ $plan = $plans[0];
39
+ $pricing_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans/{$plan->id}/pricing.json" );
40
+ if ( ! isset( $pricing_result->error ) ) {
41
+ // Update plan's pricing.
42
+ $plan->pricing = $pricing_result->pricing;
43
+
44
+ if ( is_array( $plan->pricing ) && 0 < count( $plan->pricing ) ) {
45
+ $min_price = 999999;
46
+ foreach ( $plan->pricing as $pricing ) {
47
+ if ( ! is_null( $pricing->annual_price ) && $pricing->annual_price > 0 ) {
48
+ $min_price = min( $min_price, $pricing->annual_price );
49
+ } else if ( ! is_null( $pricing->monthly_price ) && $pricing->monthly_price > 0 ) {
50
+ $min_price = min( $min_price, 12 * $pricing->monthly_price );
51
+ }
52
+ }
53
+
54
+ if ( $min_price < 999999 ) {
55
+ $price = $min_price;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ?>
62
+ <li class="fs-card" data-slug="<?php echo $addon->slug ?>">
63
+ <?php
64
+ echo sprintf( '<a href="%s" class="thickbox fs-overlay" aria-label="%s" data-title="%s"></a>',
65
+ esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
66
+ '&TB_iframe=true&width=600&height=550' ) ),
67
+ esc_attr( sprintf( __fs( 'more-information-about-x' ), $addon->title ) ),
68
+ esc_attr( $addon->title )
69
+ );
70
+ ?>
71
+ <?php
72
+ if ( is_null( $addon->info ) ) {
73
+ $addon->info = new stdClass();
74
+ }
75
+ if ( ! isset( $addon->info->card_banner_url ) ) {
76
+ $addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
77
+ }
78
+ if ( ! isset( $addon->info->short_description ) ) {
79
+ $addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
80
+ }
81
+ ?>
82
+ <div class="fs-inner">
83
+ <ul>
84
+ <li class="fs-card-banner"
85
+ style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"></li>
86
+ <li class="fs-title"><?php echo $addon->title ?></li>
87
+ <li class="fs-offer">
88
+ <span
89
+ class="fs-price"><?php echo ( 0 == $price ) ? __fs( 'free' ) : '$' . number_format( $price, 2 ) ?></span>
90
+ </li>
91
+ <li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
92
+ </ul>
93
+ </div>
94
+ </li>
95
+ <?php endforeach ?>
96
+ </ul>
97
+ </div>
98
+ </div>
99
+ <?php if ( $open_addon ) : ?>
100
+ <script type="text/javascript">
101
+ (function ($) {
102
+ var interval = setInterval(function () {
103
+ // Open add-on information page.
104
+ $('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
105
+ if ($('#TB_iframeContent').length > 0) {
106
+ clearInterval(interval);
107
+ interval = null;
108
+ }
109
+ }, 200);
110
+ })(jQuery);
111
+ </script>
112
+ <?php endif ?>
113
+ <?php fs_require_template( 'powered-by.php' ) ?>
lib/freemius/templates/admin-notice.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+ ?>
9
+ <div data-id="<?php echo $VARS['id'] ?>" data-slug="<?php echo $VARS['slug'] ?>" class="<?php
10
+ switch ( $VARS['type'] ) {
11
+ case 'error':
12
+ echo 'error form-invalid';
13
+ break;
14
+ case 'promotion':
15
+ echo 'updated promotion';
16
+ break;
17
+ case 'update':
18
+ // echo 'update-nag update';
19
+ // break;
20
+ case 'success':
21
+ default:
22
+ echo 'updated success';
23
+ break;
24
+ }
25
+ ?> fs-notice<?php if ( $VARS['sticky'] ) {
26
+ echo ' fs-sticky';
27
+ } ?><?php if ( ! empty( $VARS['plugin'] ) ) {
28
+ echo ' fs-has-title';
29
+ } ?>"><?php if ( ! empty( $VARS['plugin'] ) ) : ?><label
30
+ class="fs-plugin-title"><?php echo $VARS['plugin'] ?></label><?php endif ?><p>
31
+ <?php if ( ! empty( $VARS['title'] ) ) : ?><b><?php echo $VARS['title'] ?></b> <?php endif ?>
32
+ <?php echo $VARS['message'] ?>
33
+ </p><?php if ( $VARS['sticky'] ) : ?><i class="fs-close dashicons dashicons-no"
34
+ title="<?php _efs( 'dismiss' ) ?>"></i><?php endif ?></div>
lib/freemius/templates/all-admin-notice.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+ ?>
9
+ <div class="<?php
10
+ switch ($VARS['type']) {
11
+ case 'error':
12
+ echo 'error form-invalid';
13
+ break;
14
+ case 'update-nag':
15
+ echo 'update-nag ';
16
+ break;
17
+ case 'update':
18
+ case 'success':
19
+ default:
20
+ echo 'updated success';
21
+ break;
22
+ }
23
+ ?> fs-notice">
24
+ <?php if ('update-nag' !== $VARS['type']) : ?><p><?php endif ?>
25
+ <?php if (!empty($VARS['title'])) : ?>
26
+ <b><?php echo $VARS['title'] ?></b>
27
+ <?php endif ?>
28
+ <?php echo $VARS['message'] ?>
29
+ <?php if ('update-nag' !== $VARS['type']) : ?></p><?php endif ?>
30
+ <?php if ($VARS['sticky']) : ?><i class="dashicons dashicons-no"></i><?php endif ?>
31
+ </div>
lib/freemius/templates/checkout.php ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ wp_enqueue_script( 'jquery' );
10
+ wp_enqueue_script( 'json2' );
11
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
12
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
13
+ fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
14
+
15
+ $slug = $VARS['slug'];
16
+ $fs = freemius( $slug );
17
+
18
+ $timestamp = time();
19
+
20
+ $context_params = array(
21
+ 'plugin_id' => $fs->get_id(),
22
+ 'plugin_public_key' => $fs->get_public_key(),
23
+ 'plugin_version' => $fs->get_plugin_version(),
24
+ );
25
+
26
+ // Get site context secure params.
27
+ if ( $fs->is_registered() ) {
28
+ $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
29
+ $fs->get_site(),
30
+ $timestamp,
31
+ 'checkout'
32
+ ) );
33
+ } else {
34
+ $current_user = wp_get_current_user();
35
+
36
+ // Add site and user info to the request, this information
37
+ // is NOT being stored unless the user complete the purchase
38
+ // and agrees to the TOS.
39
+ $context_params = array_merge( $context_params, array(
40
+ 'user_firstname' => $current_user->user_firstname,
41
+ 'user_lastname' => $current_user->user_lastname,
42
+ 'user_email' => $current_user->user_email,
43
+ // 'user_nickname' => $current_user->user_nicename,
44
+ // 'plugin_slug' => $slug,
45
+ // 'site_url' => get_site_url(),
46
+ // 'site_name' => get_bloginfo( 'name' ),
47
+ // 'platform_version' => get_bloginfo( 'version' ),
48
+ // 'language' => get_bloginfo( 'language' ),
49
+ // 'charset' => get_bloginfo( 'charset' ),
50
+ // 'account_url' => fs_nonce_url( $fs->_get_admin_page_url(
51
+ // 'account',
52
+ // array( 'fs_action' => 'sync_user' )
53
+ // ), 'sync_user' ),
54
+ ) );
55
+
56
+ $fs_user = Freemius::_get_user_by_email( $current_user->user_email );
57
+
58
+ if ( is_object( $fs_user ) ) {
59
+ $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
60
+ $fs_user,
61
+ $timestamp,
62
+ 'checkout'
63
+ ) );
64
+ }
65
+ }
66
+
67
+ if ( $fs->is_payments_sandbox() ) // Append plugin secure token for sandbox mode authentication.)
68
+ {
69
+ $context_params['sandbox'] = FS_Security::instance()->get_secure_token(
70
+ $fs->get_plugin(),
71
+ $timestamp,
72
+ 'checkout'
73
+ );
74
+ }
75
+
76
+ $return_url = fs_nonce_url( $fs->_get_admin_page_url(
77
+ 'account',
78
+ array(
79
+ 'fs_action' => $slug . '_sync_license',
80
+ 'plugin_id' => isset( $_GET['plugin_id'] ) ? $_GET['plugin_id'] : $fs->get_id()
81
+ )
82
+ ), $slug . '_sync_license' );
83
+
84
+ $query_params = array_merge( $context_params, $_GET, array(
85
+ // Current plugin version.
86
+ 'plugin_version' => $fs->get_plugin_version(),
87
+ 'return_url' => $return_url,
88
+ // Admin CSS URL for style/design competability.
89
+ // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
90
+ ) );
91
+ ?>
92
+ <div class="fs-secure-notice">
93
+ <i class="dashicons dashicons-lock"></i>
94
+ <span><b>Secure HTTPS Checkout</b> - PCI compliant, running via iframe from external domain</span>
95
+ </div>
96
+ <div id="fs_contact" class="wrap" style="margin: 40px 0 -65px -20px;">
97
+ <div id="iframe"></div>
98
+ <script type="text/javascript">
99
+ // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax
100
+ jQuery(function ($) {
101
+ $.extend({
102
+ form: function (url, data, method) {
103
+ if (method == null) method = 'POST';
104
+ if (data == null) data = {};
105
+
106
+ var form = $('<form>').attr({
107
+ method: method,
108
+ action: url
109
+ }).css({
110
+ display: 'none'
111
+ });
112
+
113
+ var addData = function (name, data) {
114
+ if ($.isArray(data)) {
115
+ for (var i = 0; i < data.length; i++) {
116
+ var value = data[i];
117
+ addData(name + '[]', value);
118
+ }
119
+ } else if (typeof data === 'object') {
120
+ for (var key in data) {
121
+ if (data.hasOwnProperty(key)) {
122
+ addData(name + '[' + key + ']', data[key]);
123
+ }
124
+ }
125
+ } else if (data != null) {
126
+ form.append($('<input>').attr({
127
+ type : 'hidden',
128
+ name : String(name),
129
+ value: String(data)
130
+ }));
131
+ }
132
+ };
133
+
134
+ for (var key in data) {
135
+ if (data.hasOwnProperty(key)) {
136
+ addData(key, data[key]);
137
+ }
138
+ }
139
+
140
+ return form.appendTo('body');
141
+ }
142
+ });
143
+ });
144
+
145
+ (function ($) {
146
+ $(function () {
147
+
148
+ var
149
+ // Keep track of the iframe height.
150
+ iframe_height = 800,
151
+ base_url = '<?php echo WP_FS__ADDRESS ?>',
152
+ // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
153
+ // passed via query string or hard coded into the child page, it depends on your needs).
154
+ src = base_url + '/checkout/?<?php echo (isset($_REQUEST['XDEBUG_SESSION']) ? 'XDEBUG_SESSION=' . $_REQUEST['XDEBUG_SESSION'] . '&' : '') . http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),
155
+
156
+ // Append the Iframe into the DOM.
157
+ iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
158
+ .appendTo('#iframe');
159
+
160
+ FS.PostMessage.init(base_url);
161
+ FS.PostMessage.receiveOnce('height', function (data) {
162
+ var h = data.height;
163
+ if (!isNaN(h) && h > 0 && h != iframe_height) {
164
+ iframe_height = h;
165
+ $("#iframe iframe").height(iframe_height + 'px');
166
+ }
167
+ });
168
+
169
+ FS.PostMessage.receiveOnce('install', function (data) {
170
+ // Post data to activation URL.
171
+ $.form('<?php echo fs_nonce_url($fs->_get_admin_page_url('account', array(
172
+ 'fs_action' => $slug . '_activate_new',
173
+ 'plugin_id' => isset($_GET['plugin_id']) ? $_GET['plugin_id'] : $fs->get_id()
174
+ )), $slug . '_activate_new') ?>', {
175
+ user_id : data.user.id,
176
+ user_secret_key : data.user.secret_key,
177
+ user_public_key : data.user.public_key,
178
+ install_id : data.install.id,
179
+ install_secret_key: data.install.secret_key,
180
+ install_public_key: data.install.public_key
181
+ }).submit();
182
+ });
183
+
184
+ FS.PostMessage.receiveOnce('pending_activation', function (data) {
185
+ $.form('<?php echo fs_nonce_url($fs->_get_admin_page_url('account', array(
186
+ 'fs_action' => $slug . '_activate_new',
187
+ 'plugin_id' => fs_request_get('plugin_id', $fs->get_id()),
188
+ 'pending_activation' => true,
189
+ )), $slug . '_activate_new') ?>', {
190
+ user_email: data.user_email
191
+ }).submit();
192
+ });
193
+
194
+ FS.PostMessage.receiveOnce('get_context', function () {
195
+ console.debug('receiveOnce', 'get_context');
196
+
197
+ // If the user didn't connect his account with Freemius,
198
+ // once he accepts the Terms of Service and Privacy Policy,
199
+ // and then click the purchase button, the context information
200
+ // of the user will be shared with Freemius in order to complete the
201
+ // purchase workflow and activate the license for the right user.
202
+ <?php $current_user = wp_get_current_user() ?>
203
+ FS.PostMessage.post('context', {
204
+ // user_firstname: '<?php //echo $current_user->user_firstname ?>//',
205
+ // user_lastname: '<?php //echo $current_user->user_lastname ?>//',
206
+ // user_email: '<?php //echo $current_user->user_email ?>//'
207
+ plugin_id : '<?php echo $fs->get_id() ?>',
208
+ plugin_public_key: '<?php echo $fs->get_public_key() ?>',
209
+ plugin_version : '<?php echo $fs->get_plugin_version() ?>',
210
+ plugin_slug : '<?php echo $slug ?>',
211
+ site_name : '<?php echo get_bloginfo('name') ?>',
212
+ platform_version : '<?php echo get_bloginfo('version') ?>',
213
+ language : '<?php echo get_bloginfo('language') ?>',
214
+ charset : '<?php echo get_bloginfo('charset') ?>',
215
+ return_url : '<?php echo $return_url ?>',
216
+ account_url : '<?php echo fs_nonce_url($fs->_get_admin_page_url(
217
+ 'account',
218
+ array('fs_action' => 'sync_user')
219
+ ), 'sync_user') ?>',
220
+ activation_url : '<?php echo fs_nonce_url($fs->_get_admin_page_url('',
221
+ array(
222
+ 'fs_action' => $slug . '_activate_new',
223
+ 'plugin_id' => fs_request_get('plugin_id', $fs->get_id()),
224
+
225
+ )),
226
+ $slug . '_activate_new') ?>'
227
+ }, iframe[0]);
228
+ });
229
+
230
+ FS.PostMessage.receiveOnce('get_dimensions', function (data) {
231
+ console.debug('receiveOnce', 'get_dimensions');
232
+
233
+ FS.PostMessage.post('dimensions', {
234
+ height : $(document.body).height(),
235
+ scrollTop: $(document).scrollTop()
236
+ }, iframe[0]);
237
+ });
238
+ });
239
+ })(jQuery);
240
+ </script>
241
+ </div>
242
+ <?php fs_require_template( 'powered-by.php' ) ?>
lib/freemius/templates/connect.php ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.7
7
+ */
8
+
9
+ $slug = $VARS['slug'];
10
+ $fs = freemius( $slug );
11
+
12
+ $fs->_enqueue_connect_essentials();
13
+
14
+ $current_user = wp_get_current_user();
15
+
16
+ $first_name = $current_user->user_firstname;
17
+ if ( empty( $first_name ) ) {
18
+ $first_name = $current_user->nickname;
19
+ }
20
+
21
+ $site_url = get_site_url();
22
+ $protocol_pos = strpos( $site_url, '://' );
23
+ if ( false !== $protocol_pos ) {
24
+ $site_url = substr( $site_url, $protocol_pos + 3 );
25
+ }
26
+
27
+ $freemius_site_url = $fs->has_paid_plan() ?
28
+ 'https://freemius.com/wordpress/' :
29
+ // Insights platform information.
30
+ 'https://freemius.com/wordpress/insights/';
31
+ ?>
32
+ <div id="fs_connect" class="wrap<?php if ( ! $fs->enable_anonymous() ) {
33
+ echo ' fs-anonymous-disabled';
34
+ } ?>">
35
+ <div class="fs-visual">
36
+ <b class="fs-site-icon"><i class="dashicons dashicons-wordpress"></i></b>
37
+ <i class="dashicons dashicons-plus fs-first"></i>
38
+ <?php
39
+ $vars = array( 'slug' => $slug );
40
+ fs_require_once_template( 'plugin-icon.php', $vars );
41
+ ?>
42
+ <i class="dashicons dashicons-plus fs-second"></i>
43
+ <img class="fs-connect-logo" width="80" height="80" src="//img.freemius.com/connect-logo.png"/>
44
+ </div>
45
+ <div class="fs-content">
46
+ <p><?php
47
+ echo $fs->apply_filters( 'connect_message', sprintf(
48
+ __fs( 'hey-x' ) . '<br>' .
49
+ __fs( 'connect-message' ),
50
+ $first_name,
51
+ '<b>' . $fs->get_plugin_name() . '</b>',
52
+ '<b>' . $current_user->user_login . '</b>',
53
+ '<a href="' . $site_url . '" target="_blank">' . $site_url . '</a>',
54
+ '<a href="' . $freemius_site_url . '" target="_blank">freemius.com</a>'
55
+ ) );
56
+ ?></p>
57
+ </div>
58
+ <div class="fs-actions">
59
+ <?php if ( $fs->enable_anonymous() ) : ?>
60
+ <a href="<?php echo wp_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $slug . '_skip_activation' ) ), $slug . '_skip_activation' ) ?>"
61
+ class="button button-secondary" tabindex="2"><?php _efs( 'skip' ) ?></a>
62
+ <?php endif ?>
63
+ <?php $fs_user = Freemius::_get_user_by_email( $current_user->user_email ) ?>
64
+ <?php if ( is_object( $fs_user ) ) : ?>
65
+ <form action="" method="POST">
66
+ <input type="hidden" name="fs_action" value="<?php echo $slug ?>_activate_existing">
67
+ <?php wp_nonce_field( 'activate_existing_' . $fs->get_public_key() ) ?>
68
+ <button class="button button-primary" tabindex="1"
69
+ type="submit"><?php _efs( 'opt-in-connect' ) ?></button>
70
+ </form>
71
+ <?php else : ?>
72
+ <form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
73
+ <?php
74
+ $params = array(
75
+ 'user_firstname' => $current_user->user_firstname,
76
+ 'user_lastname' => $current_user->user_lastname,
77
+ 'user_nickname' => $current_user->user_nicename,
78
+ 'user_email' => $current_user->user_email,
79
+ 'user_ip' => fs_get_ip(),
80
+ 'plugin_slug' => $slug,
81
+ 'plugin_id' => $fs->get_id(),
82
+ 'plugin_public_key' => $fs->get_public_key(),
83
+ 'plugin_version' => $fs->get_plugin_version(),
84
+ 'return_url' => wp_nonce_url( $fs->_get_admin_page_url(
85
+ '',
86
+ array( 'fs_action' => $slug . '_activate_new' )
87
+ ), $slug . '_activate_new' ),
88
+ 'account_url' => wp_nonce_url( $fs->_get_admin_page_url(
89
+ 'account',
90
+ array( 'fs_action' => 'sync_user' )
91
+ ), 'sync_user' ),
92
+ 'site_uid' => $fs->get_anonymous_id(),
93
+ 'site_url' => get_site_url(),
94
+ 'site_name' => get_bloginfo( 'name' ),
95
+ 'platform_version' => get_bloginfo( 'version' ),
96
+ 'php_version' => phpversion(),
97
+ 'language' => get_bloginfo( 'language' ),
98
+ 'charset' => get_bloginfo( 'charset' ),
99
+ );
100
+
101
+ if ( WP_FS__SKIP_EMAIL_ACTIVATION && $fs->has_secret_key() ) {
102
+ // Even though rand() is known for its security issues,
103
+ // the timestamp adds another layer of protection.
104
+ // It would be very hard for an attacker to get the secret key form here.
105
+ // Plus, this should never run in production since the secret should never
106
+ // be included in the production version.
107
+ $params['ts'] = WP_FS__SCRIPT_START_TIME;
108
+ $params['salt'] = md5( uniqid( rand() ) );
109
+ $params['secure'] = md5(
110
+ $params['ts'] .
111
+ $params['salt'] .
112
+ $fs->get_secret_key()
113
+ );
114
+ }
115
+ ?>
116
+ <?php foreach ( $params as $name => $value ) : ?>
117
+ <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
118
+ <?php endforeach ?>
119
+ <button class="button button-primary" tabindex="1"
120
+ type="submit"><?php _efs( 'opt-in-connect' ) ?></button>
121
+ </form>
122
+ <?php endif ?>
123
+ </div>
124
+ <div class="fs-permissions">
125
+ <a class="fs-trigger" href="#"><?php _efs( 'what-permissions' ) ?></a>
126
+ <ul>
127
+ <li>
128
+ <i class="dashicons dashicons-admin-users"></i>
129
+
130
+ <div>
131
+ <span><?php _efs( 'permissions-profile' ) ?></span>
132
+
133
+ <p><?php _efs( 'permissions-profile_desc' ) ?></p>
134
+ </div>
135
+ </li>
136
+ <li>
137
+ <i class="dashicons dashicons-wordpress"></i>
138
+
139
+ <div>
140
+ <span><?php _efs( 'permissions-site' ) ?></span>
141
+
142
+ <p><?php _efs( 'permissions-site_desc' ) ?></p>
143
+ </div>
144
+ </li>
145
+ <li>
146
+ <i class="dashicons dashicons-admin-plugins"></i>
147
+
148
+ <div>
149
+ <span><?php _efs( 'permissions-events' ) ?></span>
150
+
151
+ <p><?php _efs( 'permissions-events_desc' ) ?></p>
152
+ </div>
153
+ </li>
154
+ </ul>
155
+ </div>
156
+ <div class="fs-terms">
157
+ <a href="https://freemius.com/privacy/" target="_blank"><?php _efs( 'privacy-policy' ) ?></a>
158
+ &nbsp;&nbsp;-&nbsp;&nbsp;
159
+ <a href="https://freemius.com/terms/" target="_blank"><?php _efs( 'tos' ) ?></a>
160
+ </div>
161
+ </div>
162
+ <script type="text/javascript">
163
+ (function ($) {
164
+ $('.button').on('click', function () {
165
+ // Set loading mode.
166
+ $(document.body).css({'cursor': 'wait'});
167
+ });
168
+ $('.button.button-primary').on('click', function () {
169
+ $(this).html('<?php _efs( 'activating' ) ?>...').css({'cursor': 'wait'});
170
+ });
171
+ $('.fs-permissions .fs-trigger').on('click', function () {
172
+ $('.fs-permissions').toggleClass('fs-open');
173
+ });
174
+ })(jQuery);
175
+ </script>
lib/freemius/templates/contact.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ wp_enqueue_script( 'jquery' );
10
+ wp_enqueue_script( 'json2' );
11
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
12
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
13
+ fs_enqueue_local_style( 'fs_checkout', '/admin/common.css' );
14
+
15
+ $slug = $VARS['slug'];
16
+ $fs = freemius( $slug );
17
+
18
+ $context_params = array(
19
+ 'plugin_id' => $fs->get_id(),
20
+ 'plugin_public_key' => $fs->get_public_key(),
21
+ 'plugin_version' => $fs->get_plugin_version(),
22
+ );
23
+
24
+
25
+ // Get site context secure params.
26
+ if ( $fs->is_registered() ) {
27
+ $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
28
+ $fs->get_site(),
29
+ time(),
30
+ 'contact'
31
+ ) );
32
+ }
33
+
34
+ $query_params = array_merge( $_GET, array_merge( $context_params, array(
35
+ 'plugin_version' => $fs->get_plugin_version(),
36
+ 'wp_login_url' => wp_login_url(),
37
+ // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
38
+ ) ) );
39
+ ?>
40
+ <div class="fs-secure-notice">
41
+ <i class="dashicons dashicons-lock"></i>
42
+ <span><b>Secure HTTPS contact page</b>, running via iframe from external domain</span>
43
+ </div>
44
+ <div id="fs_contact" class="wrap" style="margin: 40px 0 -65px -20px;">
45
+ <div id="iframe"></div>
46
+ <script type="text/javascript">
47
+ (function ($) {
48
+ $(function () {
49
+
50
+ var
51
+ // Keep track of the iframe height.
52
+ iframe_height = 800,
53
+ base_url = '<?php echo WP_FS__ADDRESS ?>',
54
+ src = base_url + '/contact/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),
55
+
56
+ // Append the Iframe into the DOM.
57
+ iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
58
+ .appendTo('#iframe');
59
+
60
+ FS.PostMessage.init(base_url);
61
+ FS.PostMessage.receive('height', function (data) {
62
+ var h = data.height;
63
+ if (!isNaN(h) && h > 0 && h != iframe_height) {
64
+ iframe_height = h;
65
+ $("#iframe iframe").height(iframe_height + 'px');
66
+ }
67
+ });
68
+ });
69
+ })(jQuery);
70
+ </script>
71
+ </div>
72
+ <?php fs_require_template( 'powered-by.php' ) ?>
lib/freemius/templates/deactivation-feedback-modal.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.1.2
7
+ */
8
+ $slug = $VARS['slug'];
9
+ $fs = freemius( $slug );
10
+
11
+ $confirmation_message = $fs->apply_filters( 'uninstall_confirmation_message', '' );
12
+
13
+ $reasons = $VARS['reasons'];
14
+
15
+ $reasons_list_items_html = '';
16
+
17
+ foreach ( $reasons as $reason ) {
18
+ $list_item_classes = 'reason' . ( ! empty( $reason['input_type'] ) ? ' has-input' : '' );
19
+ $reasons_list_items_html .= '<li class="' . $list_item_classes . '" data-input-type="' . $reason['input_type'] . '" data-input-placeholder="' . $reason['input_placeholder'] . '"><label><span><input type="radio" name="selected-reason" value="' . $reason['id'] . '"/></span><span>' . $reason['text'] . '</span></label></li>';
20
+ }
21
+ ?>
22
+ <script>
23
+ (function( $ ) {
24
+ var reasonsHtml = <?php echo json_encode( $reasons_list_items_html ); ?>,
25
+ modalHtml =
26
+ '<div class="fs-modal<?php echo empty( $confirmation_message ) ? ' no-confirmation-message' : ''; ?>">'
27
+ + ' <div class="fs-modal-dialog">'
28
+ + ' <div class="fs-modal-body">'
29
+ + ' <div class="fs-modal-panel" data-panel-id="confirm"><p><?php echo $confirmation_message; ?></p></div>'
30
+ + ' <div class="fs-modal-panel active" data-panel-id="reasons"><h3><strong><?php printf( __fs( 'deactivation-share-reason' ) ); ?>:</strong></h3><ul id="reasons-list">' + reasonsHtml + '</ul></div>'
31
+ + ' </div>'
32
+ + ' <div class="fs-modal-footer">'
33
+ + ' <a href="#" class="button button-secondary button-deactivate"></a>'
34
+ + ' <a href="#" class="button button-primary button-close"><?php printf( __fs( 'deactivation-modal-button-cancel' ) ); ?></a>'
35
+ + ' </div>'
36
+ + ' </div>'
37
+ + '</div>',
38
+ $modal = $( modalHtml ),
39
+ $deactivateLink = $( '#the-list .deactivate > [data-slug=<?php echo $VARS['slug']; ?>].fs-slug' ).prev();
40
+
41
+ $modal.appendTo( $( 'body' ) );
42
+
43
+ registerEventHandlers();
44
+
45
+ function registerEventHandlers() {
46
+ $deactivateLink.click(function ( evt ) {
47
+ evt.preventDefault();
48
+
49
+ showModal();
50
+ });
51
+
52
+ $modal.on( 'click', '.button', function( evt ) {
53
+ evt.preventDefault();
54
+
55
+ if ( $( this ).hasClass( 'disabled' ) ) {
56
+ return;
57
+ }
58
+
59
+ var _parent = $( this ).parents( '.fs-modal:first' );
60
+ var _this = $( this );
61
+
62
+ if ( _this.hasClass( 'allow-deactivate' ) ) {
63
+ var $radio = $( 'input[type="radio"]:checked' );
64
+
65
+ if ( 0 === $radio.length ) {
66
+ // If no selected reason, just deactivate the plugin.
67
+ window.location.href = $deactivateLink.attr( 'href' );
68
+ return;
69
+ }
70
+
71
+ var $selected_reason = $radio.parents( 'li:first' ),
72
+ $input = $selected_reason.find( 'textarea, input[type="text"]' );
73
+
74
+ $.ajax({
75
+ url: ajaxurl,
76
+ method: 'POST',
77
+ data: {
78
+ 'action' : 'submit-uninstall-reason',
79
+ 'reason_id' : $radio.val(),
80
+ 'reason_info' : ( 0 !== $input.length ) ? $input.val().trim() : ''
81
+ },
82
+ beforeSend: function() {
83
+ _parent.find( '.button' ).addClass( 'disabled' );
84
+ _parent.find( '.button-secondary' ).text( 'Processing...' );
85
+ },
86
+ complete: function() {
87
+ // Do not show the dialog box, deactivate the plugin.
88
+ window.location.href = $deactivateLink.attr( 'href' );
89
+ }
90
+ });
91
+ } else if ( _this.hasClass( 'button-deactivate' ) ) {
92
+ // Change the Deactivate button's text and show the reasons panel.
93
+ _parent.find( '.button-deactivate').addClass( 'allow-deactivate' );
94
+
95
+ showPanel( 'reasons' );
96
+ }
97
+ });
98
+
99
+ $modal.on( 'click', 'input[type="radio"]', function() {
100
+ var _parent = $( this ).parents( 'li:first' );
101
+
102
+ $modal.find( '.reason-input' ).remove();
103
+ $modal.find( '.button-deactivate').text( '<?php printf( __fs( 'deactivation-modal-button-submit' ) ); ?>' );
104
+
105
+ if ( _parent.hasClass( 'has-input' ) ) {
106
+ var inputType = _parent.data( 'input-type' ),
107
+ inputPlaceholder = _parent.data( 'input-placeholder' ),
108
+ reasonInputHtml = '<div class="reason-input">' + ( ( 'textfield' === inputType ) ? '<input type="text" />' : '<textarea rows="5"></textarea>' ) + '</div>';
109
+
110
+ _parent.append( $( reasonInputHtml ) );
111
+ _parent.find( 'input, textarea' ).attr( 'placeholder', inputPlaceholder ).focus();
112
+ }
113
+ });
114
+
115
+ // If the user has clicked outside the window, cancel it.
116
+ $modal.on( 'click', function( evt ) {
117
+ var $target = $( evt.target );
118
+
119
+ // If the user has clicked anywhere in the modal dialog, just return.
120
+ if ( $target.hasClass( 'fs-modal-body' ) || $target.hasClass( 'fs-modal-footer' ) ) {
121
+ return;
122
+ }
123
+
124
+ // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return.
125
+ if ( ! $target.hasClass( 'button-close' ) && ( $target.parents( '.fs-modal-body').length > 0 || $target.parents( '.fs-modal-footer').length > 0 ) ) {
126
+ return;
127
+ }
128
+
129
+ closeModal();
130
+ });
131
+ }
132
+
133
+ function showModal() {
134
+ resetModal();
135
+
136
+ // Display the dialog box.
137
+ $modal.addClass( 'active' );
138
+
139
+ $( 'body' ).addClass( 'has-fs-modal' );
140
+ }
141
+
142
+ function closeModal() {
143
+ $modal.removeClass( 'active' );
144
+
145
+ $( 'body' ).removeClass( 'has-fs-modal' );
146
+ }
147
+
148
+ function resetModal() {
149
+ $modal.find( '.button' ).removeClass( 'disabled' );
150
+
151
+ // Uncheck all radio buttons.
152
+ $modal.find( 'input[type="radio"]' ).prop( 'checked', false );
153
+
154
+ // Remove all input fields ( textfield, textarea ).
155
+ $modal.find( '.reason-input' ).remove();
156
+
157
+ var $deactivateButton = $modal.find( '.button-deactivate' );
158
+
159
+ /*
160
+ * If the modal dialog has no confirmation message, that is, it has only one panel, then ensure
161
+ * that clicking the deactivate button will actually deactivate the plugin.
162
+ */
163
+ if ( $modal.hasClass( 'no-confirmation-message' ) ) {
164
+ $deactivateButton.addClass( 'allow-deactivate' );
165
+
166
+ showPanel( 'reasons' );
167
+ } else {
168
+ $deactivateButton.removeClass( 'allow-deactivate' );
169
+
170
+ showPanel( 'confirm' );
171
+ }
172
+ }
173
+
174
+ function showPanel( panelType ) {
175
+ $modal.find( '.fs-modal-panel' ).removeClass( 'active ');
176
+ $modal.find( '[data-panel-id="' + panelType + '"]' ).addClass( 'active' );
177
+
178
+ updateButtonLabels();
179
+ }
180
+
181
+ function updateButtonLabels() {
182
+ var $deactivateButton = $modal.find( '.button-deactivate' );
183
+
184
+ // Reset the deactivate button's text.
185
+ if ( 'confirm' === getCurrentPanel() ) {
186
+ $deactivateButton.text( '<?php printf( __fs( 'deactivation-modal-button-confirm' ) ); ?>' );
187
+ } else {
188
+ $deactivateButton.text( '<?php printf( __fs( 'deactivation-modal-button-deactivate' ) ); ?>' );
189
+ }
190
+ }
191
+
192
+ function getCurrentPanel() {
193
+ return $modal.find( '.fs-modal-panel.active' ).attr( 'data-panel-id' );
194
+ }
195
+ })( jQuery );
196
+ </script>
lib/freemius/templates/debug.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h2><?php _efs( 'plugin-installs' ) ?> / <?php _efs( 'sites' ) ?></h2>
2
+ <?php
3
+ /**
4
+ * @var FS_Site[] $sites
5
+ */
6
+ $sites = $VARS['sites'];
7
+ ?>
8
+ <table id="fs_installs" class="widefat">
9
+ <thead>
10
+ <tr>
11
+ <th><?php _efs( 'id' ) ?></th>
12
+ <th><?php _efs( 'plugin' ) ?></th>
13
+ <th><?php _efs( 'plan' ) ?></th>
14
+ <th><?php _efs( 'public-key' ) ?></th>
15
+ <th><?php _efs( 'secret-key' ) ?></th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ <?php foreach ( $sites as $plugin_basename => $site ) : ?>
20
+ <tr>
21
+ <td><?php echo $site->id ?></td>
22
+ <td><?php echo dirname( $plugin_basename ) ?></td>
23
+ <td><?php
24
+ echo is_object( $site->plan ) ? $site->plan->name : ''
25
+ ?></td>
26
+ <td><?php echo $site->public_key ?></td>
27
+ <td><?php echo $site->secret_key ?></td>
28
+ </tr>
29
+ <?php endforeach ?>
30
+ </tbody>
31
+ </table>
32
+ <?php
33
+ $addons = $VARS['addons'];
34
+ ?>
35
+ <?php foreach ( $addons as $plugin_id => $plugin_addons ) : ?>
36
+ <h2><?php printf( __fs( 'addons-of-x' ), $plugin_id ) ?></h2>
37
+ <table id="fs_addons" class="widefat">
38
+ <thead>
39
+ <tr>
40
+ <th><?php _efs( 'id' ) ?></th>
41
+ <th><?php _efs( 'title' ) ?></th>
42
+ <th><?php _efs( 'slug' ) ?></th>
43
+ <th><?php _efs( 'version' ) ?></th>
44
+ <th><?php _efs( 'public-key' ) ?></th>
45
+ <th><?php _efs( 'secret-key' ) ?></th>
46
+ </tr>
47
+ </thead>
48
+ <tbody>
49
+ <?php
50
+ /**
51
+ * @var FS_Plugin[] $plugin_addons
52
+ */
53
+ foreach ( $plugin_addons as $addon ) : ?>
54
+ <tr>
55
+ <td><?php echo $addon->id ?></td>
56
+ <td><?php echo $addon->title ?></td>
57
+ <td><?php echo $addon->slug ?></td>
58
+ <td><?php echo $addon->version ?></td>
59
+ <td><?php echo $addon->public_key ?></td>
60
+ <td><?php echo $addon->secret_key ?></td>
61
+ </tr>
62
+ <?php endforeach ?>
63
+ </tbody>
64
+ </table>
65
+ <?php endforeach ?>
66
+ <h2><?php _efs( 'users' ) ?></h2>
67
+ <?php
68
+ /**
69
+ * @var FS_User[] $users
70
+ */
71
+ $users = $VARS['users'];
72
+ ?>
73
+ <table id="fs_users" class="widefat">
74
+ <thead>
75
+ <tr>
76
+ <th><?php _efs( 'id' ) ?></th>
77
+ <th><?php _efs( 'name' ) ?></th>
78
+ <th><?php _efs( 'email' ) ?></th>
79
+ <th><?php _efs( 'verified' ) ?></th>
80
+ <th><?php _efs( 'public-key' ) ?></th>
81
+ <th><?php _efs( 'secret-key' ) ?></th>
82
+ </tr>
83
+ </thead>
84
+ <tbody>
85
+ <?php foreach ( $users as $user_id => $user ) : ?>
86
+ <tr>
87
+ <td><?php echo $user->id ?></td>
88
+ <td><?php echo $user->get_name() ?></td>
89
+ <td><?php echo $user->email ?></td>
90
+ <td><?php echo json_encode( $user->is_verified ) ?></td>
91
+ <td><?php echo $user->public_key ?></td>
92
+ <td><?php echo $user->secret_key ?></td>
93
+ </tr>
94
+ <?php endforeach ?>
95
+ </tbody>
96
+ </table>
97
+ <br><br>
98
+ <form action="" method="POST">
99
+ <input type="hidden" name="fs_action" value="delete_all_accounts">
100
+ <?php wp_nonce_field( 'delete_all_accounts' ) ?>
101
+ <button class="button button-primary"
102
+ onclick="if (confirm('<?php _efs( 'delete-all-confirm' ) ?>')) this.parentNode.submit(); return false;"><?php _efs( 'delete-all-accounts' ) ?></button>
103
+ </form>
lib/freemius/templates/email.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.1.1
7
+ */
8
+
9
+ $sections = $VARS['sections'];
10
+ ?>
11
+ <table>
12
+ <?php
13
+ foreach ( $sections as $section_id => $section ) {
14
+ ?>
15
+ <thead>
16
+ <tr><th colspan="2" style="text-align: left; background: #333; color: #fff; padding: 5px;"><?php echo $section['title']; ?></th></tr>
17
+ </thead>
18
+ <tbody>
19
+ <?php
20
+ foreach ( $section['rows'] as $row_id => $row ) {
21
+ $col_count = count( $row );
22
+ ?>
23
+ <tr>
24
+ <?php
25
+ if ( 1 === $col_count ) { ?>
26
+ <td style="vertical-align: top;" colspan="2"><?php echo $row[0]; ?></td>
27
+ <?php
28
+ } else { ?>
29
+ <td style="vertical-align: top;"><b><?php echo $row[0]; ?>:</b></td>
30
+ <td><?php echo $row[1]; ?></td>
31
+ <?php
32
+ }
33
+ ?>
34
+ </tr>
35
+ <?php
36
+ }
37
+ ?>
38
+ </tbody>
39
+ <?php
40
+ }
41
+ ?>
42
+ </table>
lib/freemius/templates/firewall-issues-js.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * API connectivity issues (CloudFlare's firewall) handler for handling different
4
+ * scenarios selected by the user after connectivity issue is detected, by sending
5
+ * AJAX call to the server in order to make the actual actions.
6
+ *
7
+ * @package Freemius
8
+ * @copyright Copyright (c) 2015, Freemius, Inc.
9
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
10
+ * @since 1.0.9
11
+ */
12
+ ?>
13
+ <script type="text/javascript">
14
+ jQuery(document).ready(function ($) {
15
+ $('#fs_firewall_issue_options a.fs-resolve').click(function () {
16
+ var
17
+ error_type = $(this).attr('data-type'),
18
+ notice = $(this).parents('.fs-notice'),
19
+ slug = notice.attr('data-slug');
20
+
21
+ var data = {
22
+ action : slug + '_resolve_firewall_issues',
23
+ slug : slug,
24
+ error_type: error_type
25
+ };
26
+
27
+ if ('squid' === error_type) {
28
+ data.hosting_company = prompt('What is the name or URL of your hosting company?');
29
+ if (null == data.hosting_company)
30
+ return false;
31
+
32
+ if ('' === data.hosting_company) {
33
+ alert('We won\'t be able to help without knowing your hosting company.');
34
+ return false;
35
+ }
36
+ }
37
+
38
+ $(this).css({'cursor': 'wait'});
39
+
40
+ // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
41
+ $.post(ajaxurl, data, function (response) {
42
+ if (1 == response) {
43
+ // Refresh page on success.
44
+ location.reload();
45
+ }
46
+ });
47
+ });
48
+ });
49
+ </script>
lib/freemius/templates/pending-activation.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.9
7
+ */
8
+
9
+ wp_enqueue_script( 'jquery' );
10
+ wp_enqueue_script( 'json2' );
11
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
12
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
13
+
14
+ fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
15
+
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+ $current_user = wp_get_current_user();
19
+
20
+ $first_name = $current_user->user_firstname;
21
+ if ( empty( $first_name ) ) {
22
+ $first_name = $current_user->nickname;
23
+ }
24
+
25
+ $site_url = get_site_url();
26
+ $protocol_pos = strpos( $site_url, '://' );
27
+ if ( false !== $protocol_pos ) {
28
+ $site_url = substr( $site_url, $protocol_pos + 3 );
29
+ }
30
+ ?>
31
+ <div id="fs_connect" class="wrap fs-anonymous-disabled">
32
+ <div class="fs-visual">
33
+ <b class="fs-site-icon"><i class="dashicons dashicons-wordpress"></i></b>
34
+ <i class="dashicons dashicons-plus fs-first"></i>
35
+
36
+ <div class="fs-plugin-icon">
37
+ <object data="//plugins.svn.wordpress.org/<?php echo $slug ?>/assets/icon-128x128.png" type="image/png">
38
+ <object data="//plugins.svn.wordpress.org/<?php echo $slug ?>/assets/icon-128x128.jpg" type="image/png">
39
+ <object data="//plugins.svn.wordpress.org/<?php echo $slug ?>/assets/icon-256x256.png"
40
+ type="image/png">
41
+ <object data="//plugins.svn.wordpress.org/<?php echo $slug ?>/assets/icon-256x256.jpg"
42
+ type="image/png">
43
+ <img src="//wimg.freemius.com/plugin-icon.png"/>
44
+ </object>
45
+ </object>
46
+ </object>
47
+ </object>
48
+ </div>
49
+ <i class="dashicons dashicons-plus fs-second"></i>
50
+ <img class="fs-connect-logo" width="80" height="80" src="//img.freemius.com/connect-logo.png"/>
51
+ </div>
52
+ <div class="fs-content">
53
+ <p><?php
54
+ echo $fs->apply_filters( 'pending_activation_message', sprintf(
55
+ __fs( 'thanks-x' ) . '<br>' .
56
+ __fs( 'pending-activation-message' ),
57
+ $first_name,
58
+ '<b>' . $fs->get_plugin_name() . '</b>',
59
+ '<b>' . $current_user->user_email . '</b>'
60
+ ) )
61
+ ?></p>
62
+ </div>
63
+ <div class="fs-actions">
64
+ <?php $fs_user = Freemius::_get_user_by_email( $current_user->user_email ) ?>
65
+ <form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
66
+ <?php
67
+ $params = array(
68
+ 'user_firstname' => $current_user->user_firstname,
69
+ 'user_lastname' => $current_user->user_lastname,
70
+ 'user_nickname' => $current_user->user_nicename,
71
+ 'user_email' => $current_user->user_email,
72
+ 'plugin_slug' => $slug,
73
+ 'plugin_id' => $fs->get_id(),
74
+ 'plugin_public_key' => $fs->get_public_key(),
75
+ 'plugin_version' => $fs->get_plugin_version(),
76
+ 'return_url' => wp_nonce_url( $fs->_get_admin_page_url(
77
+ '',
78
+ array( 'fs_action' => $slug . '_activate_new' )
79
+ ), $slug . '_activate_new' ),
80
+ 'account_url' => wp_nonce_url( $fs->_get_admin_page_url(
81
+ 'account',
82
+ array( 'fs_action' => 'sync_user' )
83
+ ), 'sync_user' ),
84
+ 'site_url' => get_site_url(),
85
+ 'site_name' => get_bloginfo( 'name' ),
86
+ 'platform_version' => get_bloginfo( 'version' ),
87
+ 'language' => get_bloginfo( 'language' ),
88
+ 'charset' => get_bloginfo( 'charset' ),
89
+ );
90
+ ?>
91
+ <?php foreach ( $params as $name => $value ) : ?>
92
+ <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
93
+ <?php endforeach ?>
94
+ <button class="button button-primary" tabindex="1"
95
+ type="submit"><?php _efs( 'resend-activation-email' ) ?></button>
96
+ </form>
97
+ </div>
98
+ <div class="fs-permissions">
99
+ <a class="fs-trigger" href="#"><?php _efs( 'what-permissions' ) ?></a>
100
+ <ul>
101
+ <li>
102
+ <i class="dashicons dashicons-admin-users"></i>
103
+
104
+ <div>
105
+ <span><?php _efs( 'permissions-profile' ) ?></span>
106
+
107
+ <p><?php _efs( 'permissions-profile_desc' ) ?></p>
108
+ </div>
109
+ </li>
110
+ <li>
111
+ <i class="dashicons dashicons-wordpress"></i>
112
+
113
+ <div>
114
+ <span><?php _efs( 'permissions-site' ) ?></span>
115
+
116
+ <p><?php _efs( 'permissions-site_desc' ) ?></p>
117
+ </div>
118
+ </li>
119
+ <li>
120
+ <i class="dashicons dashicons-admin-plugins"></i>
121
+
122
+ <div>
123
+ <span><?php _efs( 'permissions-events' ) ?></span>
124
+
125
+ <p><?php _efs( 'permissions-events_desc' ) ?></p>
126
+ </div>
127
+ </li>
128
+ </ul>
129
+ </div>
130
+ <div class="fs-terms">
131
+ <a href="https://freemius.com/privacy/" target="_blank"><?php _efs( 'privacy-policy' ) ?></a>
132
+ &nbsp;&nbsp;-&nbsp;&nbsp;
133
+ <a href="https://freemius.com/terms/" target="_blank"><?php _efs( 'tos' ) ?></a>
134
+ </div>
135
+ </div>
136
+ <script type="text/javascript">
137
+ (function ($) {
138
+ $('.button.button-primary').on('click', function () {
139
+ $(document.body).css({'cursor': 'wait'});
140
+ $(this).html('Sending email...').css({'cursor': 'wait'});
141
+ });
142
+ $('.fs-permissions .fs-trigger').on('click', function () {
143
+ $('.fs-permissions').toggleClass('fs-open');
144
+ });
145
+ })(jQuery);
146
+ </script>
lib/freemius/templates/plugin-icon.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.1.4
7
+ */
8
+ $slug = $VARS['slug'];
9
+ $fs = freemius( $slug );
10
+
11
+ $icons = glob( fs_normalize_path( WP_FS__DIR_IMG . '/icon.*' ) );
12
+ if ( ! is_array( $icons ) || 0 === count( $icons ) ) {
13
+ $icon_found = false;
14
+ $local_path = fs_normalize_path( WP_FS__DIR_IMG . '/icon.png' );
15
+
16
+ if ( WP_FS__IS_LOCALHOST && $fs->is_org_repo_compliant() ) {
17
+ /**
18
+ * IMPORTANT: THIS CODE WILL NEVER RUN AFTER THE PLUGIN IS IN THE REPO.
19
+ *
20
+ * This code will only be executed once during the testing
21
+ * of the plugin in a local environment. The plugin icon file WILL
22
+ * already exist in the assets folder when the plugin is deployed to
23
+ * the repository.
24
+ */
25
+ $suffixes = array(
26
+ '-128x128.png',
27
+ '-128x128.jpg',
28
+ '-256x256.png',
29
+ '-256x256.jpg',
30
+ '.svg',
31
+ );
32
+
33
+ $base_url = 'https://plugins.svn.wordpress.org/' . $slug . '/assets/icon';
34
+
35
+ foreach ( $suffixes as $s ) {
36
+ $headers = get_headers( $base_url . $s );
37
+ if ( strpos( $headers[0], '200' ) ) {
38
+ $local_path = fs_normalize_path( WP_FS__DIR_IMG . '/icon.' . substr( $s, strpos( $s, '.' ) + 1 ) );
39
+ fs_download_image( $base_url . $s, $local_path );
40
+ $icon_found = true;
41
+ break;
42
+ }
43
+ }
44
+ }
45
+
46
+ if ( ! $icon_found ) {
47
+ // No icons found, fallback to default icon.
48
+ copy( fs_normalize_path( WP_FS__DIR_IMG . '/plugin-icon.png' ), $local_path );
49
+ }
50
+
51
+ $icons = array( $local_path );
52
+ }
53
+
54
+ $relative_url = fs_img_url( substr( $icons[0], strlen( fs_normalize_path( WP_FS__DIR_IMG ) ) ) );
55
+ ?>
56
+ <div class="fs-plugin-icon">
57
+ <img src="<?php echo $relative_url ?>"/>
58
+ </div>
lib/freemius/templates/plugin-info/description.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var FS_Plugin $plugin
4
+ */
5
+ $plugin = $VARS['plugin'];
6
+
7
+ if ( ! empty( $plugin->info->selling_point_0 ) ||
8
+ ! empty( $plugin->info->selling_point_1 ) ||
9
+ ! empty( $plugin->info->selling_point_2 )
10
+ ) : ?>
11
+ <div class="fs-selling-points">
12
+ <ul>
13
+ <?php for ( $i = 0; $i < 3; $i ++ ) : ?>
14
+ <?php if ( ! empty( $plugin->info->{'selling_point_' . $i} ) ) : ?>
15
+ <li><i class="dashicons dashicons-yes"></i>
16
+
17
+ <h3><?php echo $plugin->info->{'selling_point_' . $i} ?></h3></li>
18
+ <?php endif ?>
19
+ <?php endfor ?>
20
+ </ul>
21
+ </div>
22
+ <?php endif ?>
23
+ <div>
24
+ <?php
25
+ echo wp_kses( $plugin->info->description, array(
26
+ 'a' => array( 'href' => array(), 'title' => array(), 'target' => array() ),
27
+ 'b' => array(),
28
+ 'i' => array(),
29
+ 'p' => array(),
30
+ 'blockquote' => array(),
31
+ 'h2' => array(),
32
+ 'h3' => array(),
33
+ 'ul' => array(),
34
+ 'ol' => array(),
35
+ 'li' => array()
36
+ ) );
37
+ ?>
38
+ </div>
39
+ <?php if ( ! empty( $plugin->info->screenshots ) ) : ?>
40
+ <?php $screenshots = $plugin->info->screenshots ?>
41
+ <div class="fs-screenshots clearfix">
42
+ <h2><?php _efs( 'screenshots' ) ?></h2>
43
+ <ul>
44
+ <?php $i = 0;
45
+ foreach ( $screenshots as $s => $url ) : ?>
46
+ <?php
47
+ // Relative URLs are replaced with WordPress.org base URL
48
+ // therefore we need to set absolute URLs.
49
+ $url = 'http' . ( WP_FS__IS_HTTPS ? 's' : '' ) . ':' . $url; ?>
50
+ <li class="<?php echo ( 0 === $i % 2 ) ? 'odd' : 'even' ?>">
51
+ <style>
52
+ #section-description .fs-screenshots .fs-screenshot-<?php echo $i ?>
53
+ {
54
+ background-image: url('<?php echo $url ?>');
55
+ }
56
+ </style>
57
+ <a href="<?php echo $url ?>" title="<?php printf( __fs( 'view-full-size-x' ), $i ) ?>"
58
+ class="fs-screenshot-<?php echo $i ?>"></a>
59
+ </li>
60
+ <?php $i ++; endforeach ?>
61
+ </ul>
62
+ </div>
63
+ <?php endif ?>
lib/freemius/templates/plugin-info/features.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $plans = $VARS['plans'];
3
+
4
+ $features_plan_map = array();
5
+ foreach ( $plans as $plan ) {
6
+ foreach ( $plan->features as $feature ) {
7
+ if ( ! isset( $features_plan_map[ $feature->id ] ) ) {
8
+ $features_plan_map[ $feature->id ] = array( 'feature' => $feature, 'plans' => array() );
9
+ }
10
+
11
+ $features_plan_map[ $feature->id ]['plans'][ $plan->id ] = $feature;
12
+ }
13
+
14
+ // Add support as a feature.
15
+ if ( ! empty( $plan->support_email ) ||
16
+ ! empty( $plan->support_skype ) ||
17
+ ! empty( $plan->support_phone ) ||
18
+ true === $plan->is_success_manager
19
+ ) {
20
+ if ( ! isset( $features_plan_map['support'] ) ) {
21
+ $support_feature = new stdClass();
22
+ $support_feature->id = 'support';
23
+ $support_feature->title = __fs( 'Support' );
24
+ $features_plan_map[ $support_feature->id ] = array( 'feature' => $support_feature, 'plans' => array() );
25
+ } else {
26
+ $support_feature = $features_plan_map['support'];
27
+ }
28
+
29
+ $features_plan_map[ $support_feature->id ]['plans'][ $plan->id ] = $support_feature;
30
+ }
31
+ }
32
+
33
+ // Add updates as a feature for all plans.
34
+ $updates_feature = new stdClass();
35
+ $updates_feature->id = 'updates';
36
+ $updates_feature->title = __fs( 'unlimited-updates' );
37
+ $features_plan_map[ $updates_feature->id ] = array( 'feature' => $updates_feature, 'plans' => array() );
38
+ foreach ( $plans as $plan ) {
39
+ $features_plan_map[ $updates_feature->id ]['plans'][ $plan->id ] = $updates_feature;
40
+ }
41
+ ?>
42
+ <div class="fs-features">
43
+ <table>
44
+ <thead>
45
+ <tr>
46
+ <th></th>
47
+ <?php foreach ( $plans as $plan ) : ?>
48
+ <th>
49
+ <?php echo $plan->title ?>
50
+ <span class="fs-price">
51
+ <?php foreach ( $plan->pricing as $pricing ) : ?>
52
+ <?php if ( 1 == $pricing->licenses ) : ?>
53
+ $<?php echo $pricing->annual_price ?> / year
54
+ <?php endif ?>
55
+ <?php endforeach ?>
56
+ </span>
57
+ </th>
58
+ <?php endforeach ?>
59
+ </tr>
60
+ </thead>
61
+ <tbody>
62
+ <?php $odd = true;
63
+ foreach ( $features_plan_map as $feature_id => $data ) : ?>
64
+ <tr class="fs-<?php echo $odd ? 'odd' : 'even' ?>">
65
+ <td><?php echo ucfirst( $data['feature']->title ) ?></td>
66
+ <?php foreach ( $plans as $plan ) : ?>
67
+ <td>
68
+ <?php if ( isset( $data['plans'][ $plan->id ] ) ) : ?>
69
+ <?php if ( ! empty( $data['plans'][ $plan->id ]->value ) ) : ?>
70
+ <b><?php echo $data['plans'][ $plan->id ]->value ?></b>
71
+ <?php else : ?>
72
+ <i class="dashicons dashicons-yes"></i>
73
+ <?php endif ?>
74
+ <?php endif ?>
75
+ </td>
76
+ <?php endforeach ?>
77
+ </tr>
78
+ <?php $odd = ! $odd; endforeach ?>
79
+ </tbody>
80
+ </table>
81
+ </div>
lib/freemius/templates/plugin-info/screenshots.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var FS_Plugin $plugin
4
+ */
5
+ $screenshots = $VARS['screenshots'];
6
+ ?>
7
+ <ol>
8
+ <?php $i = 0;
9
+ foreach ( $screenshots as $s => $url ) : ?>
10
+ <?php
11
+ // Relative URLs are replaced with WordPress.org base URL
12
+ // therefore we need to set absolute URLs.
13
+ $url = 'http' . ( WP_FS__IS_HTTPS ? 's' : '' ) . ':' . $url; ?>
14
+ <li>
15
+ <a href="<?php echo $url ?>" title="<?php printf( __fs( 'view-full-size-x' ), $i ) ?>"><img
16
+ src="<?php echo $url ?>"></a>
17
+ </li>
18
+ <?php $i ++; endforeach ?>
19
+ </ol>
lib/freemius/templates/powered-by.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.5
7
+ */
8
+
9
+ /**
10
+ * KEEP THE POWERED BY TAB AND GET ADDITIONAL - 2% - OFF THE COMMISSION
11
+ */
12
+
13
+ wp_enqueue_script( 'jquery' );
14
+ wp_enqueue_script( 'json2' );
15
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
16
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
+ ?>
18
+
19
+ <div id="piframe"></div>
20
+ <script type="text/javascript">
21
+ (function ($) {
22
+ $(function () {
23
+ var
24
+ base_url = '<?php echo WP_FS__ADDRESS ?>',
25
+ piframe = $('<iframe id="fs_promo_tab" src="' + base_url + '/promotional-tab/?page=contact#' + encodeURIComponent(document.location.href) + '" height="350" width="60" frameborder="0" style=" background: transparent; position: fixed; top: 20%; right: 0;" scrolling="no"></iframe>')
26
+ .appendTo('#piframe');
27
+
28
+ FS.PostMessage.init(base_url);
29
+ FS.PostMessage.receive('state', function (state) {
30
+ if ('closed' === state)
31
+ $('#fs_promo_tab').css('width', '60px');
32
+ else
33
+ $('#fs_promo_tab').css('width', '345px');
34
+ });
35
+ });
36
+ })(jQuery);
37
+ </script>
lib/freemius/templates/pricing.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.3
7
+ */
8
+
9
+ wp_enqueue_script( 'jquery' );
10
+ wp_enqueue_script( 'json2' );
11
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
12
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
13
+
14
+ $slug = $VARS['slug'];
15
+ $fs = freemius( $slug );
16
+ $timestamp = time();
17
+
18
+ $context_params = array(
19
+ 'plugin_id' => $fs->get_id(),
20
+ 'plugin_public_key' => $fs->get_public_key(),
21
+ 'plugin_version' => $fs->get_plugin_version(),
22
+ );
23
+
24
+ // Get site context secure params.
25
+ if ( $fs->is_registered() ) {
26
+ $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
27
+ $fs->get_site(),
28
+ $timestamp,
29
+ 'upgrade'
30
+ ) );
31
+ }
32
+
33
+ if ( $fs->is_payments_sandbox() ) // Append plugin secure token for sandbox mode authentication.)
34
+ {
35
+ $context_params['sandbox'] = FS_Security::instance()->get_secure_token(
36
+ $fs->get_plugin(),
37
+ $timestamp,
38
+ 'checkout'
39
+ );
40
+ }
41
+
42
+ $query_params = array_merge( $context_params, $_GET, array(
43
+ 'next' => $fs->_get_admin_page_url( 'account', array( 'fs_action' => $slug . '_sync_license' ) ),
44
+ 'plugin_version' => $fs->get_plugin_version(),
45
+ // Billing cycle.
46
+ 'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),
47
+ ) );
48
+ ?>
49
+
50
+ <div id="fs_pricing" class="wrap" style="margin: 0 0 -65px -20px;">
51
+ <div id="iframe"></div>
52
+ <form action="" method="POST">
53
+ <input type="hidden" name="user_id"/>
54
+ <input type="hidden" name="user_email"/>
55
+ <input type="hidden" name="site_id"/>
56
+ <input type="hidden" name="public_key"/>
57
+ <input type="hidden" name="secret_key"/>
58
+ <input type="hidden" name="action" value="account"/>
59
+ </form>
60
+
61
+ <script type="text/javascript">
62
+ (function ($, undef) {
63
+ $(function () {
64
+ var
65
+ // Keep track of the iframe height.
66
+ iframe_height = 800,
67
+ base_url = '<?php echo WP_FS__ADDRESS ?>',
68
+ // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
69
+ // passed via query string or hard coded into the child page, it depends on your needs).
70
+ src = base_url + '/pricing/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),
71
+
72
+ // Append the Iframe into the DOM.
73
+ iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
74
+ .appendTo('#iframe');
75
+
76
+ FS.PostMessage.init(base_url);
77
+
78
+ FS.PostMessage.receive('height', function (data) {
79
+ var h = data.height;
80
+ if (!isNaN(h) && h > 0 && h != iframe_height) {
81
+ iframe_height = h;
82
+ $("#iframe iframe").height(iframe_height + 'px');
83
+ }
84
+ });
85
+
86
+ FS.PostMessage.receive('get_dimensions', function (data) {
87
+ FS.PostMessage.post('dimensions', {
88
+ height : $(document.body).height(),
89
+ scrollTop: $(document).scrollTop()
90
+ }, iframe[0]);
91
+ });
92
+ });
93
+ })(jQuery);
94
+ </script>
95
+ </div>
96
+ <?php fs_require_template( 'powered-by.php' ) ?>
lib/freemius/templates/sticky-admin-notice-js.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Sticky admin notices JavaScript handler for dismissing notice messages
4
+ * by sending AJAX call to the server in order to remove the message from the Database.
5
+ *
6
+ * @package Freemius
7
+ * @copyright Copyright (c) 2015, Freemius, Inc.
8
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
+ * @since 1.0.7
10
+ */
11
+ ?>
12
+ <script type="text/javascript" >
13
+ jQuery(document).ready(function($) {
14
+ $('.fs-notice.fs-sticky .fs-close').click(function(){
15
+ var
16
+ notice = $(this).parents('.fs-notice'),
17
+ id = notice.attr('data-id'),
18
+ slug = notice.attr('data-slug');
19
+
20
+ notice.fadeOut('fast', function(){
21
+ var data = {
22
+ action: slug + '_dismiss_notice_action',
23
+ slug: slug,
24
+ message_id: id
25
+ };
26
+
27
+ // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
28
+ $.post(ajaxurl, data, function(response) {
29
+
30
+ });
31
+
32
+ notice.remove();
33
+ });
34
+ });
35
+ });
36
+ </script>
readme.txt CHANGED
@@ -6,7 +6,7 @@ License: GPLv2 or later
6
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
7
  Requires at least: WordPress 3.6
8
  Tested up to: 4.4
9
- Stable tag: 3.9.5
10
 
11
  Add albums, photo, audio/video encoding, privacy, sharing, front-end uploads & more. All this works on mobile/tablets devices.
12
 
@@ -140,6 +140,10 @@ http://www.youtube.com/watch?v=dJrykKQGDcs
140
 
141
  == Changelog ==
142
 
 
 
 
 
143
  = 3.9.5 [Dec 11, 2015] =
144
  * Added new filters
145
  * Update chinese translations
@@ -1115,8 +1119,8 @@ http://www.youtube.com/watch?v=dJrykKQGDcs
1115
 
1116
  == Upgrade Notice ==
1117
 
1118
- = 3.9.5 =
1119
- Requires BuddyPress 1.7 or higher, if using BuddyPress. Added new filters, update chinese translations, fix rtMedia add-on broken images.
1120
 
1121
  == Sponsors ==
1122
 
6
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
7
  Requires at least: WordPress 3.6
8
  Tested up to: 4.4
9
+ Stable tag: 3.10
10
 
11
  Add albums, photo, audio/video encoding, privacy, sharing, front-end uploads & more. All this works on mobile/tablets devices.
12
 
140
 
141
  == Changelog ==
142
 
143
+ = 3.10 [Dec 22, 2015] =
144
+ * Added update BuddyPress activity privacy feature
145
+ * Added BuddyPress activity for media likes and comments feature
146
+
147
  = 3.9.5 [Dec 11, 2015] =
148
  * Added new filters
149
  * Update chinese translations
1119
 
1120
  == Upgrade Notice ==
1121
 
1122
+ = 3.10 =
1123
+ Requires BuddyPress 1.7 or higher, if using BuddyPress. Added update BuddyPress activity privacy feature, added BuddyPress activity for media likes and comments feature.
1124
 
1125
  == Sponsors ==
1126