WP to Twitter - Version 3.2.19

Version Description

  • Bug fix: account for mixed return values in get_the_tags()
Download this release

Release Info

Developer joedolson
Plugin Icon 128x128 WP to Twitter
Version 3.2.19
Comparing to
See all releases

Code changes from version 3.2.0 to 3.2.19

Files changed (107) hide show
  1. css/post-styles.css +2 -2
  2. css/styles.css +16 -2
  3. freemius/.gitignore +0 -3
  4. freemius/README.md +7 -2
  5. freemius/assets/css/admin/account.css +1 -1
  6. freemius/assets/css/admin/add-ons.css +2 -2
  7. freemius/assets/css/admin/common.css +1 -1
  8. freemius/assets/css/admin/connect.css +1 -1
  9. freemius/assets/css/admin/deactivation-feedback.css +1 -1
  10. freemius/assets/css/admin/debug.css +1 -0
  11. freemius/assets/css/admin/dialog-boxes.css +2 -0
  12. freemius/assets/css/admin/license-activation.css +1 -0
  13. freemius/assets/img/icon.png +0 -0
  14. freemius/assets/js/postmessage.js +28 -3
  15. freemius/assets/scss/_mixins.scss +0 -8
  16. freemius/assets/scss/admin/_deactivation-feedback.scss +55 -0
  17. freemius/assets/scss/admin/_license-activation.scss +7 -0
  18. freemius/assets/scss/admin/_license-key-resend.scss +44 -0
  19. freemius/assets/scss/admin/_modal-common.scss +153 -0
  20. freemius/assets/scss/admin/account.scss +60 -14
  21. freemius/assets/scss/admin/add-ons.scss +224 -94
  22. freemius/assets/scss/admin/common.scss +8 -2
  23. freemius/assets/scss/admin/connect.scss +471 -421
  24. freemius/assets/scss/admin/debug.scss +91 -0
  25. freemius/assets/scss/admin/dialog-boxes.scss +5 -0
  26. freemius/config.php +73 -15
  27. freemius/gulpfile.js +42 -0
  28. freemius/includes/class-freemius-abstract.php +49 -0
  29. freemius/includes/class-freemius.php +3596 -1019
  30. freemius/includes/class-fs-api.php +44 -16
  31. freemius/includes/class-fs-logger.php +17 -6
  32. freemius/includes/class-fs-plugin-updater.php +41 -18
  33. freemius/includes/class-fs-security.php +19 -1
  34. freemius/includes/debug/class-fs-debug-bar-panel.php +64 -0
  35. freemius/includes/debug/debug-bar-start.php +52 -0
  36. freemius/includes/entities/class-fs-entity.php +1 -1
  37. freemius/includes/entities/class-fs-payment.php +94 -0
  38. freemius/includes/entities/class-fs-plugin-license.php +59 -3
  39. freemius/includes/entities/class-fs-plugin-plan.php +75 -1
  40. freemius/includes/entities/class-fs-pricing.php +141 -0
  41. freemius/includes/entities/class-fs-site.php +8 -0
  42. freemius/includes/entities/class-fs-subscription.php +8 -0
  43. freemius/includes/fs-core-functions.php +272 -152
  44. freemius/includes/fs-essential-functions.php +53 -41
  45. freemius/includes/fs-plugin-info-dialog.php +930 -0
  46. freemius/includes/i18n.php +390 -299
  47. freemius/includes/managers/class-fs-admin-menu-manager.php +5 -5
  48. freemius/includes/managers/class-fs-admin-notice-manager.php +309 -302
  49. freemius/includes/managers/class-fs-cache-manager.php +26 -0
  50. freemius/includes/managers/class-fs-key-value-storage.php +36 -1
  51. freemius/includes/managers/class-fs-license-manager.php +3 -0
  52. freemius/includes/managers/class-fs-option-manager.php +5 -0
  53. freemius/includes/managers/class-fs-plan-manager.php +15 -0
  54. freemius/includes/sdk/Freemius.php +58 -15
  55. freemius/includes/sdk/FreemiusBase.php +1 -1
  56. freemius/languages/freemius-en.mo +0 -0
  57. freemius/languages/freemius-en.po +1396 -0
  58. freemius/languages/freemius-it_IT.mo +0 -0
  59. freemius/languages/freemius-it_IT.po +1521 -0
  60. freemius/languages/freemius.pot +1399 -0
  61. freemius/package.json +32 -0
  62. freemius/require.php +43 -0
  63. freemius/start.php +311 -331
  64. freemius/templates/account.php +550 -314
  65. freemius/templates/add-ons.php +97 -60
  66. freemius/templates/admin-notice.php +25 -21
  67. freemius/templates/all-admin-notice.php +4 -0
  68. freemius/templates/billing.php +109 -0
  69. freemius/templates/checkout.php +40 -22
  70. freemius/templates/connect.php +348 -241
  71. freemius/templates/contact.php +12 -1
  72. freemius/templates/deactivation-feedback-modal.php +177 -177
  73. freemius/templates/debug.php +87 -4
  74. freemius/templates/debug/api-calls.php +138 -0
  75. freemius/templates/debug/logger.php +66 -0
  76. freemius/templates/debug/plugins-themes-sync.php +68 -0
  77. freemius/templates/debug/scheduled-crons.php +109 -0
  78. freemius/templates/email.php +3 -0
  79. freemius/templates/firewall-issues-js.php +8 -1
  80. freemius/templates/forms/deactivation/contact.php +23 -0
  81. freemius/templates/forms/deactivation/form.php +360 -0
  82. freemius/templates/forms/deactivation/retry-skip.php +24 -0
  83. freemius/templates/forms/license-activation.php +228 -0
  84. freemius/templates/forms/resend-key.php +197 -0
  85. freemius/templates/pending-activation.php +157 -0
  86. freemius/templates/plugin-icon.php +64 -44
  87. freemius/templates/plugin-info/description.php +2 -0
  88. freemius/templates/plugin-info/features.php +2 -0
  89. freemius/templates/plugin-info/screenshots.php +2 -0
  90. freemius/templates/powered-by.php +2 -4
  91. freemius/templates/pricing.php +13 -2
  92. freemius/templates/sticky-admin-notice-js.php +1 -1
  93. js/ajax.js +11 -4
  94. lang/wp-to-twitter-en_AU.mo +0 -0
  95. readme.txt +114 -11
  96. tmhOAuth/tmhOAuth.php +1 -1
  97. uninstall.php +0 -98
  98. wp-to-twitter-manager.php +53 -31
  99. wp-to-twitter-oauth.php +23 -2
  100. wp-to-twitter-shorteners.php +68 -42
  101. wp-to-twitter.php +145 -200
  102. wpt-feed.php +9 -6
  103. wpt-functions.php +220 -50
  104. wpt-rate-limiting.php +1 -0
  105. wpt-truncate.php +120 -7
  106. wpt-widget.php +30 -17
  107. wpt_twitter_oauth.php +57 -5
css/post-styles.css CHANGED
@@ -210,8 +210,8 @@ button.time div {
210
 
211
  .tweet-buttons {
212
  padding: .75em 12px;
213
- margin: -10px -12px 10px;
214
- background: #f6f6f6;
215
  }
216
 
217
  .wp-to-twitter .template {
210
 
211
  .tweet-buttons {
212
  padding: .75em 12px;
213
+ margin: -10px -12px 0;
214
+ background: #f3f3f3;
215
  }
216
 
217
  .wp-to-twitter .template {
css/styles.css CHANGED
@@ -157,10 +157,14 @@ label[for="wpt_license_key"] {
157
 
158
  #wpt_settings_page .wptab {
159
  background: #fff;
160
- padding: 0 12px;
161
  margin-bottom: 10px;
162
  min-height: 200px;
163
- border: 1px solid #ccc;
 
 
 
 
 
164
  }
165
 
166
  #wp-to-twitter .wpt-pro-tab {
@@ -189,6 +193,16 @@ label[for="wpt_license_key"] {
189
  padding: 0;
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
192
  .wpt-terms li {
193
  padding: 2px !important;
194
  border-radius: 3px;
157
 
158
  #wpt_settings_page .wptab {
159
  background: #fff;
 
160
  margin-bottom: 10px;
161
  min-height: 200px;
162
+ border-top: 1px solid #ccc;
163
+ }
164
+
165
+ #wpt_settings_page .inside.purchase ul {
166
+ list-style-type: disc;
167
+ margin-left: 2em;
168
  }
169
 
170
  #wp-to-twitter .wpt-pro-tab {
193
  padding: 0;
194
  }
195
 
196
+ .inside.purchase {
197
+ width: 70%;
198
+ margin: 0 auto;
199
+ min-width: 300px;
200
+ }
201
+
202
+ .inside.purchase h4 {
203
+ font-size: 1.8em;
204
+ }
205
+
206
  .wpt-terms li {
207
  padding: 2px !important;
208
  border-radius: 3px;
freemius/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- output/
2
- assets/img/icon.*
3
-
 
 
 
freemius/README.md CHANGED
@@ -10,6 +10,11 @@ http://bit.ly/freemius-beta
10
 
11
  **Below you'll find the integration instructions for our WordPress SDK.**
12
 
 
 
 
 
 
13
  ## Initializing the SDK
14
 
15
  Copy the code below and paste it into the top of your main plugin's PHP file, right after the plugin's header comment:
@@ -77,9 +82,9 @@ Add marketing content to encourage your users to upgrade for your paid version:
77
  ```php
78
  <?php
79
  if ( my_prefix_fs()->is_not_paying() ) {
80
- echo '<section><h1>' . __('Awesome Premium Features', 'my-plugin-slug') . '</h1>';
81
  echo '<a href="' . my_prefix_fs()->get_upgrade_url() . '">' .
82
- __('Upgrade Now!', 'my-plugin-slug') .
83
  '</a>';
84
  echo '</section>';
85
  }
10
 
11
  **Below you'll find the integration instructions for our WordPress SDK.**
12
 
13
+ ## Code Documentation
14
+
15
+ You can find the SDK's PHP-Doc documentation here:
16
+ https://codedoc.pub/freemius/wordpress-sdk/master/
17
+
18
  ## Initializing the SDK
19
 
20
  Copy the code below and paste it into the top of your main plugin's PHP file, right after the plugin's header comment:
82
  ```php
83
  <?php
84
  if ( my_prefix_fs()->is_not_paying() ) {
85
+ echo '<section><h1>' . esc_html__('Awesome Premium Features', 'my-plugin-slug') . '</h1>';
86
  echo '<a href="' . my_prefix_fs()->get_upgrade_url() . '">' .
87
+ esc_html__('Upgrade Now!', 'my-plugin-slug') .
88
  '</a>';
89
  echo '</section>';
90
  }
freemius/assets/css/admin/account.css CHANGED
@@ -1 +1 @@
1
- #fs_account .postbox,#fs_account .widefat{max-width:700px}#fs_account h3{font-size:1.3em;padding:12px 12px 12px 15px;margin:0 0 12px 0;line-height:1.4;border-bottom:1px solid #F1F1F1}#fs_account i.dashicons{font-size:1.2em;height:1.2em;width:1.2em}#fs_account .fs-header-actions{position:absolute;top:17px;right:15px;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:15px;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}
1
+ #fs_account .postbox,#fs_account .widefat{max-width:700px}#fs_account h3{font-size:1.3em;padding:12px 15px;margin:0 0 12px 0;line-height:1.4;border-bottom:1px solid #F1F1F1}#fs_account i.dashicons{font-size:1.2em;height:1.2em;width:1.2em}#fs_account .button i.dashicons{vertical-align:middle}#fs_account .fs-header-actions{position:absolute;top:17px;right:15px;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}#fs_account_details .button-group{float:right}.rtl #fs_account .fs-header-actions{left:15px;right:auto}.fs-key-value-table{width:100%}.fs-key-value-table form{display:inline-block}.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 code{line-height:28px}.fs-key-value-table var,.fs-key-value-table code,.fs-key-value-table input[type="text"]{color:#0073AA;font-size:16px;background:none}.fs-key-value-table input[type="text"]{width:100%;font-weight:bold}label.fs-tag{background:#ffba00;color:#fff;display:inline-block;border-radius:3px;padding:5px;font-size:11px;line-height:11px;vertical-align:baseline}label.fs-tag.fs-warn{background:#ffba00}label.fs-tag.fs-success{background:#46b450}label.fs-tag.fs-error{background:#dc3232}#fs_addons h3{border:none;margin-bottom:0;padding:4px 5px}#fs_addons td{vertical-align:middle}#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}
freemius/assets/css/admin/add-ons.css CHANGED
@@ -1,2 +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}}
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;background-size:100% 100%;-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}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-tag{position:absolute;top:10px;right:0px;background:greenyellow;display:block;padding:2px 10px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.3);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.3);box-shadow:1px 1px 1px rgba(0,0,0,0.3);text-transform:uppercase;font-size:0.9em;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button{position:absolute;top:112px;right:10px}@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:1em 30px !important}#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{margin:-16px;border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan h3{margin-top:0;padding:20px;font-size:16px}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper{border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab{cursor:pointer;position:relative;padding:0 10px;font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab label{text-transform:uppercase;color:green;background:greenyellow;position:absolute;left:-1px;right:-1px;bottom:100%;border:1px solid darkgreen;padding:2px;text-align:center;font-size:0.9em;line-height:1em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab.nav-tab-active{cursor:default;background:#fffeec;border-bottom-color:#fffeec}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle h3{background:#fffeec;margin:0;padding-bottom:0;color:#0073aa}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .nav-tab-wrapper,#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .fs-billing-frequency{display:none}#plugin-information .plugin-information-pricing .fs-plan .fs-pricing-body{background:#fffeec;padding:20px}#plugin-information .plugin-information-pricing .fs-plan .button{width:100%;text-align:center;font-weight:bold;text-transform:uppercase;font-size:1.1em}#plugin-information .plugin-information-pricing .fs-plan label{white-space:nowrap}#plugin-information .plugin-information-pricing .fs-plan var{font-style:normal}#plugin-information .plugin-information-pricing .fs-plan .fs-billing-frequency,#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-align:center;display:block;font-weight:bold;margin-bottom:10px;text-transform:uppercase;background:#F3F3F3;padding:2px;border:1px solid #ccc}#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-transform:none;color:green;background:greenyellow}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms{font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms i{float:left;margin:0 0 0 -15px}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms li{margin:10px 0 0 0}#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}}
freemius/assets/css/admin/common.css CHANGED
@@ -1 +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-notice-body{margin:.5em 0;padding:2px}.fs-notice .fs-close{cursor:pointer;color:#aaa;float:right}.fs-notice .fs-close:hover{color:#666}.fs-notice .fs-close>*{margin-top:7px;display:inline-block}.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{float:left}.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'}
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-notice-body{margin:.5em 0;padding:2px}.fs-notice .fs-close{cursor:pointer;color:#aaa;float:right}.fs-notice .fs-close:hover{color:#666}.fs-notice .fs-close>*{margin-top:7px;display:inline-block}.fs-notice label.fs-plugin-title{background:rgba(0,0,0,0.3);color:#fff;padding:2px 10px;position:absolute;top:100%;bottom: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{float:left}.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: 500px){#fs_promo_tab{display:none}}@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'}
freemius/assets/css/admin/connect.css CHANGED
@@ -1 +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-primary.fs-loading:after{content:''}#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-primary.fs-loading:after{content:''}.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}
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 .fs-error{background:snow;color:#d3135a;border:1px solid #d3135a;-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);text-align:center;padding:5px;margin-bottom:10px}#fs_connect .fs-content p{margin:0;padding:0;font-size:1.2em}#fs_connect .fs-license-key-container{position:relative;width:280px;margin:10px auto 0 auto}#fs_connect .fs-license-key-container input{width:100%}#fs_connect .fs-license-key-container .dashicons{position:absolute;top:5px;right:5px}#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-primary.fs-loading:after{content:''}#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-license-sync-disclaimer{text-align:center;margin-top:0}#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-freemium-licensing{padding:8px;background:#777;color:#fff}#fs_connect .fs-freemium-licensing p{text-align:center;display:block;margin:0;padding:0}#fs_connect .fs-freemium-licensing a{color:#C2EEFF;text-decoration:underline}#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-primary.fs-loading:after{content:''}.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}
freemius/assets/css/admin/deactivation-feedback.css CHANGED
@@ -1 +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}
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,.fs-modal .fs-modal-dialog li.reason .internal-message{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,.fs-modal .internal-message{margin:3px 0 3px 22px}.fs-modal .reason-input input,.fs-modal .reason-input textarea,.fs-modal .internal-message input,.fs-modal .internal-message textarea{width:100%}.fs-modal li.reason.has-internal-message .internal-message{border:1px solid #ccc;padding:7px;display:none}body.has-fs-modal{overflow:hidden}#the-list .deactivate>.fs-slug{display:none}
freemius/assets/css/admin/debug.css ADDED
@@ -0,0 +1 @@
 
1
+ .switch{position:relative;display:inline-block;font-size:1.6em;font-weight:bold;color:#ccc;text-shadow:0px 1px 1px rgba(255,255,255,0.8);height:18px;padding:6px 6px 5px 6px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:4px;background:#ececec;box-shadow:0px 0px 4px rgba(0,0,0,0.1),inset 0px 1px 3px 0px rgba(0,0,0,0.1);cursor:pointer}.switch span{display:inline-block;width:35px;text-transform:uppercase}.switch span.on{color:#6bc406}.switch .toggle{position:absolute;top:1px;width:37px;height:25px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.3);border-radius:4px;background:#fff;background:-moz-linear-gradient(top, #ececec 0%, #fff 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ececec), color-stop(100%, #fff));background:-webkit-linear-gradient(top, #ececec 0%, #fff 100%);background:-o-linear-gradient(top, #ececec 0%, #fff 100%);background:-ms-linear-gradient(top, #ececec 0%, #fff 100%);background:linear-gradient(top, #ececec 0%, #fff 100%);box-shadow:inset 0px 1px 0px 0px rgba(255,255,255,0.5);z-index:999;-moz-transition:all 0.15s ease-in-out;-o-transition:all 0.15s ease-in-out;-ms-transition:all 0.15s ease-in-out;-webkit-transition:all 0.15s ease-in-out;transition:all 0.15s ease-in-out}.switch.on .toggle{left:2%}.switch.off .toggle{left:54%}.switch.round{padding:0px 20px;border-radius:40px}.switch.round .toggle{border-radius:40px;width:14px;height:14px}.switch.round.on .toggle{left:3%;background:#6bc406}.switch.round.off .toggle{left:58%}.switch-label{font-size:20px;line-height:31px;margin:0 5px}
freemius/assets/css/admin/dialog-boxes.css ADDED
@@ -0,0 +1,2 @@
 
 
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.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-header{border-bottom:#eeeeee solid 1px;background:#fbfbfb;padding:15px 20px;position:relative}.fs-modal .fs-modal-header h4{margin:0;padding:0;text-transform:uppercase;font-size:1.2em;font-weight:bold;color:#cacaca;text-shadow:1px 1px 1px #fff;letter-spacing:0.6px;-webkit-font-smoothing:antialiased}.fs-modal .fs-modal-header .fs-close{position:absolute;right:10px;top:12px;cursor:pointer;color:#bbb;-moz-border-radius:20px;-webkit-border-radius:20px;border-radius:20px;padding:3px;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;-ms-transition:all 0.2s ease-in-out;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.fs-modal .fs-modal-header .fs-close:hover{color:#fff;background:#aaa}.fs-modal .fs-modal-body{border-bottom:0}.fs-modal .fs-modal-body p{font-size:14px}.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>.notice.inline{margin:0;display:none}.fs-modal .fs-modal-panel:not(.active){display:none}.rtl .fs-modal .fs-modal-header .fs-close{right:auto;left:20px}body.has-fs-modal{overflow:hidden}.fs-modal.fs-modal-deactivation-feedback .reason-input,.fs-modal.fs-modal-deactivation-feedback .internal-message{margin:3px 0 3px 22px}.fs-modal.fs-modal-deactivation-feedback .reason-input input,.fs-modal.fs-modal-deactivation-feedback .reason-input textarea,.fs-modal.fs-modal-deactivation-feedback .internal-message input,.fs-modal.fs-modal-deactivation-feedback .internal-message textarea{width:100%}.fs-modal.fs-modal-deactivation-feedback li.reason.has-internal-message .internal-message{border:1px solid #ccc;padding:7px;display:none}@media (max-width: 650px){.fs-modal.fs-modal-deactivation-feedback li.reason li.reason{margin-bottom:10px}.fs-modal.fs-modal-deactivation-feedback li.reason li.reason .reason-input,.fs-modal.fs-modal-deactivation-feedback li.reason li.reason .internal-message{margin-left:29px}.fs-modal.fs-modal-deactivation-feedback li.reason li.reason label{display:table}.fs-modal.fs-modal-deactivation-feedback li.reason li.reason label>span{display:table-cell;font-size:1.3em}}.fs-modal.fs-modal-deactivation-feedback .anonymous-feedback-label{float:left}.fs-modal.fs-modal-deactivation-feedback .fs-modal-panel{margin-top:0 !important}.fs-modal.fs-modal-deactivation-feedback .fs-modal-panel h3{margin-top:0;line-height:1.5em}#the-list .deactivate>.fs-slug{display:none}.fs-modal.fs-modal-license-activation .fs-modal-body input.license_key{width:100%}.fs-modal.fs-modal-license-key-resend .fs-modal-body .input-container>.email-address-container{overflow:hidden;padding-right:2px}.fs-modal.fs-modal-license-key-resend .fs-modal-body input.email-address{width:100%}.fs-modal.fs-modal-license-key-resend .fs-modal-body .button-container{float:right;margin-left:7px}@media (max-width: 650px){.fs-modal.fs-modal-license-key-resend .fs-modal-body .button-container{margin-top:2px}}
2
+ .rtl .fs-modal.fs-modal-license-key-resend .fs-modal-body .input-container>.email-address-container{padding-left:2px;padding-right:0}.rtl .fs-modal.fs-modal-license-key-resend .fs-modal-body .button-container{float:left;margin-right:7px;margin-left:0}a.show-license-resend-modal{margin-top:4px;display:inline-block}
freemius/assets/css/admin/license-activation.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.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 .license-activation-message{margin:0;display:none}.fs-modal .fs-modal-body input.license_key{width:100%}.fs-modal .fs-modal-body p{font-size:14px}.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}body.has-fs-modal{overflow:hidden}
freemius/assets/img/icon.png ADDED
Binary file
freemius/assets/js/postmessage.js CHANGED
@@ -24,10 +24,13 @@
24
  }
25
  }
26
  }, _base_url);
27
- };
 
 
 
28
 
29
  return {
30
- init : function (url)
31
  {
32
  _base_url = url;
33
  _init();
@@ -36,6 +39,16 @@
36
  FS.PostMessage.receiveOnce('forward', function (data){
37
  window.location = data.url;
38
  });
 
 
 
 
 
 
 
 
 
 
39
  },
40
  init_child : function ()
41
  {
@@ -46,8 +59,14 @@
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;
@@ -56,6 +75,12 @@
56
  height: diff + $(wrapper).outerHeight(true)
57
  });
58
  },
 
 
 
 
 
 
59
  post : function (type, data, iframe)
60
  {
61
  console.debug('PostMessage.post', type);
24
  }
25
  }
26
  }, _base_url);
27
+ },
28
+ _hasParent = ('' !== _parent_url),
29
+ $window = $(window),
30
+ $html = $('html');
31
 
32
  return {
33
+ init : function (url, iframes)
34
  {
35
  _base_url = url;
36
  _init();
39
  FS.PostMessage.receiveOnce('forward', function (data){
40
  window.location = data.url;
41
  });
42
+
43
+ iframes = iframes || [];
44
+
45
+ if (iframes.length > 0) {
46
+ $window.on('scroll', function () {
47
+ for (var i = 0; i < iframes.length; i++) {
48
+ FS.PostMessage.postScroll(iframes[i]);
49
+ }
50
+ });
51
+ }
52
  },
53
  init_child : function ()
54
  {
59
  // Post height of a child right after window is loaded.
60
  $(window).bind('load', function () {
61
  FS.PostMessage.postHeight();
 
62
 
63
+ // Post message that window was loaded.
64
+ FS.PostMessage.post('loaded');
65
+ });
66
+ },
67
+ hasParent : function ()
68
+ {
69
+ return _hasParent;
70
  },
71
  postHeight : function (diff, wrapper) {
72
  diff = diff || 0;
75
  height: diff + $(wrapper).outerHeight(true)
76
  });
77
  },
78
+ postScroll : function (iframe) {
79
+ this.post('scroll', {
80
+ top: $window.scrollTop(),
81
+ height: ($window.height() - parseFloat($html.css('paddingTop')) - parseFloat($html.css('marginTop')))
82
+ }, iframe);
83
+ },
84
  post : function (type, data, iframe)
85
  {
86
  console.debug('PostMessage.post', type);
freemius/assets/scss/_mixins.scss CHANGED
@@ -200,14 +200,6 @@ $useIEFilters: 0;
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;
200
  filter: alpha(opacity=$opacity-ie); //IE8
201
  }
202
 
 
 
 
 
 
 
 
 
203
  @mixin size($width, $height: $width)
204
  {
205
  width: $width;
freemius/assets/scss/admin/_deactivation-feedback.scss ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../colors";
2
+
3
+ .fs-modal.fs-modal-deactivation-feedback {
4
+ .reason-input, .internal-message {
5
+ margin: 3px 0 3px 22px;
6
+
7
+ input, textarea {
8
+ width: 100%;
9
+ }
10
+ }
11
+
12
+ li.reason {
13
+ &.has-internal-message .internal-message {
14
+ border: 1px solid lighten($darkest-color, 80%);
15
+ padding: 7px;
16
+ display: none;
17
+ }
18
+
19
+ @media (max-width: 650px) {
20
+ li.reason {
21
+ margin-bottom: 10px;
22
+
23
+ .reason-input, .internal-message {
24
+ margin-left: 29px;
25
+ }
26
+
27
+ label {
28
+ display: table;
29
+
30
+ > span {
31
+ display: table-cell;
32
+ font-size: 1.3em;
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+
39
+ .anonymous-feedback-label {
40
+ float: left;
41
+ }
42
+
43
+ .fs-modal-panel {
44
+ margin-top: 0 !important;
45
+
46
+ h3 {
47
+ margin-top: 0;
48
+ line-height: 1.5em;
49
+ }
50
+ }
51
+ }
52
+
53
+ #the-list .deactivate > .fs-slug {
54
+ display: none;
55
+ }
freemius/assets/scss/admin/_license-activation.scss ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ .fs-modal.fs-modal-license-activation {
2
+ .fs-modal-body {
3
+ input.license_key {
4
+ width: 100%;
5
+ }
6
+ }
7
+ }
freemius/assets/scss/admin/_license-key-resend.scss ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .fs-modal.fs-modal-license-key-resend {
2
+ .fs-modal-body {
3
+ .input-container > .email-address-container {
4
+ overflow: hidden;
5
+ padding-right: 2px;
6
+ }
7
+
8
+ input.email-address {
9
+ width: 100%;
10
+ }
11
+
12
+ .button-container {
13
+ float: right;
14
+ margin-left: 7px;
15
+
16
+ @media (max-width: 650px) {
17
+ margin-top: 2px;
18
+ }
19
+ }
20
+ }
21
+ }
22
+
23
+ .rtl
24
+ {
25
+ .fs-modal.fs-modal-license-key-resend {
26
+ .fs-modal-body {
27
+ .input-container > .email-address-container {
28
+ padding-left: 2px;
29
+ padding-right: 0;
30
+ }
31
+
32
+ .button-container {
33
+ float: left;
34
+ margin-right: 7px;
35
+ margin-left: 0;
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ a.show-license-resend-modal {
42
+ margin-top: 4px;
43
+ display: inline-block;
44
+ }
freemius/assets/scss/admin/_modal-common.scss ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../colors";
2
+ @import "../mixins";
3
+
4
+ .fs-modal {
5
+ position: fixed;
6
+ overflow: auto;
7
+ height: 100%;
8
+ width: 100%;
9
+ top: 0;
10
+ z-index: 100000;
11
+ display: none;
12
+ background: rgba(0, 0, 0, 0.6);
13
+
14
+ .fs-modal-dialog {
15
+ background: transparent;
16
+ position: absolute;
17
+ left: 50%;
18
+ margin-left: -298px;
19
+ padding-bottom: 30px;
20
+ top: -100%;
21
+ z-index: 100001;
22
+ width: 596px;
23
+
24
+ @media (max-width: 650px) {
25
+ margin-left: -50%;
26
+ box-sizing: border-box;
27
+ padding-left: 10px;
28
+ padding-right: 10px;
29
+ width: 100%;
30
+
31
+ .fs-modal-panel > h3 > strong {
32
+ font-size: 1.3em;
33
+ }
34
+ }
35
+ }
36
+
37
+ &.active {
38
+ display: block;
39
+
40
+ &:before {
41
+ display: block;
42
+ }
43
+
44
+ .fs-modal-dialog {
45
+ top: 10%;
46
+ }
47
+ }
48
+
49
+ .fs-modal-body,
50
+ .fs-modal-footer {
51
+ border: 0;
52
+ background: #fefefe;
53
+ padding: 20px;
54
+ }
55
+
56
+ .fs-modal-header {
57
+ border-bottom: #eeeeee solid 1px;
58
+ background: #fbfbfb;
59
+ padding: 15px 20px;
60
+ position: relative;
61
+ // z-index: 2;
62
+
63
+ h4 {
64
+ margin: 0;
65
+ padding: 0;
66
+ text-transform: uppercase;
67
+ font-size: 1.2em;
68
+ font-weight: bold;
69
+ color: #cacaca;
70
+ text-shadow: 1px 1px 1px #fff;
71
+ letter-spacing: 0.6px;
72
+ -webkit-font-smoothing: antialiased;
73
+ }
74
+
75
+ .fs-close {
76
+ position: absolute;
77
+ right: 10px;
78
+ top: 12px;
79
+ cursor: pointer;
80
+ color: #bbb;
81
+ @include border-radius(20px);
82
+ padding: 3px;
83
+ @include transition(all 0.2s ease-in-out);
84
+
85
+ &:hover {
86
+ color: #fff;
87
+ background: #aaa;
88
+ }
89
+ }
90
+ }
91
+
92
+ .fs-modal-body {
93
+ border-bottom: 0;
94
+
95
+ p {
96
+ font-size: 14px;
97
+ }
98
+
99
+ h2 {
100
+ font-size: 20px;
101
+ }
102
+
103
+ > div {
104
+ margin-top: 10px;
105
+
106
+ h2 {
107
+ font-weight: bold;
108
+ font-size: 20px;
109
+ margin-top: 0;
110
+ }
111
+ }
112
+ }
113
+
114
+ .fs-modal-footer {
115
+ border-top: #eeeeee solid 1px;
116
+ text-align: right;
117
+
118
+ > .button {
119
+ margin: 0 7px;
120
+
121
+ &:first-child {
122
+ margin: 0;
123
+ }
124
+ }
125
+ }
126
+
127
+ .fs-modal-panel {
128
+ > .notice.inline {
129
+ margin: 0;
130
+ display: none;
131
+ }
132
+
133
+ &:not(.active) {
134
+ display: none;
135
+ }
136
+ }
137
+ }
138
+
139
+ .rtl
140
+ {
141
+ .fs-modal {
142
+ .fs-modal-header {
143
+ .fs-close {
144
+ right: auto;
145
+ left: 20px;
146
+ }
147
+ }
148
+ }
149
+ }
150
+
151
+ body.has-fs-modal {
152
+ overflow: hidden;
153
+ }
freemius/assets/scss/admin/account.scss CHANGED
@@ -9,7 +9,7 @@
9
  h3
10
  {
11
  font-size: 1.3em;
12
- padding: 12px 12px 12px 15px;
13
  margin: 0 0 12px 0;
14
  line-height: 1.4;
15
  border-bottom: 1px solid #F1F1F1;
@@ -22,6 +22,14 @@
22
  width: 1.2em;
23
  }
24
 
 
 
 
 
 
 
 
 
25
  .fs-header-actions
26
  {
27
  position: absolute;
@@ -50,6 +58,10 @@
50
  }
51
  }
52
 
 
 
 
 
53
  .rtl #fs_account .fs-header-actions
54
  {
55
  left: 15px;
@@ -65,18 +77,6 @@
65
  display: inline-block;
66
  }
67
 
68
- td label
69
- {
70
- background: orange;
71
- color: #fff;
72
- display: inline-block;
73
- border-radius: 3px;
74
- padding: 5px;
75
- font-size: 11px;
76
- line-height: 11px;
77
- vertical-align: baseline;
78
- }
79
-
80
  tr
81
  {
82
  td:first-child
@@ -110,16 +110,62 @@
110
  padding: 10px;
111
  }
112
 
113
- var, code
 
 
 
 
114
  {
115
  color: #0073AA;
116
  font-size: 16px;
117
  background: none;
118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
 
121
  #fs_addons
122
  {
 
 
 
 
 
 
 
 
 
 
 
 
123
  td:first-child,
124
  th:first-child
125
  {
9
  h3
10
  {
11
  font-size: 1.3em;
12
+ padding: 12px 15px;
13
  margin: 0 0 12px 0;
14
  line-height: 1.4;
15
  border-bottom: 1px solid #F1F1F1;
22
  width: 1.2em;
23
  }
24
 
25
+ .button
26
+ {
27
+ i.dashicons
28
+ {
29
+ vertical-align: middle;
30
+ }
31
+ }
32
+
33
  .fs-header-actions
34
  {
35
  position: absolute;
58
  }
59
  }
60
 
61
+ #fs_account_details .button-group {
62
+ float: right;
63
+ }
64
+
65
  .rtl #fs_account .fs-header-actions
66
  {
67
  left: 15px;
77
  display: inline-block;
78
  }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  tr
81
  {
82
  td:first-child
110
  padding: 10px;
111
  }
112
 
113
+ code {
114
+ line-height: 28px;
115
+ }
116
+
117
+ var, code, input[type="text"]
118
  {
119
  color: #0073AA;
120
  font-size: 16px;
121
  background: none;
122
  }
123
+
124
+ input[type="text"] {
125
+ width: 100%;
126
+ font-weight: bold;
127
+ }
128
+ }
129
+
130
+ label.fs-tag
131
+ {
132
+ background: #ffba00;
133
+ color: #fff;
134
+ display: inline-block;
135
+ border-radius: 3px;
136
+ padding: 5px;
137
+ font-size: 11px;
138
+ line-height: 11px;
139
+ vertical-align: baseline;
140
+
141
+ &.fs-warn
142
+ {
143
+ background: #ffba00;
144
+ }
145
+ &.fs-success
146
+ {
147
+ background: #46b450;
148
+ }
149
+ &.fs-error
150
+ {
151
+ background: #dc3232;
152
+ }
153
  }
154
 
155
  #fs_addons
156
  {
157
+ h3
158
+ {
159
+ border: none;
160
+ margin-bottom: 0;
161
+ padding: 4px 5px;
162
+ }
163
+
164
+ td
165
+ {
166
+ vertical-align: middle;
167
+ }
168
+
169
  td:first-child,
170
  th:first-child
171
  {
freemius/assets/scss/admin/add-ons.scss CHANGED
@@ -8,76 +8,75 @@
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
@@ -88,10 +87,34 @@
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
 
@@ -149,7 +172,7 @@
149
  .fs-selling-points
150
  {
151
  padding-bottom: 10px;
152
- border-bottom: 1px solid #ddd;
153
 
154
  ul
155
  {
@@ -157,22 +180,22 @@
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
  }
@@ -184,23 +207,23 @@
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
 
@@ -215,28 +238,134 @@
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
 
@@ -247,12 +376,14 @@
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;
@@ -260,10 +391,10 @@
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
 
@@ -272,16 +403,16 @@
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
  }
@@ -297,15 +428,14 @@
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
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
  li
50
  {
51
+ list-style: none;
52
  line-height: 18px;
53
+ padding: 0 15px;
54
+ width: 100%;
55
+ display: block;
56
  @include box-sizing(border-box);
57
  }
58
 
59
  .fs-card-banner
60
  {
61
+ padding: 0;
62
+ margin: 0;
63
+ line-height: 0;
64
+ display: block;
65
+ height: 100px;
66
  background-repeat: repeat-x;
67
+ background-size: 100% 100%;
68
  @include transition(all, 0.15s);
69
  }
70
 
71
  .fs-title
72
  {
73
+ margin: 10px 0 0 0;
74
+ height: 18px;
75
+ overflow: hidden;
76
+ color: #000;
77
+ white-space: nowrap;
78
  text-overflow: ellipsis;
79
+ font-weight: bold;
80
  }
81
 
82
  .fs-offer
87
  .fs-description
88
  {
89
  background-color: #f9f9f9;
90
+ padding: 10px 15px 100px 15px;
91
+ border-top: 1px solid #eee;
92
+ margin: 0 0 10px 0;
93
+ color: #777;
94
+ }
95
+
96
+ .fs-tag
97
+ {
98
+ position: absolute;
99
+ top: 10px;
100
+ right: 0px;
101
+ background: greenyellow;
102
+ display: block;
103
+ padding: 2px 10px;
104
+ @include box-shadow(1px 1px 1px rgba(0,0,0,0.3));
105
+ text-transform: uppercase;
106
+ font-size: 0.9em;
107
+ font-weight: bold;
108
+ }
109
+
110
+ .fs-cta
111
+ {
112
+ .button
113
+ {
114
+ position: absolute;
115
+ top: 112px;
116
+ right: 10px;
117
+ }
118
  }
119
  }
120
 
172
  .fs-selling-points
173
  {
174
  padding-bottom: 10px;
175
+ border-bottom: 1px solid #ddd;
176
 
177
  ul
178
  {
180
 
181
  li
182
  {
183
+ padding: 0;
184
  list-style: none outside none;
185
 
186
  i.dashicons
187
  {
188
+ color: $fs-logo-green-color;
189
+ font-size: 3em;
190
  vertical-align: middle;
191
+ line-height: 30px;
192
+ float: left;
193
+ margin: 0 0 0 -15px;
194
  }
195
 
196
  h3
197
  {
198
+ margin: 1em 30px !important;
199
  }
200
  }
201
  }
207
  ul
208
  {
209
  list-style: none;
210
+ margin: 0;
211
 
212
  li
213
  {
214
+ width: 225px;
215
+ height: 225px;
216
+ float: left;
217
  margin-bottom: 20px;
218
  @include box-sizing(content-box);
219
 
220
  a
221
  {
222
+ display: block;
223
+ width: 100%;
224
+ height: 100%;
225
+ border: 1px solid;
226
+ @include box-shadow(1px 1px 1px rgba(0, 0, 0, 0.2));
227
  background-size: cover;
228
  }
229
 
238
 
239
  .plugin-information-pricing
240
  {
241
+ $pricing_color: #FFFEEC;
242
+ $borders_color: #DDD;
243
+ margin: -16px;
244
+ // padding: 20px;
245
+ border-bottom: 1px solid $borders_color;
246
 
247
+ .fs-plan
248
  {
 
 
249
 
250
+ h3
251
+ {
252
+ margin-top: 0;
253
+ padding: 20px;
254
+ font-size: 16px;
255
+ }
 
 
256
 
257
+ .nav-tab-wrapper
258
+ {
259
+ border-bottom: 1px solid $borders_color;
260
+
261
+ .nav-tab
262
+ {
263
+ cursor: pointer;
264
+ position: relative;
265
+ padding: 0 10px;
266
+ font-size: 0.9em;
267
+
268
+ label
269
+ {
270
+ text-transform: uppercase;
271
+ color: green;
272
+ background: greenyellow;
273
+ position: absolute;
274
+ left: -1px;
275
+ right: -1px;
276
+ bottom: 100%;
277
+ border: 1px solid darkgreen;
278
+ padding: 2px;
279
+ text-align: center;
280
+ font-size: 0.9em;
281
+ line-height: 1em;
282
+ }
283
+
284
+ &.nav-tab-active
285
+ {
286
+ cursor: default;
287
+ background: $pricing_color;
288
+ border-bottom-color: $pricing_color;
289
+ }
290
+ }
291
+ }
292
+
293
+ &.fs-single-cycle
294
+ {
295
+ h3
296
+ {
297
+ background: $pricing_color;
298
+ margin: 0;
299
+ padding-bottom: 0;
300
+ color: #0073aa;
301
+ }
302
+
303
+ .nav-tab-wrapper,
304
+ .fs-billing-frequency
305
+ {
306
+ display: none;
307
+ }
308
+ }
309
+
310
+ .fs-pricing-body
311
+ {
312
+ background: $pricing_color;
313
+ padding: 20px;
314
+ }
315
+
316
+ .button
317
+ {
318
+ width: 100%;
319
+ text-align: center;
320
+ font-weight: bold;
321
+ text-transform: uppercase;
322
+ font-size: 1.1em;
323
+ }
324
+
325
+ label
326
+ {
327
+ white-space: nowrap;
328
+ }
329
+
330
+ var {
331
+ font-style: normal;
332
+ }
333
+
334
+ .fs-billing-frequency,
335
+ .fs-annual-discount
336
+ {
337
+ text-align: center;
338
+ display: block;
339
+ font-weight: bold;
340
+ margin-bottom: 10px;
341
+ text-transform: uppercase;
342
+ background: #F3F3F3;
343
+ padding: 2px;
344
+ border: 1px solid #ccc;
345
+ }
346
+
347
+ .fs-annual-discount
348
+ {
349
+ text-transform: none;
350
+ color: green;
351
+ background: greenyellow;
352
+ }
353
+
354
+ ul.fs-trial-terms
355
+ {
356
+ font-size: 0.9em;
357
+
358
+ i
359
+ {
360
+ float: left;
361
+ margin: 0 0 0 -15px;
362
+ }
363
+
364
+ li
365
+ {
366
+ margin: 10px 0 0 0;
367
+ }
368
+ }
369
  }
370
  }
371
 
376
  margin: -20px -26px;
377
  }
378
 
379
+ table
380
+ {
381
+ width: 100%;
382
+ border-spacing: 0;
383
  border-collapse: separate;
384
 
385
+ thead
386
+ {
387
  th
388
  {
389
  padding: 10px 0;
391
 
392
  .fs-price
393
  {
394
+ color: $fs-logo-green-color;
395
  font-weight: normal;
396
+ display: block;
397
+ text-align: center;
398
  }
399
  }
400
 
403
  td
404
  {
405
  border-top: 1px solid #ccc;
406
+ padding: 10px 0;
407
  text-align: center;
408
+ width: 100px;
409
+ color: $fs-logo-green-color;
410
 
411
  &:first-child
412
  {
413
+ text-align: left;
414
+ width: auto;
415
+ color: inherit;
416
  padding-left: 26px;
417
  }
418
  }
428
 
429
  .dashicons-yes
430
  {
431
+ width: 30px;
432
+ height: 30px;
433
  font-size: 30px;
434
  }
435
  }
436
  }
437
 
438
+ @media screen and (max-width: 961px) {
 
439
  #fs_addons
440
  {
441
  .fs-cards-list
freemius/assets/scss/admin/common.scss CHANGED
@@ -59,8 +59,8 @@
59
  color: #fff;
60
  padding: 2px 10px;
61
  position: absolute;
62
- bottom: -22px;
63
- top: auto;
64
  right: auto;
65
  @include border-radius(0 0 3px 3px);
66
  left: 10px;
@@ -108,6 +108,12 @@
108
  }
109
  }
110
 
 
 
 
 
 
 
111
  @media screen and (max-width: 782px) {
112
  .fs-secure-notice
113
  {
59
  color: #fff;
60
  padding: 2px 10px;
61
  position: absolute;
62
+ top: 100%;
63
+ bottom: auto;
64
  right: auto;
65
  @include border-radius(0 0 3px 3px);
66
  left: 10px;
108
  }
109
  }
110
 
111
+ @media screen and (max-width:500px) {
112
+ #fs_promo_tab {
113
+ display: none;
114
+ }
115
+ }
116
+
117
  @media screen and (max-width: 782px) {
118
  .fs-secure-notice
119
  {
freemius/assets/scss/admin/connect.scss CHANGED
@@ -1,421 +1,471 @@
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
- &.fs-loading
61
- {
62
- &:after
63
- {
64
- content: '';
65
- }
66
- }
67
- }
68
-
69
- &.button-secondary
70
- {
71
- float: right;
72
- }
73
- }
74
-
75
- // .fs-skip
76
- // {
77
- // line-height: 38px;
78
- // vertical-align: middle;
79
- // text-decoration: none;
80
- // margin-left: 10px;
81
- // }
82
- }
83
-
84
- &.fs-anonymous-disabled
85
- {
86
- .fs-actions
87
- {
88
- .button.button-primary
89
- {
90
- width: 100%;
91
- }
92
- }
93
- }
94
-
95
- .fs-permissions
96
- {
97
- padding: 10px 20px;
98
- background: #FEFEFE;
99
- // background: #F1F1F1;
100
- @include transition(background 0.5s ease);
101
-
102
- .fs-trigger
103
- {
104
- font-size: 0.9em;
105
- text-decoration: none;
106
- text-align: center;
107
- display: block;
108
- }
109
-
110
- ul
111
- {
112
- height: 0;
113
- overflow: hidden;
114
- margin: 0;
115
-
116
- li
117
- {
118
- margin-bottom: 12px;
119
-
120
- &:last-child
121
- {
122
- margin-bottom: 0;
123
- }
124
-
125
- i.dashicons
126
- {
127
- float: left;
128
- font-size: 40px;
129
- width: 40px;
130
- height: 40px;
131
- }
132
-
133
- div
134
- {
135
- margin-left: 55px;
136
-
137
- span
138
- {
139
- font-weight: bold;
140
- text-transform: uppercase;
141
- color: #23282d;
142
- }
143
-
144
- p
145
- {
146
- margin: 2px 0 0 0;
147
- }
148
- }
149
- }
150
- }
151
-
152
- &.fs-open
153
- {
154
- background: #fff;
155
-
156
- ul
157
- {
158
- height: auto;
159
- margin: 20px 20px 10px 20px;
160
- }
161
- }
162
-
163
- @media screen and (max-width: ($form_width - 1)) {
164
- background: #fff;
165
-
166
- .fs-trigger
167
- {
168
- display: none;
169
- }
170
-
171
- ul
172
- {
173
- height: auto;
174
- margin: 20px;
175
- }
176
- }
177
- }
178
-
179
- $icon_size: 80px;
180
- $wp_logo_padding: $icon_size / 10;
181
- $icons_top: 10px;
182
-
183
- .fs-visual
184
- {
185
- padding: 12px;
186
- line-height: 0;
187
- background: #fafafa;
188
- height: $icon_size;
189
- position: relative;
190
-
191
- .fs-site-icon
192
- {
193
- position: absolute;
194
- left: 20px;
195
- top: $icons_top;
196
- }
197
-
198
- .fs-connect-logo
199
- {
200
- position: absolute;
201
- right: 20px;
202
- top: $icons_top;
203
- }
204
-
205
- .fs-plugin-icon
206
- {
207
- position: absolute;
208
- top: $icons_top;
209
- left: 50%;
210
- margin-left: - ($icon_size / 2);
211
- }
212
-
213
- .fs-plugin-icon,
214
- .fs-site-icon,
215
- img,
216
- object
217
- {
218
- width: $icon_size;
219
- height: $icon_size;
220
- }
221
-
222
- .dashicons-wordpress
223
- {
224
- font-size: $icon_size - ($wp_logo_padding * 2);
225
- background: $wordpress_color;
226
- color: #fff;
227
- width: $icon_size - ($wp_logo_padding * 2);
228
- height: $icon_size - ($wp_logo_padding * 2);
229
- padding: $wp_logo_padding;
230
- }
231
-
232
- .dashicons-plus
233
- {
234
- position: absolute;
235
- top: 50%;
236
- font-size: 30px;
237
- margin-top: -10px;
238
- color: #bbb;
239
-
240
- &.fs-first
241
- {
242
- left: 28%;
243
- }
244
- &.fs-second
245
- {
246
- left: 65%;
247
- }
248
- }
249
-
250
- .fs-plugin-icon,
251
- .fs-connect-logo,
252
- .fs-site-icon
253
- {
254
- border: 1px solid #ccc;
255
- padding: 1px;
256
- background: #fff;
257
- }
258
- }
259
-
260
- .fs-terms
261
- {
262
- text-align: center;
263
- font-size: 0.85em;
264
- padding: 5px;
265
- background: rgba(0, 0, 0, 0.05);
266
-
267
- &, a
268
- {
269
- color: #999;
270
- }
271
-
272
- a
273
- {
274
- text-decoration: none;
275
- }
276
- }
277
- }
278
-
279
- .rtl
280
- {
281
- #fs_connect
282
- {
283
- .fs-actions
284
- {
285
- padding: 10px 20px;
286
- background: #C0C7CA;
287
-
288
- .button
289
- {
290
- .dashicons
291
- {
292
- font-size: 37px;
293
- margin-left: -8px;
294
- margin-right: 12px;
295
- }
296
-
297
- &.button-primary
298
- {
299
- &:after
300
- {
301
- content: ' \000bb';
302
- }
303
-
304
- &.fs-loading
305
- {
306
- &:after
307
- {
308
- content: '';
309
- }
310
- }
311
- }
312
-
313
- &.button-secondary
314
- {
315
- float: left;
316
- }
317
- }
318
- }
319
-
320
- .fs-permissions
321
- {
322
- ul
323
- {
324
- li
325
- {
326
- div
327
- {
328
- margin-right: 55px;
329
- margin-left: 0;
330
- }
331
-
332
- i.dashicons
333
- {
334
- float: right;
335
- }
336
-
337
- }
338
- }
339
- }
340
-
341
- .fs-visual
342
- {
343
- .fs-site-icon
344
- {
345
- right: 20px;
346
- left: auto;
347
- }
348
-
349
- .fs-connect-logo
350
- {
351
- right: auto;
352
- left: 20px;
353
- }
354
- }
355
- }
356
- }
357
-
358
- .wp-pointer-content
359
- {
360
- #fs_connect
361
- {
362
- margin: 0;
363
- @include box-shadow(none);
364
- }
365
- }
366
-
367
- .fs-opt-in-pointer
368
- {
369
- .wp-pointer-content
370
- {
371
- padding: 0;
372
- }
373
-
374
- &.wp-pointer-top
375
- {
376
- .wp-pointer-arrow
377
- {
378
- border-bottom-color: #dfdfdf;
379
- }
380
- .wp-pointer-arrow-inner
381
- {
382
- border-bottom-color: #fafafa;
383
- }
384
- }
385
-
386
- &.wp-pointer-bottom
387
- {
388
- .wp-pointer-arrow
389
- {
390
- border-top-color: #dfdfdf;
391
- }
392
- .wp-pointer-arrow-inner
393
- {
394
- border-top-color: #fafafa;
395
- }
396
- }
397
-
398
- &.wp-pointer-left
399
- {
400
- .wp-pointer-arrow
401
- {
402
- border-right-color: #dfdfdf;
403
- }
404
- .wp-pointer-arrow-inner
405
- {
406
- border-right-color: #fafafa;
407
- }
408
- }
409
-
410
- &.wp-pointer-right
411
- {
412
- .wp-pointer-arrow
413
- {
414
- border-left-color: #dfdfdf;
415
- }
416
- .wp-pointer-arrow-inner
417
- {
418
- border-left-color: #fafafa;
419
- }
420
- }
421
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ .fs-error {
23
+ background: snow;
24
+ color: $fs-logo-magenta-color;
25
+ border: 1px solid $fs-logo-magenta-color;
26
+ @include box-shadow(0 1px 1px 0 rgba(0,0,0,.1));
27
+ text-align: center;
28
+ padding: 5px;
29
+ margin-bottom: 10px;
30
+ }
31
+
32
+ p
33
+ {
34
+ margin: 0;
35
+ padding: 0;
36
+ font-size: 1.2em;
37
+ }
38
+ }
39
+
40
+ .fs-license-key-container {
41
+ position: relative;
42
+ width: 280px;
43
+ margin: 10px auto 0 auto;
44
+
45
+ input {
46
+ width: 100%;
47
+ }
48
+
49
+ .dashicons {
50
+ position: absolute;
51
+ top: 5px;
52
+ right: 5px;
53
+ }
54
+ }
55
+
56
+ .fs-actions
57
+ {
58
+ padding: 10px 20px;
59
+ background: #C0C7CA;
60
+
61
+ .button
62
+ {
63
+ padding: 0 10px 1px;
64
+ line-height: 35px;
65
+ height: 37px;
66
+ font-size: 16px;
67
+ margin-bottom: 0;
68
+
69
+ .dashicons
70
+ {
71
+ font-size: 37px;
72
+ margin-left: -8px;
73
+ margin-right: 12px;
74
+ }
75
+
76
+ &.button-primary
77
+ {
78
+ padding-right: 15px;
79
+ padding-left: 15px;
80
+
81
+ &:after
82
+ {
83
+ content: ' \279C';
84
+ }
85
+
86
+ &.fs-loading
87
+ {
88
+ &:after
89
+ {
90
+ content: '';
91
+ }
92
+ }
93
+ }
94
+
95
+ &.button-secondary
96
+ {
97
+ float: right;
98
+ }
99
+ }
100
+
101
+ // .fs-skip
102
+ // {
103
+ // line-height: 38px;
104
+ // vertical-align: middle;
105
+ // text-decoration: none;
106
+ // margin-left: 10px;
107
+ // }
108
+ }
109
+
110
+ &.fs-anonymous-disabled
111
+ {
112
+ .fs-actions
113
+ {
114
+ .button.button-primary
115
+ {
116
+ width: 100%;
117
+ }
118
+ }
119
+ }
120
+
121
+ .fs-permissions
122
+ {
123
+ padding: 10px 20px;
124
+ background: #FEFEFE;
125
+ // background: #F1F1F1;
126
+ @include transition(background 0.5s ease);
127
+
128
+ .fs-license-sync-disclaimer {
129
+ text-align: center;
130
+ margin-top: 0;
131
+ }
132
+
133
+ .fs-trigger
134
+ {
135
+ font-size: 0.9em;
136
+ text-decoration: none;
137
+ text-align: center;
138
+ display: block;
139
+ }
140
+
141
+ ul
142
+ {
143
+ height: 0;
144
+ overflow: hidden;
145
+ margin: 0;
146
+
147
+ li
148
+ {
149
+ margin-bottom: 12px;
150
+
151
+ &:last-child
152
+ {
153
+ margin-bottom: 0;
154
+ }
155
+
156
+ i.dashicons
157
+ {
158
+ float: left;
159
+ font-size: 40px;
160
+ width: 40px;
161
+ height: 40px;
162
+ }
163
+
164
+ div
165
+ {
166
+ margin-left: 55px;
167
+
168
+ span
169
+ {
170
+ font-weight: bold;
171
+ text-transform: uppercase;
172
+ color: #23282d;
173
+ }
174
+
175
+ p
176
+ {
177
+ margin: 2px 0 0 0;
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ &.fs-open
184
+ {
185
+ background: #fff;
186
+
187
+ ul
188
+ {
189
+ height: auto;
190
+ margin: 20px 20px 10px 20px;
191
+ }
192
+ }
193
+
194
+ @media screen and (max-width: ($form_width - 1)) {
195
+ background: #fff;
196
+
197
+ .fs-trigger
198
+ {
199
+ display: none;
200
+ }
201
+
202
+ ul
203
+ {
204
+ height: auto;
205
+ margin: 20px;
206
+ }
207
+ }
208
+ }
209
+
210
+ .fs-freemium-licensing {
211
+ padding: 8px;
212
+ // background: #0085BA;
213
+ background: #777;
214
+ color: #fff;
215
+
216
+ p {
217
+ text-align: center;
218
+ display: block;
219
+ margin: 0;
220
+ padding: 0;
221
+ }
222
+
223
+ a {
224
+ color: #C2EEFF;
225
+ text-decoration: underline;
226
+ }
227
+ }
228
+
229
+ $icon_size: 80px;
230
+ $wp_logo_padding: $icon_size / 10;
231
+ $icons_top: 10px;
232
+
233
+ .fs-visual
234
+ {
235
+ padding: 12px;
236
+ line-height: 0;
237
+ background: #fafafa;
238
+ height: $icon_size;
239
+ position: relative;
240
+
241
+ .fs-site-icon
242
+ {
243
+ position: absolute;
244
+ left: 20px;
245
+ top: $icons_top;
246
+ }
247
+
248
+ .fs-connect-logo
249
+ {
250
+ position: absolute;
251
+ right: 20px;
252
+ top: $icons_top;
253
+ }
254
+
255
+ .fs-plugin-icon
256
+ {
257
+ position: absolute;
258
+ top: $icons_top;
259
+ left: 50%;
260
+ margin-left: - ($icon_size / 2);
261
+ }
262
+
263
+ .fs-plugin-icon,
264
+ .fs-site-icon,
265
+ img,
266
+ object
267
+ {
268
+ width: $icon_size;
269
+ height: $icon_size;
270
+ }
271
+
272
+ .dashicons-wordpress
273
+ {
274
+ font-size: $icon_size - ($wp_logo_padding * 2);
275
+ background: $wordpress_color;
276
+ color: #fff;
277
+ width: $icon_size - ($wp_logo_padding * 2);
278
+ height: $icon_size - ($wp_logo_padding * 2);
279
+ padding: $wp_logo_padding;
280
+ }
281
+
282
+ .dashicons-plus
283
+ {
284
+ position: absolute;
285
+ top: 50%;
286
+ font-size: 30px;
287
+ margin-top: -10px;
288
+ color: #bbb;
289
+
290
+ &.fs-first
291
+ {
292
+ left: 28%;
293
+ }
294
+ &.fs-second
295
+ {
296
+ left: 65%;
297
+ }
298
+ }
299
+
300
+ .fs-plugin-icon,
301
+ .fs-connect-logo,
302
+ .fs-site-icon
303
+ {
304
+ border: 1px solid #ccc;
305
+ padding: 1px;
306
+ background: #fff;
307
+ }
308
+ }
309
+
310
+ .fs-terms
311
+ {
312
+ text-align: center;
313
+ font-size: 0.85em;
314
+ padding: 5px;
315
+ background: rgba(0, 0, 0, 0.05);
316
+
317
+ &, a
318
+ {
319
+ color: #999;
320
+ }
321
+
322
+ a
323
+ {
324
+ text-decoration: none;
325
+ }
326
+ }
327
+ }
328
+
329
+ .rtl
330
+ {
331
+ #fs_connect
332
+ {
333
+ .fs-actions
334
+ {
335
+ padding: 10px 20px;
336
+ background: #C0C7CA;
337
+
338
+ .button
339
+ {
340
+ .dashicons
341
+ {
342
+ font-size: 37px;
343
+ margin-left: -8px;
344
+ margin-right: 12px;
345
+ }
346
+
347
+ &.button-primary
348
+ {
349
+ &:after
350
+ {
351
+ content: ' \000bb';
352
+ }
353
+
354
+ &.fs-loading
355
+ {
356
+ &:after
357
+ {
358
+ content: '';
359
+ }
360
+ }
361
+ }
362
+
363
+ &.button-secondary
364
+ {
365
+ float: left;
366
+ }
367
+ }
368
+ }
369
+
370
+ .fs-permissions
371
+ {
372
+ ul
373
+ {
374
+ li
375
+ {
376
+ div
377
+ {
378
+ margin-right: 55px;
379
+ margin-left: 0;
380
+ }
381
+
382
+ i.dashicons
383
+ {
384
+ float: right;
385
+ }
386
+
387
+ }
388
+ }
389
+ }
390
+
391
+ .fs-visual
392
+ {
393
+ .fs-site-icon
394
+ {
395
+ right: 20px;
396
+ left: auto;
397
+ }
398
+
399
+ .fs-connect-logo
400
+ {
401
+ right: auto;
402
+ left: 20px;
403
+ }
404
+ }
405
+ }
406
+ }
407
+
408
+ .wp-pointer-content
409
+ {
410
+ #fs_connect
411
+ {
412
+ margin: 0;
413
+ @include box-shadow(none);
414
+ }
415
+ }
416
+
417
+ .fs-opt-in-pointer
418
+ {
419
+ .wp-pointer-content
420
+ {
421
+ padding: 0;
422
+ }
423
+
424
+ &.wp-pointer-top
425
+ {
426
+ .wp-pointer-arrow
427
+ {
428
+ border-bottom-color: #dfdfdf;
429
+ }
430
+ .wp-pointer-arrow-inner
431
+ {
432
+ border-bottom-color: #fafafa;
433
+ }
434
+ }
435
+
436
+ &.wp-pointer-bottom
437
+ {
438
+ .wp-pointer-arrow
439
+ {
440
+ border-top-color: #dfdfdf;
441
+ }
442
+ .wp-pointer-arrow-inner
443
+ {
444
+ border-top-color: #fafafa;
445
+ }
446
+ }
447
+
448
+ &.wp-pointer-left
449
+ {
450
+ .wp-pointer-arrow
451
+ {
452
+ border-right-color: #dfdfdf;
453
+ }
454
+ .wp-pointer-arrow-inner
455
+ {
456
+ border-right-color: #fafafa;
457
+ }
458
+ }
459
+
460
+ &.wp-pointer-right
461
+ {
462
+ .wp-pointer-arrow
463
+ {
464
+ border-left-color: #dfdfdf;
465
+ }
466
+ .wp-pointer-arrow-inner
467
+ {
468
+ border-left-color: #fafafa;
469
+ }
470
+ }
471
+ }
freemius/assets/scss/admin/debug.scss ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "../start";
2
+
3
+ .switch
4
+ {
5
+ position: relative;
6
+ display: inline-block;
7
+ font-size: 1.6em;
8
+ font-weight: bold;
9
+ color: #ccc;
10
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.8);
11
+ height: 18px;
12
+ padding: 6px 6px 5px 6px;
13
+ border: 1px solid #ccc;
14
+ border: 1px solid rgba(0, 0, 0, 0.2);
15
+ border-radius: 4px;
16
+ background: #ececec;
17
+ box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1), inset 0px 1px 3px 0px rgba(0, 0, 0, 0.1);
18
+ cursor: pointer;
19
+
20
+ span
21
+ {
22
+ display: inline-block; width: 35px;
23
+ text-transform: uppercase;
24
+
25
+ &.on
26
+ {
27
+ color: $button-primary-bkg;
28
+ }
29
+ }
30
+
31
+ .toggle
32
+ {
33
+ position: absolute;
34
+ top: 1px;
35
+ width: 37px;
36
+ height: 25px;
37
+ border: 1px solid #ccc;
38
+ border: 1px solid rgba(0, 0, 0, 0.3);
39
+ border-radius: 4px;
40
+ background: #fff;
41
+ background: -moz-linear-gradient(top, #ececec 0%, #fff 100%);
42
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ececec), color-stop(100%, #fff));
43
+ background: -webkit-linear-gradient(top, #ececec 0%, #fff 100%);
44
+ background: -o-linear-gradient(top, #ececec 0%, #fff 100%);
45
+ background: -ms-linear-gradient(top, #ececec 0%, #fff 100%);
46
+ background: linear-gradient(top, #ececec 0%, #fff 100%);
47
+ box-shadow: inset 0px 1px 0px 0px rgba(255, 255, 255, 0.5);
48
+ z-index: 999;
49
+ @include transition(all 0.15s ease-in-out);
50
+ }
51
+
52
+ &.on .toggle
53
+ {
54
+ left: 2%;
55
+ }
56
+ &.off .toggle
57
+ {
58
+ left: 54%;
59
+ }
60
+
61
+ /* Round switch */
62
+ &.round
63
+ {
64
+ padding: 0px 20px;
65
+ border-radius: 40px;
66
+
67
+ .toggle
68
+ {
69
+ border-radius: 40px;
70
+ width: 14px;
71
+ height: 14px;
72
+ }
73
+
74
+ &.on .toggle
75
+ {
76
+ left: 3%;
77
+ background: $button-primary-bkg;
78
+ }
79
+ &.off .toggle
80
+ {
81
+ left: 58%;
82
+ }
83
+ }
84
+ }
85
+
86
+ .switch-label
87
+ {
88
+ font-size: 20px;
89
+ line-height: 31px;
90
+ margin: 0 5px;
91
+ }
freemius/assets/scss/admin/dialog-boxes.scss ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ @import "../start";
2
+ @import "modal-common";
3
+ @import "deactivation-feedback";
4
+ @import "license-activation";
5
+ @import "license-key-resend";
freemius/config.php CHANGED
@@ -18,10 +18,18 @@
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
  }
@@ -32,6 +40,24 @@
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
@@ -60,6 +86,7 @@
60
  define( 'WP_FS__SKIP_EMAIL_ACTIVATION', false );
61
  }
62
 
 
63
  /**
64
  * Directories
65
  */
@@ -76,16 +103,34 @@
76
  /**
77
  * Domain / URL / Address
78
  */
79
- define( 'WP_FS__TESTING_DOMAIN', 'fswp:8080' );
80
  define( 'WP_FS__DOMAIN_PRODUCTION', 'wp.freemius.com' );
81
- define( 'WP_FS__DOMAIN_LOCALHOST', 'wp.freemius' );
82
- define( 'WP_FS__ADDRESS_LOCALHOST', 'http://' . WP_FS__DOMAIN_LOCALHOST . ':8080' );
83
  define( 'WP_FS__ADDRESS_PRODUCTION', 'https://' . WP_FS__DOMAIN_PRODUCTION );
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  define( 'WP_FS__IS_HTTP_REQUEST', isset( $_SERVER['HTTP_HOST'] ) );
86
  define( 'WP_FS__REMOTE_ADDR', fs_get_ip() );
87
 
88
- define( 'WP_FS__IS_PRODUCTION_MODE', ! defined( 'WP_FS__DEV_MODE' ) || ! WP_FS__DEV_MODE || ( WP_FS__TESTING_DOMAIN !== $_SERVER['HTTP_HOST'] ) );
 
 
 
89
 
90
  define( 'WP_FS__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? WP_FS__ADDRESS_PRODUCTION : WP_FS__ADDRESS_LOCALHOST ) );
91
 
@@ -94,8 +139,8 @@
94
  } else {
95
  define( 'WP_FS__IS_LOCALHOST', WP_FS__IS_HTTP_REQUEST &&
96
  is_string( WP_FS__REMOTE_ADDR ) &&
97
- ( substr( WP_FS__REMOTE_ADDR, 0, 4 ) == '127.' ||
98
- WP_FS__REMOTE_ADDR == '::1' )
99
  );
100
  }
101
 
@@ -104,8 +149,8 @@
104
 
105
  // Set API address for local testing.
106
  if ( ! WP_FS__IS_PRODUCTION_MODE ) {
107
- define( 'FS_API__ADDRESS', 'http://api.freemius:8080' );
108
- define( 'FS_API__SANDBOX_ADDRESS', 'http://sandbox-api.freemius:8080' );
109
  }
110
 
111
  define( 'WP_FS___OPTION_PREFIX', 'fs' . ( WP_FS__IS_PRODUCTION_MODE ? '' : '_dbg' ) . '_' );
@@ -119,8 +164,8 @@
119
  define( 'WP_FS__OPTIONS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'options' );
120
 
121
  define( 'WP_FS__IS_HTTPS', ( WP_FS__IS_HTTP_REQUEST &&
122
- // Checks if CloudFlare's HTTPS (Flexible SSL support)
123
- isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) ||
124
  // Check if HTTPS request.
125
  ( isset( $_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) ||
126
  ( isset( $_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] )
@@ -154,9 +199,22 @@
154
  /**
155
  * Debugging
156
  */
157
- define( 'WP_FS__DEBUG_SDK', WP_FS__DEV_MODE && ! empty( $_GET['fs_dbg'] ) );
 
 
 
 
 
 
 
 
 
 
158
  define( 'WP_FS__ECHO_DEBUG_SDK', WP_FS__DEV_MODE && ! empty( $_GET['fs_dbg_echo'] ) );
159
  define( 'WP_FS__LOG_DATETIME_FORMAT', 'Y-n-d H:i:s' );
 
 
 
160
 
161
  if ( WP_FS__ECHO_DEBUG_SDK ) {
162
  error_reporting( E_ALL );
18
  /**
19
  * API Connectivity Simulation
20
  */
21
+ if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY' ) ) {
22
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY', false );
23
+ }
24
+ if ( ! defined( 'WP_FS__SIMULATE_NO_CURL' ) ) {
25
+ define( 'WP_FS__SIMULATE_NO_CURL', false );
26
+ }
27
+ if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE' ) ) {
28
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false );
29
+ }
30
+ if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL' ) ) {
31
+ define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false );
32
+ }
33
  if ( WP_FS__SIMULATE_NO_CURL ) {
34
  define( 'FS_SDK__SIMULATE_NO_CURL', true );
35
  }
40
  define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', true );
41
  }
42
 
43
+ if ( ! defined( 'WP_FS__SIMULATE_FREEMIUS_OFF' ) ) {
44
+ define( 'WP_FS__SIMULATE_FREEMIUS_OFF', false );
45
+ }
46
+
47
+ if ( ! defined( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES' ) ) {
48
+ /**
49
+ * @since 1.1.7.3
50
+ * @author Vova Feldman (@svovaf)
51
+ *
52
+ * I'm not sure if shared servers periodically change IP, or the subdomain of the
53
+ * admin dashboard. Also, I've seen sites that have strange loop of switching
54
+ * between domains on a daily basis. Therefore, to eliminate the risk of
55
+ * multiple unwanted connectivity test pings, temporary ignore domain or
56
+ * server IP changes.
57
+ */
58
+ define( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES', false );
59
+ }
60
+
61
  /**
62
  * If your dev environment supports custom public network IP setup
63
  * like VVV, please update WP_FS__LOCALHOST_IP with your public IP
86
  define( 'WP_FS__SKIP_EMAIL_ACTIVATION', false );
87
  }
88
 
89
+
90
  /**
91
  * Directories
92
  */
103
  /**
104
  * Domain / URL / Address
105
  */
 
106
  define( 'WP_FS__DOMAIN_PRODUCTION', 'wp.freemius.com' );
 
 
107
  define( 'WP_FS__ADDRESS_PRODUCTION', 'https://' . WP_FS__DOMAIN_PRODUCTION );
108
 
109
+ if ( ! defined( 'WP_FS__DOMAIN_LOCALHOST' ) ) {
110
+ define( 'WP_FS__DOMAIN_LOCALHOST', 'wp.freemius' );
111
+ }
112
+ if ( ! defined( 'WP_FS__ADDRESS_LOCALHOST' ) ) {
113
+ define( 'WP_FS__ADDRESS_LOCALHOST', 'http://' . WP_FS__DOMAIN_LOCALHOST . ':8080' );
114
+ }
115
+
116
+ if ( ! defined( 'WP_FS__TESTING_DOMAIN' ) ) {
117
+ define( 'WP_FS__TESTING_DOMAIN', 'fswp' );
118
+ }
119
+
120
+ if ( ! defined( 'WP_FS__API_ADDRESS_LOCALHOST' ) ) {
121
+ define( 'WP_FS__API_ADDRESS_LOCALHOST', 'http://api.freemius:8080' );
122
+ }
123
+ if ( ! defined( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST' ) ) {
124
+ define( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST', 'http://sandbox-api.freemius:8080' );
125
+ }
126
+
127
  define( 'WP_FS__IS_HTTP_REQUEST', isset( $_SERVER['HTTP_HOST'] ) );
128
  define( 'WP_FS__REMOTE_ADDR', fs_get_ip() );
129
 
130
+ if ( ! defined( 'WP_FS__IS_PRODUCTION_MODE' ) ) {
131
+ // By default, run with Freemius production servers.
132
+ define( 'WP_FS__IS_PRODUCTION_MODE', true );
133
+ }
134
 
135
  define( 'WP_FS__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? WP_FS__ADDRESS_PRODUCTION : WP_FS__ADDRESS_LOCALHOST ) );
136
 
139
  } else {
140
  define( 'WP_FS__IS_LOCALHOST', WP_FS__IS_HTTP_REQUEST &&
141
  is_string( WP_FS__REMOTE_ADDR ) &&
142
+ ( substr( WP_FS__REMOTE_ADDR, 0, 4 ) === '127.' ||
143
+ WP_FS__REMOTE_ADDR === '::1' )
144
  );
145
  }
146
 
149
 
150
  // Set API address for local testing.
151
  if ( ! WP_FS__IS_PRODUCTION_MODE ) {
152
+ define( 'FS_API__ADDRESS', WP_FS__API_ADDRESS_LOCALHOST );
153
+ define( 'FS_API__SANDBOX_ADDRESS', WP_FS__API_SANDBOX_ADDRESS_LOCALHOST );
154
  }
155
 
156
  define( 'WP_FS___OPTION_PREFIX', 'fs' . ( WP_FS__IS_PRODUCTION_MODE ? '' : '_dbg' ) . '_' );
164
  define( 'WP_FS__OPTIONS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'options' );
165
 
166
  define( 'WP_FS__IS_HTTPS', ( WP_FS__IS_HTTP_REQUEST &&
167
+ // Checks if CloudFlare's HTTPS (Flexible SSL support).
168
+ isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) ||
169
  // Check if HTTPS request.
170
  ( isset( $_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) ||
171
  ( isset( $_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] )
199
  /**
200
  * Debugging
201
  */
202
+ if ( ! defined( 'WP_FS__DEBUG_SDK' ) ) {
203
+ $debug_mode = get_option( 'fs_debug_mode', null );
204
+
205
+ if ( $debug_mode === null ) {
206
+ $debug_mode = false;
207
+ add_option( 'fs_debug_mode', $debug_mode );
208
+ }
209
+
210
+ define( 'WP_FS__DEBUG_SDK', is_numeric( $debug_mode ) ? ( 0 < $debug_mode ) : WP_FS__DEV_MODE );
211
+ }
212
+
213
  define( 'WP_FS__ECHO_DEBUG_SDK', WP_FS__DEV_MODE && ! empty( $_GET['fs_dbg_echo'] ) );
214
  define( 'WP_FS__LOG_DATETIME_FORMAT', 'Y-n-d H:i:s' );
215
+ if ( ! defined( 'FS_API__LOGGER_ON' ) ) {
216
+ define( 'FS_API__LOGGER_ON', WP_FS__DEBUG_SDK );
217
+ }
218
 
219
  if ( WP_FS__ECHO_DEBUG_SDK ) {
220
  error_reporting( E_ALL );
freemius/gulpfile.js ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var gulp = require('gulp');
2
+ var wpPot = require('gulp-wp-pot');
3
+ var gettext = require('gulp-gettext');
4
+ var sort = require('gulp-sort');
5
+ var pofill = require('gulp-pofill');
6
+ var rename = require('gulp-rename');
7
+
8
+ gulp.task('default', function () {
9
+ // Create POT out of i18n.php.
10
+ gulp.src('includes/i18n.php')
11
+ .pipe(sort())
12
+ .pipe(wpPot( {
13
+ destFile:'freemius.pot',
14
+ package: 'freemius',
15
+ bugReport: 'https://github.com/Freemius/wordpress-sdk/issues',
16
+ lastTranslator: 'Vova Feldman <vova@freemius.com>',
17
+ team: 'Freemius Team <admin@freemius.com>'
18
+ } ))
19
+ .pipe(gulp.dest('languages/'));
20
+
21
+ // Create English PO out of the POT.
22
+ gulp.src('languages/freemius.pot')
23
+ .pipe(pofill({
24
+ items: function(item) {
25
+ // If msgstr is empty, use identity translation
26
+ if (!item.msgstr.length) {
27
+ item.msgstr = [''];
28
+ }
29
+ if (!item.msgstr[0]) {
30
+ item.msgstr[0] = item.msgid;
31
+ }
32
+ return item;
33
+ }
34
+ }))
35
+ .pipe(rename('freemius-en.po'))
36
+ .pipe(gulp.dest('languages/'));
37
+
38
+ // Compile POs to MOs.
39
+ gulp.src('languages/*.po')
40
+ .pipe(gettext())
41
+ .pipe(gulp.dest('languages/'))
42
+ });
freemius/includes/class-freemius-abstract.php CHANGED
@@ -109,6 +109,16 @@
109
  return ( $this->is_paying() || $this->is_trial() );
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
112
  #region Premium Only ------------------------------------------------------------------
113
 
114
  /**
@@ -201,6 +211,20 @@
201
  return $this->is_paying__premium_only();
202
  }
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  #endregion Premium Only ------------------------------------------------------------------
205
 
206
  #region Trial ------------------------------------------------------------------
@@ -295,6 +319,31 @@
295
  */
296
  abstract function has_free_plan();
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  #endregion Plans ------------------------------------------------------------------
299
 
300
  /**
109
  return ( $this->is_paying() || $this->is_trial() );
110
  }
111
 
112
+ /**
113
+ * Check if user in a trial or have feature enabled license.
114
+ *
115
+ * @author Vova Feldman (@svovaf)
116
+ * @since 1.1.7
117
+ *
118
+ * @return bool
119
+ */
120
+ abstract function can_use_premium_code();
121
+
122
  #region Premium Only ------------------------------------------------------------------
123
 
124
  /**
211
  return $this->is_paying__premium_only();
212
  }
213
 
214
+ /**
215
+ * Check if user in a trial or have feature enabled license.
216
+ *
217
+ * All code wrapped in this statement will be only included in the premium code.
218
+ *
219
+ * @author Vova Feldman (@svovaf)
220
+ * @since 1.1.9
221
+ *
222
+ * @return bool
223
+ */
224
+ function can_use_premium_code__premium_only() {
225
+ return $this->is_premium() && $this->can_use_premium_code();
226
+ }
227
+
228
  #endregion Premium Only ------------------------------------------------------------------
229
 
230
  #region Trial ------------------------------------------------------------------
319
  */
320
  abstract function has_free_plan();
321
 
322
+ /**
323
+ * Check if plugin is premium only (no free plans).
324
+ *
325
+ * NOTE: is__premium_only() is very different method, don't get confused.
326
+ *
327
+ * @author Vova Feldman (@svovaf)
328
+ * @since 1.1.9
329
+ *
330
+ * @return bool
331
+ */
332
+ abstract function is_only_premium();
333
+
334
+ /**
335
+ * Checks if it's a freemium plugin.
336
+ *
337
+ * @author Vova Feldman (@svovaf)
338
+ * @since 1.1.9
339
+ *
340
+ * @return bool
341
+ */
342
+ function is_freemium() {
343
+ return $this->has_paid_plan() &&
344
+ $this->has_free_plan();
345
+ }
346
+
347
  #endregion Plans ------------------------------------------------------------------
348
 
349
  /**
freemius/includes/class-freemius.php CHANGED
@@ -96,6 +96,18 @@
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.
@@ -140,7 +152,7 @@
140
  /**
141
  * @since 1.0.4
142
  *
143
- * @var FS_Plugin
144
  */
145
  private $_parent_plugin = false;
146
  /**
@@ -215,18 +227,43 @@
215
  */
216
  private static $_instances = array();
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
  /* Ctor
220
  ------------------------------------------------------------------------------------------------------------------*/
221
 
222
- private function __construct( $slug ) {
 
 
 
 
 
 
 
 
 
223
  $this->_slug = $slug;
224
 
225
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
226
 
227
  $this->_storage = FS_Key_Value_Storage::instance( 'plugin_data', $this->_slug );
228
 
229
- $this->_plugin_main_file_path = $this->_find_caller_plugin_file();
230
  $this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
231
  $this->_plugin_basename = plugin_basename( $this->_plugin_main_file_path );
232
  $this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
@@ -257,7 +294,9 @@
257
  is_object( $this->_plugin ) ? $this->_plugin->title : ''
258
  );
259
 
260
- if ( 'true' === fs_request_get( 'fs_clear_api_cache' ) ) {
 
 
261
  FS_Api::clear_cache();
262
  }
263
 
@@ -325,6 +364,13 @@
325
  * @param string $sdk_version
326
  */
327
  function _data_migration( $sdk_prev_version, $sdk_version ) {
 
 
 
 
 
 
 
328
  if ( version_compare( $sdk_prev_version, '1.1.5', '<' ) &&
329
  version_compare( $sdk_version, '1.1.5', '>=' )
330
  ) {
@@ -348,6 +394,54 @@
348
  }
349
  }
350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  /**
352
  * @author Vova Feldman (@svovaf)
353
  * @since 1.0.9
@@ -360,8 +454,20 @@
360
  '_activate_plugin_event_hook'
361
  ) );
362
 
363
- // Hook to plugin uninstall.
364
- register_uninstall_hook( $this->_plugin_main_file_path, array( 'Freemius', '_uninstall_plugin_hook' ) );
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  if ( ! $this->is_ajax() ) {
367
  if ( ! $this->is_addon() ) {
@@ -380,6 +486,41 @@
380
  $this->add_action( 'sdk_version_update', array( &$this, '_data_migration' ), WP_FS__DEFAULT_PRIORITY, 2 );
381
  }
382
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  /**
384
  * @author Vova Feldman (@svovaf)
385
  * @since 1.0.9
@@ -387,7 +528,7 @@
387
  private function _register_account_hooks() {
388
  if ( is_admin() ) {
389
  if ( ! $this->is_ajax() ) {
390
- if ( $this->has_trial_plan() ) {
391
  $last_time_trial_promotion_shown = $this->_storage->get( 'trial_promotion_shown', false );
392
  if ( ! $this->_site->is_trial_utilized() &&
393
  (
@@ -404,16 +545,90 @@
404
  // If user is paying or in trial and have the free version installed,
405
  // assume that the deactivation is for the upgrade process.
406
  if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
407
- add_action( 'wp_ajax_submit-uninstall-reason', array( &$this, '_submit_uninstall_reason_action' ) );
 
 
 
408
 
409
  global $pagenow;
410
  if ( 'plugins.php' === $pagenow ) {
411
  add_action( 'admin_footer', array( &$this, '_add_deactivation_feedback_dialog_box' ) );
412
  }
413
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  }
416
 
 
 
 
417
  /**
418
  * Displays a confirmation and feedback dialog box when the user clicks on the "Deactivate" link on the plugins
419
  * page.
@@ -423,8 +638,6 @@
423
  * @since 1.1.2
424
  */
425
  function _add_deactivation_feedback_dialog_box() {
426
- fs_enqueue_local_style( 'fs_deactivation_feedback', '/admin/deactivation-feedback.css' );
427
-
428
  /* Check the type of user:
429
  * 1. Long-term (long-term)
430
  * 2. Non-registered and non-anonymous short-term (non-registered-and-non-anonymous-short-term).
@@ -468,7 +681,7 @@
468
  /**
469
  * @todo Deactivation form core functions should be loaded only once! Otherwise, when there are multiple Freemius powered plugins the same code is loaded multiple times. The only thing that should be loaded differently is the various deactivation reasons object based on the state of the plugin.
470
  */
471
- fs_require_template( 'deactivation-feedback-modal.php', $vars );
472
  }
473
 
474
  /**
@@ -480,15 +693,32 @@
480
  * @return array The uninstall reasons for the specified user type.
481
  */
482
  function _get_uninstall_reasons( $user_type = 'long-term' ) {
 
 
 
 
 
 
 
 
 
 
483
  $reason_found_better_plugin = array(
484
- 'id' => 2,
485
  'text' => __fs( 'reason-found-a-better-plugin', $this->_slug ),
486
  'input_type' => 'textfield',
487
  'input_placeholder' => __fs( 'placeholder-plugin-name', $this->_slug )
488
  );
489
 
 
 
 
 
 
 
 
490
  $reason_other = array(
491
- 'id' => 7,
492
  'text' => __fs( 'reason-other', $this->_slug ),
493
  'input_type' => 'textfield',
494
  'input_placeholder' => ''
@@ -496,97 +726,116 @@
496
 
497
  $long_term_user_reasons = array(
498
  array(
499
- 'id' => 1,
500
  'text' => __fs( 'reason-no-longer-needed', $this->_slug ),
501
  'input_type' => '',
502
  'input_placeholder' => ''
503
  ),
504
  $reason_found_better_plugin,
505
  array(
506
- 'id' => 3,
507
  'text' => __fs( 'reason-needed-for-a-short-period', $this->_slug ),
508
  'input_type' => '',
509
  'input_placeholder' => ''
510
  ),
511
  array(
512
- 'id' => 4,
513
  'text' => __fs( 'reason-broke-my-site', $this->_slug ),
514
  'input_type' => '',
515
- 'input_placeholder' => ''
 
516
  ),
517
  array(
518
- 'id' => 5,
519
  'text' => __fs( 'reason-suddenly-stopped-working', $this->_slug ),
520
  'input_type' => '',
521
- 'input_placeholder' => ''
 
522
  )
523
  );
524
 
525
  if ( $this->is_paying() ) {
526
  $long_term_user_reasons[] = array(
527
- 'id' => 6,
528
  'text' => __fs( 'reason-cant-pay-anymore', $this->_slug ),
529
  'input_type' => 'textfield',
530
  'input_placeholder' => __fs( 'placeholder-comfortable-price', $this->_slug )
531
  );
532
  }
533
 
534
- $long_term_user_reasons[] = $reason_other;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
  $uninstall_reasons = array(
537
  'long-term' => $long_term_user_reasons,
538
  'non-registered-and-non-anonymous-short-term' => array(
539
  array(
540
- 'id' => 8,
541
  'text' => __fs( 'reason-didnt-work', $this->_slug ),
542
  'input_type' => '',
543
  'input_placeholder' => ''
544
  ),
545
- array(
546
- 'id' => 9,
547
- 'text' => __fs( 'reason-dont-like-to-share-my-information', $this->_slug ),
548
- 'input_type' => '',
549
- 'input_placeholder' => ''
550
- ),
551
- $reason_found_better_plugin,
552
- $reason_other
553
  ),
554
  'short-term' => array(
555
  array(
556
- 'id' => 10,
557
  'text' => __fs( 'reason-couldnt-make-it-work', $this->_slug ),
558
  'input_type' => '',
559
- 'input_placeholder' => ''
 
560
  ),
561
  $reason_found_better_plugin,
562
  array(
563
- 'id' => 11,
564
  'text' => __fs( 'reason-great-but-need-specific-feature', $this->_slug ),
565
  'input_type' => 'textarea',
566
  'input_placeholder' => __fs( 'placeholder-feature', $this->_slug )
567
  ),
568
  array(
569
- 'id' => 12,
570
  'text' => __fs( 'reason-not-working', $this->_slug ),
571
  'input_type' => 'textarea',
572
  'input_placeholder' => __fs( 'placeholder-share-what-didnt-work', $this->_slug )
573
  ),
574
  array(
575
- 'id' => 13,
576
  'text' => __fs( 'reason-not-what-i-was-looking-for', $this->_slug ),
577
  'input_type' => 'textarea',
578
  'input_placeholder' => __fs( 'placeholder-what-youve-been-looking-for', $this->_slug )
579
  ),
580
  array(
581
- 'id' => 14,
582
  'text' => __fs( 'reason-didnt-work-as-expected', $this->_slug ),
583
  'input_type' => 'textarea',
584
  'input_placeholder' => __fs( 'placeholder-what-did-you-expect', $this->_slug )
585
- ),
586
- $reason_other
587
  )
588
  );
589
 
 
 
 
 
 
 
 
590
  $uninstall_reasons = $this->apply_filters( 'uninstall_reasons', $uninstall_reasons );
591
 
592
  return $uninstall_reasons[ $user_type ];
@@ -599,15 +848,22 @@
599
  * @since 1.1.2
600
  */
601
  function _submit_uninstall_reason_action() {
602
- if ( ! isset( $_POST['reason_id'] ) ) {
 
 
 
603
  exit;
604
  }
605
 
606
- $reason_info = isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '';
 
 
 
607
 
608
  $reason = (object) array(
609
- 'id' => $_POST['reason_id'],
610
- 'info' => substr( $reason_info, 0, 128 )
 
611
  );
612
 
613
  $this->_storage->store( 'uninstall_reason', $reason );
@@ -617,32 +873,7 @@
617
  exit;
618
  }
619
 
620
- /**
621
- * Leverage backtrace to find caller plugin file path.
622
- *
623
- * @author Vova Feldman (@svovaf)
624
- * @since 1.0.6
625
- *
626
- * @return string
627
- *
628
- * @uses fs_find_caller_plugin_file
629
- */
630
- private function _find_caller_plugin_file() {
631
- // Try to load the cached value of the file path.
632
- if ( isset( $this->_storage->plugin_main_file ) ) {
633
- if ( file_exists( $this->_storage->plugin_main_file->path ) ) {
634
- return $this->_storage->plugin_main_file->path;
635
- }
636
- }
637
-
638
- $plugin_file = fs_find_caller_plugin_file();
639
-
640
- $this->_storage->plugin_main_file = (object) array(
641
- 'path' => fs_normalize_path( $plugin_file ),
642
- );
643
-
644
- return $plugin_file;
645
- }
646
 
647
  #region Instance ------------------------------------------------------------------
648
 
@@ -652,11 +883,12 @@
652
  * @author Vova Feldman (@svovaf)
653
  * @since 1.0.0
654
  *
655
- * @param $slug
 
656
  *
657
  * @return Freemius
658
  */
659
- static function instance( $slug ) {
660
  $slug = strtolower( $slug );
661
 
662
  if ( ! isset( self::$_instances[ $slug ] ) ) {
@@ -664,7 +896,7 @@
664
  self::_load_required_static();
665
  }
666
 
667
- self::$_instances[ $slug ] = new Freemius( $slug );
668
  }
669
 
670
  return self::$_instances[ $slug ];
@@ -778,16 +1010,127 @@
778
  * @author Vova Feldman (@svovaf)
779
  * @since 1.0.7
780
  *
 
 
781
  * @return bool
782
  */
783
- function is_activation_mode() {
784
  return (
 
785
  ! $this->is_registered() &&
786
- ( ! $this->enable_anonymous() ||
787
  ( ! $this->is_anonymous() && ! $this->is_pending_activation() ) )
788
  );
789
  }
790
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
791
  private static $_statics_loaded = false;
792
 
793
  /**
@@ -814,9 +1157,35 @@
814
 
815
  add_action( 'admin_menu', array( 'Freemius', 'add_debug_page' ) );
816
 
 
 
 
 
817
  self::$_statics_loaded = true;
818
  }
819
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
820
  #region Debugging ------------------------------------------------------------------
821
 
822
  /**
@@ -834,7 +1203,7 @@
834
 
835
  if ( WP_FS__DEV_MODE ) {
836
  // Add top-level debug menu item.
837
- $hook = add_object_page(
838
  $title,
839
  $title,
840
  'manage_options',
@@ -856,6 +1225,18 @@
856
  add_action( "load-$hook", array( 'Freemius', '_debug_page_actions' ) );
857
  }
858
 
 
 
 
 
 
 
 
 
 
 
 
 
859
  /**
860
  * @author Vova Feldman (@svovaf)
861
  * @since 1.0.8
@@ -863,11 +1244,12 @@
863
  static function _debug_page_actions() {
864
  self::_clean_admin_content_section();
865
 
866
- if ( fs_request_is_action( 'delete_all_accounts' ) ) {
867
- check_admin_referer( 'delete_all_accounts' );
868
 
869
  self::$_accounts->clear( true );
870
 
 
871
  return;
872
  }
873
  }
@@ -883,6 +1265,7 @@
883
  $users = self::get_all_users();
884
  $addons = self::get_all_addons();
885
  $account_addons = self::get_all_account_addons();
 
886
 
887
  // $plans = self::get_all_plans();
888
  // $licenses = self::get_all_licenses();
@@ -892,7 +1275,10 @@
892
  'users' => $users,
893
  'addons' => $addons,
894
  'account_addons' => $account_addons,
 
895
  );
 
 
896
  fs_require_once_template( 'debug.php', $vars );
897
  }
898
 
@@ -928,23 +1314,108 @@
928
  return false;
929
  }
930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
  /**
932
  * Check if there's any connectivity issue to Freemius API.
933
  *
934
  * @author Vova Feldman (@svovaf)
935
  * @since 1.0.9
936
  *
937
- * @param bool $flush
938
  *
939
  * @return bool
940
  */
941
- function has_api_connectivity( $flush = false ) {
942
- if ( ! $flush && isset( $this->_has_api_connection ) ) {
 
 
943
  return $this->_has_api_connection;
944
  }
945
 
946
- $version = $this->get_plugin_version();
947
-
948
  if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY &&
949
  isset( $this->_storage->connectivity_test ) &&
950
  true === $this->_storage->connectivity_test['is_connected']
@@ -952,48 +1423,54 @@
952
  unset( $this->_storage->connectivity_test );
953
  }
954
 
955
- if ( isset( $this->_storage->connectivity_test ) ) {
956
- if ( ! WP_FS__IS_HTTP_REQUEST ||
957
- ( $_SERVER['HTTP_HOST'] == $this->_storage->connectivity_test['host'] &&
958
- WP_FS__REMOTE_ADDR == $this->_storage->connectivity_test['server_ip'] )
959
- ) {
960
- if ( ( $this->_storage->connectivity_test['is_connected'] &&
961
- $this->_storage->connectivity_test['is_active'] ) ||
962
- ( ! $flush &&
963
- $version == $this->_storage->connectivity_test['version'] )
964
- ) {
965
- $this->_has_api_connection = $this->_storage->connectivity_test['is_connected'];
966
- $this->_is_on = $this->_storage->connectivity_test['is_active'] || ( WP_FS__DEV_MODE && $this->_has_api_connection );
967
 
968
- return $this->_has_api_connection;
969
- }
970
- }
971
  }
972
 
973
- $is_update = $this->apply_filters( 'is_plugin_update', $this->is_plugin_update() );
 
974
 
975
- if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY ) {
976
- $is_connected = false;
977
- } else {
978
- $pong = $this->get_api_plugin_scope()->ping( $this->get_anonymous_id(), $is_update );
979
- $is_connected = $this->get_api_plugin_scope()->is_valid_ping( $pong );
980
  }
981
 
982
- if ( ! $is_connected ) {
983
- // 2nd try of connectivity.
984
- $pong = $this->get_api_plugin_scope()->ping( $this->get_anonymous_id(), $is_update );
985
 
986
- if ( $this->get_api_plugin_scope()->is_valid_ping( $pong ) ) {
987
- $is_connected = true;
988
- } else {
989
- // Another API failure.
990
- $this->_add_connectivity_issue_message( $pong );
991
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
992
  }
993
 
994
- $is_active = ( ! $is_connected ) ?
995
- false :
996
- ( isset( $pong->is_active ) && true == $pong->is_active );
 
 
 
997
 
998
  $this->_storage->connectivity_test = array(
999
  'is_connected' => $is_connected,
@@ -1006,9 +1483,32 @@
1006
  );
1007
 
1008
  $this->_has_api_connection = $is_connected;
1009
- $this->_is_on = $is_active || ( WP_FS__DEV_MODE && $is_connected );
 
1010
 
1011
- return $this->_has_api_connection;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  }
1013
 
1014
  /**
@@ -1020,18 +1520,39 @@
1020
  * @return string
1021
  */
1022
  function get_anonymous_id() {
1023
- if ( ! self::$_accounts->has_option( 'unique_id' ) ) {
 
 
1024
  $key = get_site_url();
1025
 
1026
  // If localhost, assign microtime instead of domain.
1027
- if ( WP_FS__IS_LOCALHOST || false !== strpos( $key, 'localhost' ) ) {
 
 
 
1028
  $key = microtime();
1029
  }
1030
 
1031
- self::$_accounts->set_option( 'unique_id', md5( $key ), true );
 
 
1032
  }
1033
 
1034
- return self::$_accounts->get_option( 'unique_id' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1035
  }
1036
 
1037
  /**
@@ -1041,8 +1562,9 @@
1041
  * @since 1.0.9
1042
  *
1043
  * @param mixed $api_result
 
1044
  */
1045
- function _add_connectivity_issue_message( $api_result ) {
1046
  if ( $this->_enable_anonymous ) {
1047
  // Don't add message if can run anonymously.
1048
  return;
@@ -1052,15 +1574,14 @@
1052
  require_once( ABSPATH . 'wp-includes/functions.php' );
1053
  }
1054
 
1055
- self::require_pluggable_essentials();
1056
-
1057
- $current_user = wp_get_current_user();
1058
  // $admin_email = get_option( 'admin_email' );
1059
  $admin_email = $current_user->user_email;
1060
 
1061
  $message = false;
1062
  if ( is_object( $api_result ) &&
1063
- isset( $api_result->error )
 
1064
  ) {
1065
  switch ( $api_result->error->code ) {
1066
  case 'curl_missing':
@@ -1158,75 +1679,83 @@
1158
  )
1159
  );
1160
  break;
1161
- default:
1162
- $message = __fs( 'connectivity-test-fails-message', $this->_slug );
1163
- break;
1164
  }
1165
  }
1166
 
 
 
 
1167
  if ( false === $message ) {
1168
- $message = sprintf(
1169
- __fs( 'x-requires-access-to-api', $this->_slug ) . ' ' .
1170
- __fs( 'connectivity-test-fails-message', $this->_slug ) . ' ' .
1171
- __fs( 'happy-to-resolve-issue-asap', $this->_slug ) .
1172
- ' %s',
1173
- '<b>' . $this->get_plugin_name() . '</b>',
1174
- sprintf(
1175
- '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1176
  sprintf(
1177
- '<a class="fs-resolve" data-type="general" href="#"><b>%s</b></a>%s',
1178
- __fs( 'fix-issue-title', $this->_slug ),
1179
- ' - ' . sprintf(
1180
- __fs( 'fix-issue-desc', $this->_slug ),
1181
- '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
 
 
 
 
1182
  )
1183
- ),
1184
- sprintf(
1185
- '<a href="%s" target="_blank"><b>%s</b></a>%s',
1186
- sprintf( 'https://wordpress.org/plugins/%s/download/', $this->_slug ),
1187
- __fs( 'install-previous-title', $this->_slug ),
1188
- ' - ' . __fs( 'install-previous-desc', $this->_slug )
1189
- ),
 
 
 
 
 
 
1190
  sprintf(
1191
- '<a href="%s"><b>%s</b></a>%s',
1192
- 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 ),
1193
- __fs( 'deactivate-plugin-title', $this->_slug ),
1194
- ' - ' . __fs( 'deactivate-plugin-desc', $this->_slug )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1195
  )
1196
- )
1197
- );
1198
  }
1199
 
1200
  $this->_admin_notices->add_sticky(
1201
  $message,
1202
- 'failed_connect_api',
1203
  __fs( 'oops', $this->_slug ) . '...',
1204
- 'error'
1205
  );
1206
  }
1207
 
1208
- /**
1209
- * Get collection of all active plugins.
1210
- *
1211
- * @author Vova Feldman (@svovaf)
1212
- * @since 1.0.9
1213
- *
1214
- * @return array[string]array
1215
- */
1216
- private function get_active_plugins() {
1217
- self::require_plugin_essentials();
1218
-
1219
- $active_plugin = array();
1220
- $all_plugins = get_plugins();
1221
- $active_plugins_basenames = get_option( 'active_plugins' );
1222
-
1223
- foreach ( $active_plugins_basenames as $plugin_basename ) {
1224
- $active_plugin[ $plugin_basename ] = $all_plugins[ $plugin_basename ];
1225
- }
1226
-
1227
- return $active_plugin;
1228
- }
1229
-
1230
  /**
1231
  * Handle user request to resolve connectivity issue.
1232
  * This method will send an email to Freemius API technical staff for resolution.
@@ -1238,12 +1767,19 @@
1238
  function _email_about_firewall_issue() {
1239
  $this->_admin_notices->remove_sticky( 'failed_connect_api' );
1240
 
1241
- self::require_pluggable_essentials();
1242
 
1243
- $current_user = wp_get_current_user();
1244
- $admin_email = $current_user->user_email;
 
 
 
 
 
 
1245
 
1246
- $ping = $this->get_api_plugin_scope()->ping();
 
1247
 
1248
  $error_type = fs_request_get( 'error_type', 'general' );
1249
 
@@ -1274,7 +1810,18 @@
1274
  $custom_email_sections['api_error'] = array(
1275
  'title' => 'API Error',
1276
  'rows' => array(
1277
- 'ping' => array( is_string( $ping ) ? htmlentities( $ping ) : json_encode( $ping ) )
 
 
 
 
 
 
 
 
 
 
 
1278
  )
1279
  );
1280
 
@@ -1300,6 +1847,33 @@
1300
  exit;
1301
  }
1302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1303
  static function _add_firewall_issues_javascript() {
1304
  $params = array();
1305
  fs_require_once_template( 'firewall-issues-js.php', $params );
@@ -1382,15 +1956,13 @@
1382
  * @return array
1383
  */
1384
  private function get_email_sections() {
1385
- self::require_pluggable_essentials();
1386
-
1387
  // Retrieve the current user's information so that we can get the user's email, first name, and last name below.
1388
- $current_user = wp_get_current_user();
1389
 
1390
  // Retrieve the cURL version information so that we can get the version number below.
1391
  $curl_version_information = curl_version();
1392
 
1393
- $active_plugin = $this->get_active_plugins();
1394
 
1395
  // Generate the list of active plugins separated by new line.
1396
  $active_plugin_string = '';
@@ -1424,6 +1996,7 @@
1424
  'site' => array(
1425
  'title' => 'Site',
1426
  'rows' => array(
 
1427
  'address' => array( 'Address', site_url() ),
1428
  'host' => array(
1429
  'HTTP_HOST',
@@ -1483,25 +2056,6 @@
1483
  ) );
1484
  }
1485
 
1486
- /**
1487
- * @param string[] $options
1488
- * @param string $key
1489
- * @param mixed $default
1490
- *
1491
- * @return bool
1492
- */
1493
- private function _get_option( &$options, $key, $default = false ) {
1494
- return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
1495
- }
1496
-
1497
- private function _get_bool_option( &$options, $key, $default = false ) {
1498
- return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
1499
- }
1500
-
1501
- private function _get_numeric_option( &$options, $key, $default = false ) {
1502
- return isset( $options[ $key ] ) && is_numeric( $options[ $key ] ) ? $options[ $key ] : $default;
1503
- }
1504
-
1505
  /**
1506
  * Dynamic initiator, originally created to support initiation
1507
  * with parent_id for add-ons.
@@ -1516,127 +2070,103 @@
1516
  function dynamic_init( array $plugin_info ) {
1517
  $this->_logger->entrance();
1518
 
1519
- $id = $this->_get_numeric_option( $plugin_info, 'id', false );
1520
- $public_key = $this->_get_option( $plugin_info, 'public_key', false );
1521
- $secret_key = $this->_get_option( $plugin_info, 'secret_key', null );
1522
- $parent_id = $this->_get_numeric_option( $plugin_info, 'parent_id', null );
1523
- $parent_name = $this->_get_option( $plugin_info, 'parent_name', null );
1524
-
1525
- if ( isset( $plugin_info['parent'] ) ) {
1526
- $parent_id = $this->_get_numeric_option( $plugin_info['parent'], 'id', null );
1527
- // $parent_slug = $this->get_option( $plugin_info['parent'], 'slug', null );
1528
- // $parent_public_key = $this->get_option( $plugin_info['parent'], 'public_key', null );
1529
- $parent_name = $this->_get_option( $plugin_info['parent'], 'name', null );
1530
- }
1531
 
1532
- if ( false === $id ) {
1533
- throw new Freemius_Exception( 'Plugin id parameter is not set.' );
1534
- }
1535
- if ( false === $public_key ) {
1536
- throw new Freemius_Exception( 'Plugin public_key parameter is not set.' );
1537
  }
1538
 
1539
- $plugin = ( $this->_plugin instanceof FS_Plugin ) ?
1540
- $this->_plugin :
1541
- new FS_Plugin();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1542
 
1543
- $plugin->update( array(
1544
- 'id' => $id,
1545
- 'public_key' => $public_key,
1546
- 'slug' => $this->_slug,
1547
- 'parent_plugin_id' => $parent_id,
1548
- 'version' => $this->get_plugin_version(),
1549
- 'title' => $this->get_plugin_name(),
1550
- 'file' => $this->_free_plugin_basename,
1551
- 'is_premium' => $this->_get_bool_option( $plugin_info, 'is_premium', true ),
1552
- 'is_live' => $this->_get_bool_option( $plugin_info, 'is_live', true ),
1553
- // 'secret_key' => $secret_key,
1554
- ) );
 
1555
 
1556
- if ( $plugin->is_updated() ) {
1557
- // Update plugin details.
1558
- $this->_plugin = FS_Plugin_Manager::instance( $this->_slug )->store( $plugin );
 
 
1559
  }
1560
- $this->_plugin->secret_key = $secret_key;
1561
 
1562
- if ( ! isset( $plugin_info['menu'] ) ) {
1563
- // Back compatibility to 1.1.2
1564
- $plugin_info['menu'] = array(
1565
- 'slug' => isset( $plugin_info['menu_slug'] ) ?
1566
- $plugin_info['menu_slug'] :
1567
- $this->_slug
1568
- );
1569
- }
1570
-
1571
- $this->_menu = FS_Admin_Menu_Manager::instance( $this->_slug );
1572
- $this->_menu->init( $plugin_info['menu'], $this->is_addon() );
1573
-
1574
- $this->_has_addons = $this->_get_bool_option( $plugin_info, 'has_addons', false );
1575
- $this->_has_paid_plans = $this->_get_bool_option( $plugin_info, 'has_paid_plans', true );
1576
- $this->_is_org_compliant = $this->_get_bool_option( $plugin_info, 'is_org_compliant', true );
1577
- $this->_enable_anonymous = $this->_get_bool_option( $plugin_info, 'enable_anonymous', true );
1578
- $this->_permissions = $this->_get_option( $plugin_info, 'permissions', array() );
1579
-
1580
- if ( ! $this->is_registered() ) {
1581
- if ( ! WP_FS__IS_HTTP_REQUEST ) {
1582
  /**
1583
- * If not registered and executed without HTTP context (e.g. CLI, Cronjob),
1584
- * then don't start Freemius.
 
 
1585
  *
1586
  * @author Vova Feldman (@svovaf)
1587
- * @since 1.1.6.3
1588
  *
1589
- * @link https://wordpress.org/support/topic/errors-in-the-freemius-class-when-running-in-wordpress-in-cli
1590
  */
1591
- return;
1592
- }
1593
-
1594
- if ( ! $this->has_api_connectivity() ) {
1595
- if ( is_admin() && $this->_admin_notices->has_sticky( 'failed_connect_api' ) ) {
1596
- if ( ! $this->_enable_anonymous ) {
1597
- // If anonymous mode is disabled, add firewall admin-notice message.
1598
- add_action( 'admin_footer', array( 'Freemius', '_add_firewall_issues_javascript' ) );
1599
-
1600
- add_action( "wp_ajax_{$this->_slug}_resolve_firewall_issues", array(
1601
- &$this,
1602
- '_email_about_firewall_issue'
1603
- ) );
1604
  }
1605
  }
1606
 
1607
- return;
1608
- }
1609
-
1610
- // Check if Freemius is on for the current plugin.
1611
- // This MUST be executed after all the plugin variables has been loaded.
1612
- if ( ! $this->is_on() ) {
1613
- return;
1614
  }
1615
  }
1616
 
1617
- if ( false === $this->_background_sync() ) {
1618
- // If background sync wasn't executed,
1619
- // and if the plugin declared it has add-ons but
1620
- // no add-ons found in the local data, then try to sync add-ons.
1621
- if ( $this->_has_addons &&
1622
- ! $this->is_addon() &&
1623
- ( false === $this->get_addons() )
1624
- ) {
1625
- $this->_sync_addons();
1626
- }
1627
  }
1628
 
1629
  if ( $this->is_addon() ) {
1630
  if ( $this->is_parent_plugin_installed() ) {
1631
  // Link to parent FS.
1632
- $this->_parent = self::get_instance_by_id( $parent_id );
1633
 
1634
  // Get parent plugin reference.
1635
  $this->_parent_plugin = $this->_parent->get_plugin();
1636
  }
1637
  }
1638
 
1639
- if ( is_admin() ) {
1640
  global $pagenow;
1641
  if ( 'plugins.php' === $pagenow ) {
1642
  $this->hook_plugin_action_links();
@@ -1644,9 +2174,15 @@
1644
 
1645
  if ( $this->is_addon() ) {
1646
  if ( ! $this->is_parent_plugin_installed() ) {
 
 
 
 
 
 
1647
  $this->_admin_notices->add(
1648
- ( is_string( $parent_name ) ?
1649
- sprintf( __fs( 'addon-cannot-run-without-x', $this->_slug ), $this->get_plugin_name(), $parent_name ) :
1650
  sprintf( __fs( 'addon-x-cannot-run-without-parent', $this->_slug ), $this->get_plugin_name() )
1651
  ),
1652
  __fs( 'oops', $this->_slug ) . '...',
@@ -1663,29 +2199,24 @@
1663
  // @todo This should be only executed on activation. It should be migrated to register_activation_hook() together with other activation related logic.
1664
  if ( $this->is_premium() ) {
1665
  // Remove add-on download admin-notice.
1666
- $this->_parent->_admin_notices->remove_sticky( 'addon_plan_upgraded_' . $this->_slug );
 
 
 
1667
  }
 
 
1668
  }
1669
  } else {
1670
  add_action( 'admin_init', array( &$this, '_admin_init_action' ) );
1671
 
1672
- if ( $this->_has_addons() &&
1673
  'plugin-information' === fs_request_get( 'tab', false ) &&
1674
  $this->get_id() == fs_request_get( 'parent_plugin_id', false )
1675
  ) {
1676
- // Remove default plugin information action.
1677
- remove_all_actions( 'install_plugins_pre_plugin-information' );
1678
 
1679
- require_once WP_FS__DIR_INCLUDES . '/fs-plugin-functions.php';
1680
-
1681
- // Override action with custom plugins function for add-ons.
1682
- add_action( 'install_plugins_pre_plugin-information', 'fs_install_plugin_information' );
1683
-
1684
- // Override request for plugin information for Add-ons.
1685
- add_filter( 'fs_plugins_api', array(
1686
- &$this,
1687
- '_get_addon_info_filter'
1688
- ), WP_FS__DEFAULT_PRIORITY, 3 );
1689
  }
1690
  }
1691
 
@@ -1703,23 +2234,25 @@
1703
 
1704
  $this->do_action( 'initiated' );
1705
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1706
  if ( ! $this->is_addon() ) {
1707
  if ( $this->is_registered() ) {
1708
  // Fix for upgrade from versions < 1.0.9.
1709
  if ( ! isset( $this->_storage->activation_timestamp ) ) {
1710
  $this->_storage->activation_timestamp = WP_FS__SCRIPT_START_TIME;
1711
  }
1712
- if ( $this->_storage->prev_is_premium !== $this->_plugin->is_premium ) {
1713
- if ( isset( $this->_storage->prev_is_premium ) ) {
1714
- add_action( is_admin() ? 'admin_init' : 'init', array(
1715
- &$this,
1716
- '_plugin_code_type_changed'
1717
- ) );
1718
- } else {
1719
- // Set for code type for the first time.
1720
- $this->_storage->prev_is_premium = $this->_plugin->is_premium;
1721
- }
1722
- }
1723
 
1724
  $this->do_action( 'after_init_plugin_registered' );
1725
  } else if ( $this->is_anonymous() ) {
@@ -1736,6 +2269,229 @@
1736
  $this->do_action( 'after_init_addon_pending_activations' );
1737
  }
1738
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1739
  }
1740
 
1741
  /**
@@ -1745,8 +2501,11 @@
1745
  * @since 1.0.9
1746
  */
1747
  function _plugin_code_type_changed() {
1748
- // Send code type changes event.
1749
- $this->sync_install();
 
 
 
1750
 
1751
  if ( $this->is_premium() ) {
1752
  // Activated premium code.
@@ -1765,6 +2524,9 @@
1765
  __fs( 'woot', $this->_slug ) . '!'
1766
  );
1767
  } else {
 
 
 
1768
  // Activated free code (after had the premium before).
1769
  $this->do_action( 'after_free_version_reactivation' );
1770
 
@@ -1773,16 +2535,26 @@
1773
  sprintf(
1774
  __fs( 'you-have-x-license', $this->_slug ),
1775
  $this->_site->plan->title
1776
- ) . ' ' . $this->_get_latest_download_link( sprintf(
1777
- __fs( 'download-x-version-now', $this->_slug ),
1778
- $this->_site->plan->title
1779
- ) ),
1780
  'plan_upgraded',
1781
  __fs( 'yee-haw', $this->_slug ) . '!'
1782
  );
1783
  }
1784
  }
1785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1786
  // Update is_premium of latest version.
1787
  $this->_storage->prev_is_premium = $this->_plugin->is_premium;
1788
  }
@@ -1792,156 +2564,50 @@
1792
  #region Add-ons -------------------------------------------------------------------------
1793
 
1794
  /**
1795
- * Generate add-on plugin information.
1796
  *
1797
  * @author Vova Feldman (@svovaf)
1798
  * @since 1.0.6
1799
  *
1800
- * @param array $data
1801
- * @param string $action
1802
- * @param object|null $args
1803
  *
1804
- * @return array|null
1805
  */
1806
- function _get_addon_info_filter( $data, $action = '', $args = null ) {
1807
- $this->_logger->entrance();
1808
-
1809
- $parent_plugin_id = fs_request_get( 'parent_plugin_id', false );
1810
-
1811
- if ( $this->get_id() != $parent_plugin_id ||
1812
- ( 'plugin_information' !== $action ) ||
1813
- ! isset( $args->slug )
1814
- ) {
1815
- return $data;
1816
- }
1817
-
1818
- // Find add-on by slug.
1819
- $addons = $this->get_addons();
1820
- $selected_addon = false;
1821
- foreach ( $addons as $addon ) {
1822
- if ( $addon->slug == $args->slug ) {
1823
- $selected_addon = $addon;
1824
- break;
1825
- }
1826
- }
1827
-
1828
- if ( false === $selected_addon ) {
1829
- return $data;
1830
- }
1831
-
1832
- if ( ! isset( $selected_addon->info ) ) {
1833
- // Setup some default info.
1834
- $selected_addon->info = new stdClass();
1835
- $selected_addon->info->selling_point_0 = 'Selling Point 1';
1836
- $selected_addon->info->selling_point_1 = 'Selling Point 2';
1837
- $selected_addon->info->selling_point_2 = 'Selling Point 3';
1838
- $selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
1839
- }
1840
-
1841
- fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
1842
-
1843
- $data = $args;
1844
-
1845
- // Fetch as much as possible info from local files.
1846
- $plugin_local_data = $this->get_plugin_data();
1847
- $data->name = $selected_addon->title;
1848
- $data->author = $plugin_local_data['Author'];
1849
- $view_vars = array( 'plugin' => $selected_addon );
1850
- $data->sections = array(
1851
- 'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
1852
- );
1853
-
1854
- if ( ! empty( $selected_addon->info->banner_url ) ) {
1855
- $data->banners = array(
1856
- 'low' => $selected_addon->info->banner_url,
1857
- );
1858
- }
1859
-
1860
- if ( ! empty( $selected_addon->info->screenshots ) ) {
1861
- $view_vars = array(
1862
- 'screenshots' => $selected_addon->info->screenshots,
1863
- 'plugin' => $selected_addon,
1864
- );
1865
- $data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
1866
- }
1867
-
1868
- // Load add-on pricing.
1869
- $has_pricing = false;
1870
- $has_features = false;
1871
- $plans = false;
1872
- $plans_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans.json" );
1873
- if ( ! isset( $plans_result->error ) ) {
1874
- $plans = $plans_result->plans;
1875
- if ( is_array( $plans ) ) {
1876
- foreach ( $plans as &$plan ) {
1877
- $pricing_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/pricing.json" );
1878
- if ( ! isset( $pricing_result->error ) ) {
1879
- // Update plan's pricing.
1880
- $plan->pricing = $pricing_result->pricing;
1881
-
1882
- $has_pricing = true;
1883
- }
1884
-
1885
- $features_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/features.json" );
1886
- if ( ! isset( $features_result->error ) &&
1887
- is_array( $features_result->features ) &&
1888
- 0 < count( $features_result->features )
1889
- ) {
1890
- // Update plan's pricing.
1891
- $plan->features = $features_result->features;
1892
-
1893
- $has_features = true;
1894
- }
1895
- }
1896
- }
1897
- }
1898
-
1899
- // Get latest add-on version.
1900
- $latest = $this->_fetch_latest_version( $selected_addon->id );
1901
-
1902
- if ( is_object( $latest ) ) {
1903
- $data->version = $latest->version;
1904
- $data->last_updated = ! is_null( $latest->updated ) ? $latest->updated : $latest->created;
1905
- $data->requires = $latest->requires_platform_version;
1906
- $data->tested = $latest->tested_up_to_version;
1907
- } else {
1908
- // Add dummy version.
1909
- $data->version = '1.0.0';
1910
-
1911
- // Add message to developer to deploy the plugin through Freemius.
1912
- }
1913
-
1914
- $data->checkout_link = $this->checkout_url();
1915
- $data->download_link = 'https://dummy.com';
1916
-
1917
- if ( $has_pricing ) {
1918
- // Add plans to data.
1919
- $data->plans = $plans;
1920
-
1921
- if ( $has_features ) {
1922
- $view_vars = array(
1923
- 'plans' => $plans,
1924
- 'plugin' => $selected_addon,
1925
- );
1926
- $data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
1927
- }
1928
- }
1929
-
1930
- return $data;
1931
  }
1932
 
1933
  /**
1934
- * Check if add-on installed and activated on site.
1935
  *
1936
  * @author Vova Feldman (@svovaf)
1937
- * @since 1.0.6
1938
  *
1939
- * @param string|number $slug_or_id
1940
  *
1941
  * @return bool
1942
  */
1943
- function is_addon_activated( $slug_or_id ) {
1944
- return self::has_instance( $slug_or_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1945
  }
1946
 
1947
  /**
@@ -1975,7 +2641,15 @@
1975
  self::instance( $slug )->get_plugin_basename();
1976
  }
1977
 
1978
- return $slug . '/' . $slug . '.php';
 
 
 
 
 
 
 
 
1979
  }
1980
 
1981
  /**
@@ -2008,7 +2682,7 @@
2008
  * @return bool
2009
  */
2010
  function has_installed_addons() {
2011
- if ( ! $this->_has_addons() ) {
2012
  return false;
2013
  }
2014
 
@@ -2020,192 +2694,491 @@
2020
  }
2021
  }
2022
 
2023
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2024
  }
2025
 
2026
  /**
2027
- * Tell Freemius that the current plugin is an add-on.
2028
  *
2029
  * @author Vova Feldman (@svovaf)
2030
- * @since 1.0.6
2031
- *
2032
- * @param number $parent_plugin_id The parent plugin ID
2033
  */
2034
- function init_addon( $parent_plugin_id ) {
2035
- $this->_plugin->parent_plugin_id = $parent_plugin_id;
2036
  }
2037
 
2038
  /**
2039
  * @author Vova Feldman (@svovaf)
2040
- * @since 1.0.6
2041
- *
2042
- * @return bool
2043
  */
2044
- function is_addon() {
2045
- return isset( $this->_plugin->parent_plugin_id ) && is_numeric( $this->_plugin->parent_plugin_id );
2046
- }
2047
 
2048
- #endregion ------------------------------------------------------------------
 
 
2049
 
2050
- #region Sandbox ------------------------------------------------------------------
 
 
 
2051
 
2052
  /**
2053
- * Set Freemius into sandbox mode for debugging.
2054
  *
2055
  * @author Vova Feldman (@svovaf)
2056
- * @since 1.0.4
2057
  *
2058
- * @param string $secret_key
2059
  */
2060
- function init_sandbox( $secret_key ) {
2061
- $this->_plugin->secret_key = $secret_key;
2062
 
2063
- // Update plugin details.
2064
- FS_Plugin_Manager::instance( $this->_slug )->update( $this->_plugin, true );
 
 
 
2065
  }
2066
 
2067
  /**
2068
- * Check if running payments in sandbox mode.
2069
  *
2070
  * @author Vova Feldman (@svovaf)
2071
- * @since 1.0.4
2072
  *
2073
- * @return bool
2074
  */
2075
- function is_payments_sandbox() {
2076
- return ( ! $this->is_live() ) || isset( $this->_plugin->secret_key );
 
 
2077
  }
2078
 
2079
- #endregion Sandbox ------------------------------------------------------------------
 
 
2080
 
2081
  /**
2082
- * Check if running test vs. live plugin.
2083
- *
2084
  * @author Vova Feldman (@svovaf)
2085
- * @since 1.0.5
2086
  *
2087
  * @return bool
2088
  */
2089
- function is_live() {
2090
- return $this->_plugin->is_live;
 
 
 
 
 
2091
  }
2092
 
2093
  /**
2094
- * Check if the user skipped connecting the account with Freemius.
2095
  *
2096
  * @author Vova Feldman (@svovaf)
2097
- * @since 1.0.7
2098
- *
2099
- * @return bool
2100
  */
2101
- function is_anonymous() {
2102
- if ( ! isset( $this->_is_anonymous ) ) {
2103
- if ( ! isset( $this->_storage->is_anonymous ) ) {
2104
- // Not skipped.
2105
- $this->_is_anonymous = false;
2106
- } else if ( is_bool( $this->_storage->is_anonymous ) ) {
2107
- // For back compatibility, since the variable was boolean before.
2108
- $this->_is_anonymous = $this->_storage->is_anonymous;
2109
 
2110
- // Upgrade stored data format to 1.1.3 format.
2111
- $this->set_anonymous_mode( $this->_storage->is_anonymous );
2112
- } else {
2113
- // Version 1.1.3 and higher.
2114
- $this->_is_anonymous = $this->_storage->is_anonymous['is'];
2115
- }
2116
- }
2117
 
2118
- return $this->_is_anonymous;
 
 
 
 
 
 
 
 
 
 
 
2119
  }
2120
 
2121
  /**
2122
- * Check if user connected his account and install pending email activation.
 
 
 
2123
  *
2124
  * @author Vova Feldman (@svovaf)
2125
- * @since 1.0.7
2126
  *
2127
- * @return bool
2128
  */
2129
- function is_pending_activation() {
2130
- return $this->_storage->get( 'is_pending_activation', false );
2131
- }
2132
 
2133
- /**
2134
- * Check if plugin must be WordPress.org compliant.
2135
- *
2136
- * @since 1.0.7
2137
- *
2138
- * @return bool
2139
- */
2140
- function is_org_repo_compliant() {
2141
- return $this->_is_org_compliant;
2142
  }
2143
 
2144
  /**
2145
- * Background sync every 24 hours.
2146
  *
2147
  * @author Vova Feldman (@svovaf)
2148
- * @since 1.0.4
2149
  *
2150
- * @return bool If function actually executed the sync in this iteration.
2151
  */
2152
- private function _background_sync() {
2153
  $this->_logger->entrance();
2154
 
2155
- // Don't sync license on AJAX calls.
2156
- if ( $this->is_ajax() ) {
2157
  return false;
2158
  }
2159
 
2160
- // Asked to sync explicitly, no need for background sync.
2161
- if ( fs_request_is_action( $this->_slug . '_sync_license' ) ) {
2162
- return false;
2163
- }
2164
 
2165
- // Check if API is not down.
2166
- if ( FS_Api::is_temporary_down() ) {
2167
- return false;
2168
- }
 
 
 
 
 
2169
 
2170
- $sync_timestamp = $this->_storage->get( 'sync_timestamp' );
 
 
 
 
 
2171
 
2172
- if ( ! is_numeric( $sync_timestamp ) || $sync_timestamp >= time() ) {
2173
- // If updated not set or happens to be in the future, set as if was 24 hours earlier.
2174
- $sync_timestamp = time() - WP_FS__TIME_24_HOURS_IN_SEC;
2175
- $this->_storage->sync_timestamp = $sync_timestamp;
2176
  }
2177
 
2178
- if ( ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE && fs_request_has( 'background_sync' ) ) ||
2179
- ( $sync_timestamp <= time() - WP_FS__TIME_24_HOURS_IN_SEC )
2180
- ) {
2181
-
2182
- if ( $this->is_registered() ) {
2183
- // Initiate background plan sync.
2184
- $this->_sync_license( true );
2185
-
2186
- if ( $this->is_paying() ) {
2187
- // Check for plugin updates.
2188
- $this->_check_updates( true );
2189
- }
2190
- }
2191
 
2192
- if ( ! $this->is_addon() ) {
2193
- if ( $this->is_registered() || $this->_has_addons ) {
2194
- // Try to fetch add-ons if registered or if plugin
2195
- // declared that it has add-ons.
2196
- $this->_sync_addons();
2197
- }
2198
- }
2199
 
2200
- // Update last sync timestamp.
2201
- $this->_storage->sync_timestamp = time();
 
 
 
 
2202
 
2203
- return true;
2204
- }
2205
 
2206
- return false;
2207
  }
2208
 
 
 
2209
  /**
2210
  * Show a notice that activation is currently pending.
2211
  *
@@ -2216,7 +3189,7 @@
2216
  */
2217
  function _add_pending_activation_notice( $email = false ) {
2218
  if ( ! is_string( $email ) ) {
2219
- $current_user = wp_get_current_user();
2220
  $email = $current_user->user_email;
2221
  }
2222
 
@@ -2279,7 +3252,7 @@
2279
  if ( ! $this->is_addon() && ! $this->is_registered() && ! $this->is_anonymous() ) {
2280
  if ( ! $this->is_pending_activation() ) {
2281
  if ( ! $this->_menu->is_activation_page() ) {
2282
- if ( $this->is_plugin_new_install() ) {
2283
  // Show notice for new plugin installations.
2284
  $this->_admin_notices->add(
2285
  sprintf(
@@ -2310,6 +3283,20 @@
2310
  'update-nag'
2311
  );
2312
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2313
  }
2314
  }
2315
  }
@@ -2333,6 +3320,55 @@
2333
 
2334
  fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
2335
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2336
  /**
2337
  * Return current page's URL.
2338
  *
@@ -2461,12 +3497,15 @@
2461
  return;
2462
  }
2463
 
 
 
2464
  // Clear API cache on activation.
2465
  FS_Api::clear_cache();
2466
 
2467
  if ( $this->is_registered() ) {
2468
- // Send re-activation event and sync.
2469
- $this->sync_install( array(), true );
 
2470
 
2471
  /**
2472
  * @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.
@@ -2501,7 +3540,7 @@
2501
  * the first time that the plugin installed on the site, or the plugin was installed
2502
  * before but didn't have Freemius integrated.
2503
  *
2504
- * Since register_activation_hook() do NOT fires since 3.1, and only fires
2505
  * on manual activation via the dashboard, is_plugin_activation() is TRUE
2506
  * only after immediate activation.
2507
  *
@@ -2511,10 +3550,20 @@
2511
  $this->_storage->is_plugin_new_install = empty( $this->_storage->plugin_last_version );
2512
  }
2513
 
2514
- if ( $this->has_api_connectivity( true ) ) {
2515
  // Store hint that the plugin was just activated to enable auto-redirection to settings.
2516
  add_option( "fs_{$this->_slug}_activated", true );
2517
  }
 
 
 
 
 
 
 
 
 
 
2518
  }
2519
 
2520
  /**
@@ -2550,6 +3599,14 @@
2550
 
2551
  self::$_accounts->store();
2552
 
 
 
 
 
 
 
 
 
2553
  // Clear all storage data.
2554
  $this->_storage->clear_all( true, array(
2555
  'connectivity_test',
@@ -2580,21 +3637,28 @@
2580
  unset( $this->_storage->sticky_optin_added );
2581
  }
2582
 
2583
- if ( ! $this->has_api_connectivity() ) {
2584
- // Reset connectivity test cache.
2585
- unset( $this->_storage->connectivity_test );
2586
- }
2587
-
2588
  if ( ! isset( $this->_storage->is_plugin_new_install ) ) {
2589
  // Remember that plugin was already installed.
2590
  $this->_storage->is_plugin_new_install = false;
2591
  }
2592
 
 
 
 
 
 
 
 
2593
  if ( $this->is_registered() ) {
2594
  // Send deactivation event.
2595
  $this->sync_install( array(
2596
  'is_active' => false,
2597
  ) );
 
 
 
 
 
2598
  }
2599
 
2600
  // Clear API cache on deactivation.
@@ -2674,36 +3738,276 @@
2674
  private function skip_connection() {
2675
  $this->_logger->entrance();
2676
 
2677
- $this->_admin_notices->remove_sticky( 'connect_account' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2678
 
2679
- $this->set_anonymous_mode();
 
2680
 
2681
- // Send anonymous skip event.
2682
- // No user identified info nor any tracking will be sent after the user skips the opt-in.
2683
- $this->get_api_plugin_scope()->call( 'skip.json', 'put', array(
2684
- 'uid' => $this->get_anonymous_id(),
2685
- ) );
2686
- }
2687
 
2688
- /**
2689
- * Plugin version update hook.
2690
- *
2691
- * @author Vova Feldman (@svovaf)
2692
- * @since 1.0.4
2693
- */
2694
- private function update_plugin_version_event() {
2695
- $this->_logger->entrance( 'slug = ' . $this->_slug );
2696
 
2697
- // Send update event.
2698
- $site = $this->send_install_update( array(), true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2699
 
2700
- if ( false !== $site && ! $this->is_api_error( $site ) ) {
2701
- $this->_site = new FS_Site( $site );
2702
- $this->_site->plan = $this->_get_plan_by_id( $site->plan_id );
2703
  }
2704
 
2705
- $this->_site->version = $this->get_plugin_version();
2706
- $this->_store_site( true );
2707
  }
2708
 
2709
  /**
@@ -2712,11 +4016,36 @@
2712
  * @author Vova Feldman (@svovaf)
2713
  * @since 1.1.2
2714
  *
2715
- * @param string[] string $override
 
 
2716
  *
2717
  * @return array
2718
  */
2719
- private function get_install_data_for_api( $override = array() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2720
  return array_merge( array(
2721
  'version' => $this->get_plugin_version(),
2722
  'is_premium' => $this->is_premium(),
@@ -2766,7 +4095,10 @@
2766
  } else {
2767
  $special[ $p ] = $v;
2768
 
2769
- if ( isset( $override[ $p ] ) ) {
 
 
 
2770
  $special_override = true;
2771
  }
2772
  }
@@ -2775,15 +4107,27 @@
2775
  if ( $special_override || 0 < count( $params ) ) {
2776
  // Add special params only if has at least one
2777
  // standard param, or if explicitly requested to
2778
- // override a special param or a pram which is not exist
2779
  // in the install object.
2780
  $params = array_merge( $params, $special );
2781
  }
2782
  }
2783
 
2784
  if ( 0 < count( $params ) ) {
 
 
 
 
 
2785
  // Send updated values to FS.
2786
- return $this->get_api_site_scope()->call( '/', 'put', $params );
 
 
 
 
 
 
 
2787
  }
2788
 
2789
  return false;
@@ -2822,6 +4166,94 @@
2822
  $this->_store_site( true );
2823
  }
2824
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2825
  /**
2826
  * Plugin uninstall hook.
2827
  *
@@ -2837,16 +4269,22 @@
2837
  return;
2838
  }
2839
 
2840
- $params = array();
 
2841
  if ( isset( $this->_storage->uninstall_reason ) ) {
2842
- $params['reason_id'] = $this->_storage->uninstall_reason->id;
2843
- $params['reason_info'] = $this->_storage->uninstall_reason->info;
 
2844
  }
2845
 
2846
- if ( ! $this->is_registered() && isset( $this->_storage->uninstall_reason ) ) {
2847
  // Send anonymous uninstall event only if user submitted a feedback.
2848
- $params['uid'] = $this->get_anonymous_id();
2849
- $this->get_api_plugin_scope()->call( 'uninstall.json', 'put', $params );
 
 
 
 
2850
  } else {
2851
  // Send uninstall event.
2852
  $this->send_install_update( array_merge( $params, array(
@@ -2945,7 +4383,17 @@
2945
  if ( ! isset( $this->_plugin_data ) ) {
2946
  self::require_plugin_essentials();
2947
 
2948
- $this->_plugin_data = get_plugin_data( $this->_plugin_main_file_path );
 
 
 
 
 
 
 
 
 
 
2949
  }
2950
 
2951
  return $this->_plugin_data;
@@ -3047,7 +4495,7 @@
3047
 
3048
  $this->_logger->departure( 'Version = ' . $plugin_data['Version'] );
3049
 
3050
- return $plugin_data['Version'];
3051
  }
3052
 
3053
  /**
@@ -3265,25 +4713,27 @@
3265
  }
3266
 
3267
  /**
 
 
3268
  * @author Vova Feldman (@svovaf)
3269
  * @since 1.0.6
3270
  *
 
 
3271
  * @return FS_Plugin[]|false
3272
  */
3273
  function get_addons() {
3274
  $this->_logger->entrance();
3275
 
3276
- $addons = self::get_all_addons();
3277
-
3278
- if ( ! is_array( $addons ) ||
3279
- ! isset( $addons[ $this->_plugin->id ] ) ||
3280
- ! is_array( $addons[ $this->_plugin->id ] ) ||
3281
- 0 === count( $addons[ $this->_plugin->id ] )
3282
- ) {
3283
  return false;
3284
  }
3285
 
3286
- return $addons[ $this->_plugin->id ];
 
 
 
 
3287
  }
3288
 
3289
  /**
@@ -3366,7 +4816,7 @@
3366
 
3367
  if ( is_array( $addons ) ) {
3368
  foreach ( $addons as $addon ) {
3369
- if ( $slug == $addon->slug ) {
3370
  return $addon;
3371
  }
3372
  }
@@ -3436,8 +4886,25 @@
3436
  return false;
3437
  }
3438
 
3439
- // Paid plan beats trial.
3440
- return $this->is_free_plan() && $this->_site->is_trial();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3441
  }
3442
 
3443
  /**
@@ -3476,7 +4943,7 @@
3476
  }
3477
 
3478
  /**
3479
- * Check if the user has an activated and valid paid license on current plugin's install.
3480
  *
3481
  * @since 1.0.9
3482
  *
@@ -3489,10 +4956,14 @@
3489
  return false;
3490
  }
3491
 
 
 
 
 
3492
  return (
3493
  ! $this->is_trial() &&
3494
  'free' !== $this->_site->plan->name &&
3495
- $this->has_features_enabled_license()
3496
  );
3497
  }
3498
 
@@ -3507,6 +4978,10 @@
3507
  return true;
3508
  }
3509
 
 
 
 
 
3510
  return (
3511
  'free' === $this->_site->plan->name ||
3512
  ! $this->has_features_enabled_license()
@@ -3527,6 +5002,18 @@
3527
  return ( false !== $premium_license );
3528
  }
3529
 
 
 
 
 
 
 
 
 
 
 
 
 
3530
  /**
3531
  * @author Vova Feldman (@svovaf)
3532
  * @since 1.0.5
@@ -3536,6 +5023,10 @@
3536
  function _get_available_premium_license() {
3537
  $this->_logger->entrance();
3538
 
 
 
 
 
3539
  if ( is_array( $this->_licenses ) ) {
3540
  foreach ( $this->_licenses as $license ) {
3541
  if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
@@ -3591,17 +5082,43 @@
3591
  return false;
3592
  }
3593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3594
  /**
3595
  * Sync local plugin plans with remote server.
3596
  *
3597
  * @author Vova Feldman (@svovaf)
3598
  * @since 1.0.6
3599
  *
 
 
3600
  * @return FS_Plugin_License[]|object
3601
  */
3602
- function _sync_licenses() {
3603
- $licenses = $this->_fetch_licenses();
3604
- if ( ! isset( $licenses->error ) ) {
3605
  $this->_licenses = $licenses;
3606
  $this->_store_licenses();
3607
  }
@@ -3629,7 +5146,7 @@
3629
  return false;
3630
  }
3631
 
3632
- if ( ! is_array( $this->_licenses ) || 0 === count( $this->_licenses ) ) {
3633
  $this->_sync_licenses();
3634
  }
3635
 
@@ -3831,7 +5348,8 @@
3831
  * @return bool
3832
  */
3833
  function has_paid_plan() {
3834
- return $this->_has_paid_plans || FS_Plan_Manager::instance()->has_paid_plan( $this->_plans );
 
3835
  }
3836
 
3837
  /**
@@ -3861,7 +5379,148 @@
3861
  * @return bool
3862
  */
3863
  function has_free_plan() {
3864
- return FS_Plan_Manager::instance()->has_free_plan( $this->_plans );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3865
  }
3866
 
3867
  #region URL Generators
@@ -3872,26 +5531,27 @@
3872
  * @author Vova Feldman (@svovaf)
3873
  * @since 1.0.2
3874
  *
3875
- * @uses pricing_url
3876
  *
3877
  * @param string $period Billing cycle
 
3878
  *
3879
  * @return string
3880
  */
3881
- function get_upgrade_url( $period = WP_FS__PERIOD_ANNUALLY ) {
3882
- return $this->pricing_url( $period );
3883
  }
3884
 
3885
  /**
3886
  * @author Vova Feldman (@svovaf)
3887
  * @since 1.0.9
3888
  *
3889
- * @uses get_upgrade_url
3890
  *
3891
  * @return string
3892
  */
3893
  function get_trial_url() {
3894
- return $this->get_upgrade_url( 'trial' );
3895
  }
3896
 
3897
  /**
@@ -3900,55 +5560,87 @@
3900
  * @author Vova Feldman (@svovaf)
3901
  * @since 1.0.4
3902
  *
3903
- * @param string $period Billing cycle
 
 
3904
  *
3905
  * @return string
3906
  */
3907
- function pricing_url( $period = WP_FS__PERIOD_ANNUALLY ) {
3908
  $this->_logger->entrance();
3909
 
3910
- return $this->_get_admin_page_url( 'pricing', array( 'billing_cycle' => $period ) );
 
 
 
 
 
 
 
 
3911
  }
3912
 
3913
  /**
3914
  * Checkout page URL.
3915
  *
3916
- * @author Vova Feldman (@svovaf)
3917
- * @since 1.0.6
3918
  *
3919
- * @param string $period Billing cycle
3920
- * @param bool|string $plan_name
3921
- * @param bool|number $plan_id
3922
- * @param bool|int $licenses
3923
  *
3924
  * @return string
3925
  */
3926
  function checkout_url(
3927
- $period = WP_FS__PERIOD_ANNUALLY,
3928
- $plan_name = false,
3929
- $plan_id = false,
3930
- $licenses = false
3931
  ) {
3932
  $this->_logger->entrance();
3933
 
3934
  $params = array(
3935
  'checkout' => 'true',
3936
- 'billing_cycle' => $period,
3937
  );
3938
 
3939
- if ( false !== $plan_name ) {
3940
- $params['plan_name'] = $plan_name;
3941
- }
3942
- if ( false !== $plan_id ) {
3943
- $params['plan_id'] = $plan_id;
3944
- }
3945
- if ( false !== $licenses ) {
3946
- $params['licenses'] = $licenses;
3947
  }
3948
 
 
 
 
 
 
3949
  return $this->_get_admin_page_url( 'pricing', $params );
3950
  }
3951
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3952
  #endregion
3953
 
3954
  #endregion ------------------------------------------------------------------
@@ -3959,26 +5651,54 @@
3959
  * @author Vova Feldman (@svovaf)
3960
  * @since 1.0.5
3961
  *
 
 
3962
  * @return bool
3963
  */
3964
- function _has_addons() {
3965
  $this->_logger->entrance();
3966
 
3967
- return ( $this->_has_addons || false !== $this->get_addons() );
3968
  }
3969
 
3970
  /**
3971
  * Check if plugin can work in anonymous mode.
3972
  *
3973
- * @author Vova Feldman (@svovaf)
3974
- * @since 1.0.9
3975
  *
3976
  * @return bool
 
 
3977
  */
3978
  function enable_anonymous() {
3979
  return $this->_enable_anonymous;
3980
  }
3981
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3982
  /**
3983
  * Check if feature supported with current site's plan.
3984
  *
@@ -4017,6 +5737,67 @@
4017
  return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
4018
  }
4019
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4020
  /**
4021
  * Check if running in HTTPS and if site's plan matching the specified plan.
4022
  *
@@ -4041,6 +5822,12 @@
4041
  * @return string
4042
  */
4043
  function _get_admin_page_url( $page = '', $params = array() ) {
 
 
 
 
 
 
4044
  if ( ! $this->_menu->is_top_level() ) {
4045
  $parent_slug = $this->_menu->get_parent_slug();
4046
  $menu_file = ( false !== strpos( $parent_slug, '.php' ) ) ?
@@ -4071,6 +5858,30 @@
4071
  }
4072
  }
4073
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4074
 
4075
  /**
4076
  * Plugin's account URL.
@@ -4097,6 +5908,25 @@
4097
  $this->_get_admin_page_url( 'account', $params );
4098
  }
4099
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4100
  /**
4101
  * Plugin's account URL.
4102
  *
@@ -4391,12 +6221,210 @@
4391
  $this->_plans = $plans;
4392
  }
4393
 
4394
- $this->send_install_update( array(), true );
4395
 
4396
  $this->_store_account();
4397
 
4398
  }
4399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4400
  /**
4401
  * Set user and site identities.
4402
  *
@@ -4424,12 +6452,17 @@
4424
  $this->_enrich_site_trial_plan( true );
4425
  }
4426
 
 
 
 
4427
  $this->do_action( 'after_account_connection', $user, $site );
4428
 
4429
  if ( is_numeric( $site->license_id ) ) {
4430
  $this->_license = $this->_get_license_by_id( $site->license_id );
4431
  }
4432
 
 
 
4433
  if ( $this->is_pending_activation() ) {
4434
  // Remove pending activation sticky notice (if still exist).
4435
  $this->_admin_notices->remove_sticky( 'activation_pending' );
@@ -4450,10 +6483,7 @@
4450
  sprintf(
4451
  __fs( 'activation-with-plan-x-message', $this->_slug ),
4452
  $this->_site->plan->title
4453
- ) . ' ' . $this->_get_latest_download_link( sprintf(
4454
- __fs( 'download-latest-x-version', $this->_slug ),
4455
- $this->_site->plan->title
4456
- ) ),
4457
  'plan_upgraded',
4458
  __fs( 'yee-haw', $this->_slug ) . '!'
4459
  );
@@ -4469,19 +6499,21 @@
4469
  if ( is_numeric( $plugin_id ) ) {
4470
  if ( $plugin_id != $this->_plugin->id ) {
4471
  // Add-on was installed - sync license right after install.
4472
- if ( $redirect && fs_redirect( fs_nonce_url( $this->_get_admin_page_url(
4473
- 'account',
4474
- array(
4475
- 'fs_action' => $this->_slug . '_sync_license',
4476
- 'plugin_id' => $plugin_id
4477
- )
4478
- ), $this->_slug . '_sync_license' ) )
4479
  ) {
4480
  exit();
4481
  }
4482
 
4483
  }
4484
  } else {
 
 
 
 
 
 
 
 
4485
  // Reload the page with the keys.
4486
  if ( $redirect && fs_redirect( $this->get_after_activation_url( 'after_connect_url' ) ) ) {
4487
  exit();
@@ -4505,44 +6537,86 @@
4505
  if ( fs_request_is_action( $this->_slug . '_activate_new' ) ) {
4506
  // check_admin_referer( $this->_slug . '_activate_new' );
4507
 
4508
- $this->_admin_notices->remove_sticky( 'connect_account' );
4509
-
4510
  if ( fs_request_has( 'user_secret_key' ) ) {
4511
- $user = new FS_User();
4512
- $user->id = fs_request_get( 'user_id' );
4513
- $user->public_key = fs_request_get( 'user_public_key' );
4514
- $user->secret_key = fs_request_get( 'user_secret_key' );
4515
-
4516
- $this->_user = $user;
4517
- $user_result = $this->get_api_user_scope()->get();
4518
- $user = new FS_User( $user_result );
4519
- $this->_user = $user;
4520
-
4521
- $site = new FS_Site();
4522
- $site->id = fs_request_get( 'install_id' );
4523
- $site->public_key = fs_request_get( 'install_public_key' );
4524
- $site->secret_key = fs_request_get( 'install_secret_key' );
4525
-
4526
- $this->_site = $site;
4527
- $site_result = $this->get_api_site_scope()->get();
4528
- $site = new FS_Site( $site_result );
4529
- $this->_site = $site;
4530
-
4531
- $this->setup_account( $this->_user, $this->_site );
4532
  } else if ( fs_request_has( 'pending_activation' ) ) {
4533
- // Install must be activated via email since
4534
- // user with the same email already exist.
4535
- $this->_storage->is_pending_activation = true;
4536
- $this->_add_pending_activation_notice( fs_request_get( 'user_email' ) );
4537
-
4538
- // Reload the page with with pending activation message.
4539
- if ( fs_redirect( $this->get_after_activation_url( 'after_pending_connect_url' ) ) ) {
4540
- exit();
4541
- }
4542
  }
4543
  }
4544
  }
4545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4546
  /**
4547
  * Install plugin with current logged WP user info.
4548
  *
@@ -4559,46 +6633,76 @@
4559
  if ( fs_request_is_action( $this->_slug . '_activate_existing' ) && fs_request_is_post() ) {
4560
  // check_admin_referer( 'activate_existing_' . $this->_plugin->public_key );
4561
 
4562
- $this->_admin_notices->remove_sticky( 'connect_account' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4563
 
4564
- // Get current logged WP user.
4565
- $current_user = wp_get_current_user();
 
 
 
4566
 
4567
- // Find the relevant FS user by the email.
4568
- $user = self::_get_user_by_email( $current_user->user_email );
 
4569
 
4570
- // We have to set the user before getting user scope API handler.
4571
- $this->_user = $user;
 
 
 
 
4572
 
4573
- // Install the plugin.
4574
- $install = $this->get_api_user_scope()->call(
4575
- "/plugins/{$this->get_id()}/installs.json",
4576
- 'post',
4577
- $this->get_install_data_for_api( array(
4578
- 'uid' => $this->get_anonymous_id(),
4579
- ) )
4580
  );
4581
 
4582
- if ( isset( $install->error ) ) {
4583
- $this->_admin_notices->add(
4584
- sprintf( __fs( 'could-not-activate-x', $this->_slug ), $this->get_plugin_name() ) . ' ' .
4585
- __fs( 'contact-us-with-error-message', $this->_slug ) . ' ' . '<b>' . $install->error->message . '</b>',
4586
- __fs( 'oops', $this->_slug ) . '...',
4587
- 'error'
4588
- );
4589
-
4590
- return;
4591
  }
4592
 
4593
- $site = new FS_Site( $install );
4594
- $this->_site = $site;
 
 
 
4595
  // $this->_enrich_site_plan( false );
4596
 
4597
  // $this->_set_account( $user, $site );
4598
  // $this->_sync_plans();
4599
 
4600
- $this->setup_account( $this->_user, $this->_site );
4601
- }
 
4602
  }
4603
 
4604
  /**
@@ -4621,7 +6725,7 @@
4621
  'post',
4622
  $this->get_install_data_for_api( array(
4623
  'uid' => $this->get_anonymous_id(),
4624
- ) )
4625
  );
4626
 
4627
  if ( isset( $addon_install->error ) ) {
@@ -4678,15 +6782,17 @@
4678
  * @since 1.0.9
4679
  */
4680
  function _prepare_admin_menu() {
4681
- if ( ! $this->is_on() ) {
4682
- return;
4683
- }
4684
 
4685
- if ( ! $this->has_api_connectivity() && ! $this->enable_anonymous() ) {
4686
  $this->_menu->remove_menu_item();
4687
  } else {
4688
- $this->add_submenu_items();
 
4689
  $this->add_menu_action();
 
4690
  }
4691
  }
4692
 
@@ -4728,7 +6834,7 @@
4728
  foreach ( $this->_menu_items as $priority => $items ) {
4729
  foreach ( $items as $item ) {
4730
  if ( isset( $item['url'] ) ) {
4731
- if ( $page === $item['menu_slug'] ) {
4732
  $this->_logger->log( 'Redirecting to ' . $item['url'] );
4733
 
4734
  fs_redirect( $item['url'] );
@@ -4818,6 +6924,30 @@
4818
  }
4819
  }
4820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4821
  /**
4822
  * @author Vova Feldman (@svovaf)
4823
  * @since 1.0.0
@@ -4839,10 +6969,8 @@
4839
  private function add_submenu_items() {
4840
  $this->_logger->entrance();
4841
 
4842
- $this->do_action( 'before_admin_menu_init' );
4843
-
4844
  if ( ! $this->is_addon() ) {
4845
- if ( $this->is_registered() || $this->is_anonymous() ) {
4846
  if ( $this->is_registered() ) {
4847
  // Add user account page.
4848
  $this->add_submenu_item(
@@ -4869,7 +6997,7 @@
4869
  $this->_menu->is_submenu_item_visible( 'contact' )
4870
  );
4871
 
4872
- if ( $this->_has_addons() ) {
4873
  $this->add_submenu_item(
4874
  __fs( 'add-ons', $this->_slug ),
4875
  array( &$this, '_addons_page_render' ),
@@ -4928,10 +7056,14 @@
4928
  '<span class="fs-submenu-item">%s</span>' :
4929
  '<span class="fs-submenu-item fs-sub">%s</span>';
4930
 
 
 
4931
  ksort( $this->_menu_items );
4932
 
4933
  foreach ( $this->_menu_items as $priority => $items ) {
4934
  foreach ( $items as $item ) {
 
 
4935
  if ( ! isset( $item['url'] ) ) {
4936
  $hook = add_submenu_page(
4937
  $item['show_submenu'] ?
@@ -4939,7 +7071,7 @@
4939
  null,
4940
  $item['page_title'],
4941
  sprintf( $item_template, $item['menu_title'] ),
4942
- $item['capability'],
4943
  $item['menu_slug'],
4944
  $item['render_function']
4945
  );
@@ -4952,7 +7084,7 @@
4952
  $this->get_top_level_menu_slug(),
4953
  $item['page_title'],
4954
  sprintf( $item_template, $item['menu_title'] ),
4955
- $item['capability'],
4956
  $item['menu_slug'],
4957
  array( $this, '' )
4958
  );
@@ -4971,7 +7103,23 @@
4971
  private function order_sub_submenu_items() {
4972
  global $submenu;
4973
 
4974
- $top_level_menu = &$submenu[ $this->_menu->get_top_level_menu_slug() ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4975
 
4976
  $all_submenu_items_after = array();
4977
 
@@ -5012,11 +7160,11 @@
5012
  *
5013
  * function _fs_show_support_menu( $is_visible, $menu_id ) {
5014
  * if ( 'support' === $menu_id ) {
5015
- * return _fs->is_registered();
5016
- * }
5017
- * return $is_visible;
5018
- * }
5019
- * _fs()->add_filter('is_submenu_visible', '_fs_show_support_menu', 10, 2);
5020
  *
5021
  */
5022
  function _add_default_submenu_items() {
@@ -5024,13 +7172,13 @@
5024
  return;
5025
  }
5026
 
5027
- if ( $this->is_registered() || $this->is_anonymous() ) {
5028
  if ( $this->_menu->is_submenu_item_visible( 'support' ) ) {
5029
  $this->add_submenu_link_item(
5030
  $this->apply_filters( 'support_forum_submenu', __fs( 'support-forum', $this->_slug ) ),
5031
  $this->apply_filters( 'support_forum_url', 'https://wordpress.org/support/plugin/' . $this->_slug ),
5032
  'wp-support-forum',
5033
- 'read',
5034
  50
5035
  );
5036
  }
@@ -5151,6 +7299,30 @@
5151
 
5152
  /* Actions / Hooks / Filters
5153
  ------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5154
  /**
5155
  * Do action, specific for the current context plugin.
5156
  *
@@ -5169,7 +7341,7 @@
5169
  $args = func_get_args();
5170
 
5171
  call_user_func_array( 'do_action', array_merge(
5172
- array( 'fs_' . $tag . '_' . $this->_slug ),
5173
  array_slice( $args, 1 ) )
5174
  );
5175
  }
@@ -5190,7 +7362,26 @@
5190
  function add_action( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
5191
  $this->_logger->entrance( $tag );
5192
 
5193
- add_action( 'fs_' . $tag . '_' . $this->_slug, $function_to_add, $priority, $accepted_args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5194
  }
5195
 
5196
  /**
@@ -5210,9 +7401,9 @@
5210
  $this->_logger->entrance( $tag );
5211
 
5212
  $args = func_get_args();
5213
- array_unshift($args, $this->_slug);
5214
 
5215
- return call_user_func_array( 'fs_apply_filter', $args);
5216
  }
5217
 
5218
  /**
@@ -5231,7 +7422,7 @@
5231
  function add_filter( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
5232
  $this->_logger->entrance( $tag );
5233
 
5234
- add_filter( 'fs_' . $tag . '_' . $this->_slug, $function_to_add, $priority, $accepted_args );
5235
  }
5236
 
5237
  /**
@@ -5250,7 +7441,7 @@
5250
  function has_filter( $tag, $function_to_check = false ) {
5251
  $this->_logger->entrance( $tag );
5252
 
5253
- return has_filter( 'fs_' . $tag . '_' . $this->_slug, $function_to_check );
5254
  }
5255
 
5256
  /**
@@ -5521,30 +7712,6 @@
5521
  }
5522
  }
5523
 
5524
- /**
5525
- * @author Vova Feldman (@svovaf)
5526
- * @since 1.0.5
5527
- * @uses FS_Api
5528
- *
5529
- * @param bool $flush
5530
- *
5531
- * @return object|\FS_Site
5532
- */
5533
- private function _fetch_site( $flush = false ) {
5534
- $this->_logger->entrance();
5535
- $api = $this->get_api_site_scope();
5536
-
5537
- $site = $api->get( '/', $flush );
5538
-
5539
- if ( ! isset( $site->error ) ) {
5540
- $site = new FS_Site( $site );
5541
- $site->slug = $this->_slug;
5542
- $site->version = $this->get_plugin_version();
5543
- }
5544
-
5545
- return $site;
5546
- }
5547
-
5548
  /**
5549
  * @param bool $store
5550
  *
@@ -5668,10 +7835,11 @@
5668
  * @uses FS_Api
5669
  *
5670
  * @param number|bool $plugin_id
 
5671
  *
5672
  * @return FS_Plugin_License[]|object
5673
  */
5674
- private function _fetch_licenses( $plugin_id = false ) {
5675
  $this->_logger->entrance();
5676
 
5677
  $api = $this->get_api_user_scope();
@@ -5682,14 +7850,75 @@
5682
 
5683
  $result = $api->get( "/plugins/{$plugin_id}/licenses.json", true );
5684
 
 
 
5685
  if ( ! isset( $result->error ) ) {
5686
  for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {
5687
  $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );
 
 
 
 
5688
  }
5689
 
5690
  $result = $result->licenses;
5691
  }
5692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5693
  return $result;
5694
  }
5695
 
@@ -5735,11 +7964,12 @@
5735
  * @since 1.0.4
5736
  *
5737
  * @param bool|number $plugin_id
 
5738
  *
5739
  * @return object|false New plugin tag info if exist.
5740
  */
5741
- private function _fetch_newer_version( $plugin_id = false ) {
5742
- $latest_tag = $this->_fetch_latest_version( $plugin_id );
5743
 
5744
  if ( ! is_object( $latest_tag ) ) {
5745
  return false;
@@ -5762,17 +7992,18 @@
5762
  * @since 1.0.5
5763
  *
5764
  * @param bool|number $plugin_id
 
5765
  *
5766
  * @return bool|FS_Plugin_Tag
5767
  */
5768
- function get_update( $plugin_id = false ) {
5769
  $this->_logger->entrance();
5770
 
5771
  if ( ! is_numeric( $plugin_id ) ) {
5772
  $plugin_id = $this->_plugin->id;
5773
  }
5774
 
5775
- $this->_check_updates( true, $plugin_id );
5776
  $updates = $this->get_all_updates();
5777
 
5778
  return isset( $updates[ $plugin_id ] ) && is_object( $updates[ $plugin_id ] ) ? $updates[ $plugin_id ] : false;
@@ -5781,8 +8012,10 @@
5781
  /**
5782
  * Check if site assigned with active license.
5783
  *
5784
- * @author Vova Feldman (@svovaf)
5785
- * @since 1.0.6
 
 
5786
  */
5787
  function has_active_license() {
5788
  return (
@@ -5792,6 +8025,21 @@
5792
  );
5793
  }
5794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5795
  /**
5796
  * Check if site assigned with license with enabled features.
5797
  *
@@ -5808,6 +8056,18 @@
5808
  );
5809
  }
5810
 
 
 
 
 
 
 
 
 
 
 
 
 
5811
  /**
5812
  * Sync site's plan.
5813
  *
@@ -5926,7 +8186,11 @@
5926
  private function _sync_plugin_license( $background = false ) {
5927
  $this->_logger->entrance();
5928
 
5929
- // Sync site info.
 
 
 
 
5930
  $site = $this->send_install_update( array(), true );
5931
 
5932
  $plan_change = 'none';
@@ -5967,17 +8231,29 @@
5967
  );
5968
  }
5969
  }
5970
- } else {
5971
- // Remove sticky API connectivity message.
5972
- self::$_global_admin_notices->remove_sticky('api_blocked');
5973
 
5974
- $site = new FS_Site( $site );
 
 
 
 
 
5975
 
5976
- // Sync licenses.
5977
- $this->_sync_licenses();
5978
 
5979
- // Sync plans.
5980
- $this->_sync_plans();
 
 
 
 
 
 
 
 
 
 
 
5981
 
5982
  // Check if plan / license changed.
5983
  if ( ! FS_Entity::equals( $site->plan, $this->_site->plan ) ||
@@ -5987,7 +8263,7 @@
5987
  // Check if license changed.
5988
  $site->license_id != $this->_site->license_id
5989
  ) {
5990
- if ( $site->is_trial() && ! $this->_site->is_trial() ) {
5991
  // New trial started.
5992
  $this->_site = $site;
5993
  $plan_change = 'trial_started';
@@ -5995,6 +8271,17 @@
5995
  // Store trial plan information.
5996
  $this->_enrich_site_trial_plan( true );
5997
 
 
 
 
 
 
 
 
 
 
 
 
5998
  } else if ( $this->_site->is_trial() && ! $site->is_trial() && ! is_numeric( $site->license_id ) ) {
5999
  // Was in trial, but now trial expired and no license ID.
6000
  // New trial started.
@@ -6008,9 +8295,19 @@
6008
  $is_free = $this->is_free_plan();
6009
 
6010
  // Make sure license exist and not expired.
6011
- $new_license = is_null( $site->license_id ) ? null : $this->_get_license_by_id( $site->license_id );
 
 
 
 
 
 
 
 
 
6012
 
6013
- if ( $is_free && ( ( ! is_object( $new_license ) || $new_license->is_expired() ) ) ) {
 
6014
  // The license is expired, so ignore upgrade method.
6015
  } else {
6016
  // License changed.
@@ -6045,110 +8342,121 @@
6045
  }
6046
  }
6047
 
6048
- switch ( $plan_change ) {
6049
- case 'none':
6050
- if ( ! $background && is_admin() ) {
6051
- $this->_admin_notices->add(
6052
- sprintf(
6053
- __fs( 'plan-did-not-change-message', $this->_slug ) . ' ' .
 
 
 
6054
  sprintf(
 
 
 
6055
  '<a href="%s">%s</a>',
6056
  $this->contact_url(
6057
  'bug',
6058
  sprintf( __fs( 'plan-did-not-change-email-message', $this->_slug ),
6059
- strtoupper( $this->_site->plan->name )
6060
  )
6061
  ),
6062
  __fs( 'contact-us-here', $this->_slug )
6063
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6064
  ),
6065
  __fs( 'hmm', $this->_slug ) . '...',
6066
  'error'
6067
  );
6068
- }
6069
- break;
6070
- case 'upgraded':
6071
- $this->_admin_notices->add_sticky(
6072
- sprintf(
6073
- __fs( 'plan-upgraded-message', $this->_slug ),
6074
- '<i>' . $this->get_plugin_name() . '</i>'
6075
- ) . ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
6076
- __fs( 'download-latest-x-version', $this->_slug ),
6077
- $this->_site->plan->title
6078
- ) )
6079
- ),
6080
- 'plan_upgraded',
6081
- __fs( 'yee-haw', $this->_slug ) . '!'
6082
- );
6083
-
6084
- $this->_admin_notices->remove_sticky( array(
6085
- 'trial_started',
6086
- 'trial_promotion',
6087
- 'trial_expired',
6088
- 'activation_complete',
6089
- ) );
6090
- break;
6091
- case 'changed':
6092
- $this->_admin_notices->add_sticky(
6093
- sprintf(
6094
- __fs( 'plan-changed-to-x-message', $this->_slug ),
6095
- $this->_site->plan->title
6096
- ),
6097
- 'plan_changed'
6098
- );
6099
-
6100
- $this->_admin_notices->remove_sticky( array(
6101
- 'trial_started',
6102
- 'trial_promotion',
6103
- 'trial_expired',
6104
- 'activation_complete',
6105
- ) );
6106
- break;
6107
- case 'downgraded':
6108
- $this->_admin_notices->add_sticky(
6109
- sprintf( __fs( 'license-expired-blocking-message', $this->_slug ) ),
6110
- 'license_expired',
6111
- __fs( 'hmm', $this->_slug ) . '...'
6112
- );
6113
- $this->_admin_notices->remove_sticky( 'plan_upgraded' );
6114
- break;
6115
- case 'expired':
6116
- $this->_admin_notices->add_sticky(
6117
- sprintf( __fs( 'license-expired-non-blocking-message', $this->_slug ), $this->_site->plan->title ),
6118
- 'license_expired',
6119
- __fs( 'hmm', $this->_slug ) . '...'
6120
- );
6121
- $this->_admin_notices->remove_sticky( 'plan_upgraded' );
6122
- break;
6123
- case 'trial_started':
6124
- $this->_admin_notices->add_sticky(
6125
- sprintf(
6126
- __fs( 'trial-started-message', $this->_slug ),
6127
- '<i>' . $this->get_plugin_name() . '</i>'
6128
- ) . ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
6129
- __fs( 'download-latest-x-version', $this->_slug ),
6130
- $this->_storage->trial_plan->title
6131
- ) ) ),
6132
- 'trial_started',
6133
- __fs( 'yee-haw', $this->_slug ) . '!'
6134
- );
6135
-
6136
- $this->_admin_notices->remove_sticky( array(
6137
- 'trial_promotion',
6138
- ) );
6139
- break;
6140
- case 'trial_expired':
6141
- $this->_admin_notices->add_sticky(
6142
- __fs( 'trial-expired-message', $this->_slug ),
6143
- 'trial_expired',
6144
- __fs( 'hmm', $this->_slug ) . '...'
6145
- );
6146
- $this->_admin_notices->remove_sticky( array(
6147
- 'trial_started',
6148
- 'trial_promotion',
6149
- 'plan_upgraded',
6150
- ) );
6151
- break;
6152
  }
6153
 
6154
  if ( 'none' !== $plan_change ) {
@@ -6165,20 +8473,58 @@
6165
  protected function _activate_license( $background = false ) {
6166
  $this->_logger->entrance();
6167
 
6168
- $premium_license = $this->_get_available_premium_license();
 
 
 
 
 
 
 
 
 
6169
 
6170
  if ( ! is_object( $premium_license ) ) {
6171
  return;
6172
  }
6173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6174
  $api = $this->get_api_site_scope();
6175
- $license = $api->call( "/licenses/{$premium_license->id}.json", 'put' );
6176
 
6177
- if ( isset( $license->error ) ) {
6178
  if ( ! $background ) {
6179
- $this->_admin_notices->add(
6180
- __fs( 'license-activation-failed-message', $this->_slug ) . '<br> ' .
6181
- __fs( 'server-error-message', $this->_slug ) . ' ' . var_export( $license->error, true ),
 
 
 
 
 
 
 
 
6182
  __fs( 'hmm', $this->_slug ) . '...',
6183
  'error'
6184
  );
@@ -6190,7 +8536,10 @@
6190
  $premium_license = new FS_Plugin_License( $license );
6191
 
6192
  // Updated site plan.
6193
- $this->_site->plan->id = $premium_license->plan_id;
 
 
 
6194
  $this->_update_site_license( $premium_license );
6195
  $this->_enrich_site_plan( false );
6196
 
@@ -6199,10 +8548,7 @@
6199
  if ( ! $background ) {
6200
  $this->_admin_notices->add_sticky(
6201
  __fs( 'license-activated-message', $this->_slug ) .
6202
- ( $this->is_premium() ? '' : ' ' . $this->_get_latest_download_link( sprintf(
6203
- __fs( 'download-latest-x-version', $this->_slug ),
6204
- $this->_site->plan->title
6205
- ) ) ),
6206
  'license_activated',
6207
  __fs( 'yee-haw', $this->_slug ) . '!'
6208
  );
@@ -6330,6 +8676,100 @@
6330
  }
6331
  }
6332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6333
  /**
6334
  * Cancel site trial.
6335
  *
@@ -6356,11 +8796,22 @@
6356
 
6357
  $trial_cancelled = false;
6358
 
6359
- if ( ! isset( $site->error ) ) {
6360
  $prev_trial_ends = $this->_site->trial_ends;
6361
 
6362
- // Update new site plan id.
6363
- $this->_site->trial_ends = $site->trial_ends;
 
 
 
 
 
 
 
 
 
 
 
6364
 
6365
  $trial_cancelled = ( $prev_trial_ends != $site->trial_ends );
6366
  } else {
@@ -6369,13 +8820,7 @@
6369
  }
6370
 
6371
  if ( $trial_cancelled ) {
6372
- // Remove previous sticky message about upgrade (if exist).
6373
- $this->_admin_notices->remove_sticky( 'plan_upgraded' );
6374
-
6375
- $this->_admin_notices->add(
6376
- sprintf( __fs( 'trial-cancel-message', $this->_slug ), $this->_storage->trial_plan->title )
6377
- );
6378
-
6379
  $this->_admin_notices->remove_sticky( array(
6380
  'trial_started',
6381
  'trial_promotion',
@@ -6387,6 +8832,14 @@
6387
 
6388
  // Clear trial plan information.
6389
  unset( $this->_storage->trial_plan );
 
 
 
 
 
 
 
 
6390
  } else {
6391
  $this->_admin_notices->add(
6392
  __fs( 'trial-cancel-failure-message', $this->_slug ),
@@ -6417,7 +8870,7 @@
6417
  * @return bool
6418
  */
6419
  private function _can_download_premium() {
6420
- return $this->has_active_license() ||
6421
  ( $this->is_trial() && ! $this->get_trial_plan()->is_free() );
6422
  }
6423
 
@@ -6454,15 +8907,30 @@
6454
  * @since 1.0.4
6455
  *
6456
  * @param bool|number $addon_id
 
6457
  *
6458
  * @return object|false Plugin latest tag info.
6459
  */
6460
- function _fetch_latest_version( $addon_id = false ) {
6461
- $tag = $this->get_api_site_or_plugin_scope()->get(
 
 
 
 
 
 
 
 
 
 
 
 
6462
  $this->_get_latest_version_endpoint( $addon_id, 'json' ),
6463
- true
6464
  );
 
6465
  $latest_version = ( is_object( $tag ) && isset( $tag->version ) ) ? $tag->version : 'couldn\'t get';
 
6466
  $this->_logger->departure( 'Latest version ' . $latest_version );
6467
 
6468
  return ( is_object( $tag ) && isset( $tag->version ) ) ? $tag : false;
@@ -6470,46 +8938,6 @@
6470
 
6471
  #region Download Plugin ------------------------------------------------------------------
6472
 
6473
- /**
6474
- * Download latest plugin version, based on plan.
6475
- * The download will be fetched via the API first.
6476
- *
6477
- * @author Vova Feldman (@svovaf)
6478
- * @since 1.0.4
6479
- *
6480
- * @param bool|number $plugin_id
6481
- *
6482
- * @uses FS_Api
6483
- *
6484
- * @deprecated
6485
- */
6486
- private function _download_latest( $plugin_id = false ) {
6487
- $this->_logger->entrance();
6488
-
6489
- $is_addon = $this->_is_addon_id( $plugin_id );
6490
-
6491
- $is_premium = $this->_can_download_premium();
6492
-
6493
- $latest = $this->get_api_site_scope()->call(
6494
- $this->_get_latest_version_endpoint( $plugin_id, 'zip' )
6495
- );
6496
-
6497
- $slug = $this->_slug;
6498
- if ( $is_addon ) {
6499
- $addon = $this->get_addon( $plugin_id );
6500
- $slug = is_object( $addon ) ? $addon->slug : 'addon';
6501
- }
6502
-
6503
- if ( ! is_object( $latest ) ) {
6504
- header( "Content-Type: application/zip" );
6505
- header( "Content-Disposition: attachment; filename={$slug}" . ( ! $is_addon && $is_premium ? '-premium' : '' ) . ".zip" );
6506
- header( "Content-Length: " . strlen( $latest ) );
6507
- echo $latest;
6508
-
6509
- exit();
6510
- }
6511
- }
6512
-
6513
  /**
6514
  * Download latest plugin version, based on plan.
6515
  *
@@ -6549,6 +8977,24 @@
6549
  );
6550
  }
6551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6552
  /**
6553
  * Get latest plugin download link.
6554
  *
@@ -6600,12 +9046,13 @@
6600
  * @param bool $background Hints the method if it's a background updates check. If false, it means that
6601
  * was initiated by the admin.
6602
  * @param bool|number $plugin_id
 
6603
  */
6604
- private function _check_updates( $background = false, $plugin_id = false ) {
6605
  $this->_logger->entrance();
6606
 
6607
  // Check if there's a newer version for download.
6608
- $new_version = $this->_fetch_newer_version( $plugin_id );
6609
 
6610
  $update = null;
6611
  if ( is_object( $new_version ) ) {
@@ -6639,24 +9086,41 @@
6639
  * @author Vova Feldman (@svovaf)
6640
  * @since 1.0.4
6641
  *
6642
- * @uses FS_Api
6643
  *
 
 
 
6644
  */
6645
- private function _sync_addons() {
6646
  $this->_logger->entrance();
6647
 
6648
- $result = $this->get_api_site_or_plugin_scope()->get( '/addons.json?enriched=true', true );
6649
 
6650
- if ( isset( $result->error ) ) {
6651
- return;
 
 
 
 
 
 
 
 
6652
  }
6653
 
 
 
6654
  $addons = array();
6655
- for ( $i = 0, $len = count( $result->plugins ); $i < $len; $i ++ ) {
6656
- $addons[ $i ] = new FS_Plugin( $result->plugins[ $i ] );
 
 
 
 
6657
  }
6658
 
6659
- $this->_store_addons( $addons, true );
6660
  }
6661
 
6662
  /**
@@ -6839,13 +9303,17 @@
6839
  * @author Vova Feldman (@svovaf)
6840
  * @since 1.1.2
6841
  *
 
 
6842
  * @return string
6843
  */
6844
- private function get_activation_url() {
6845
- return $this->apply_filters( 'connect_url', $this->_get_admin_page_url() );
6846
  }
6847
 
6848
  /**
 
 
6849
  * @author Vova Feldman (@svovaf)
6850
  * @since 1.1.3
6851
  *
@@ -7027,7 +9495,14 @@
7027
  #region Actions that might be called from external links (e.g. email)
7028
 
7029
  case 'cancel_trial':
7030
- $this->_cancel_trial();
 
 
 
 
 
 
 
7031
 
7032
  return;
7033
 
@@ -7094,7 +9569,7 @@
7094
 
7095
  fs_enqueue_local_style( 'fs_account', '/admin/account.css' );
7096
 
7097
- if ( $this->_has_addons() ) {
7098
  wp_enqueue_script( 'plugin-install' );
7099
  add_thickbox();
7100
 
@@ -7107,6 +9582,19 @@
7107
  add_filter( 'admin_body_class', 'fs_addons_body_class' );
7108
  }
7109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7110
  $this->_handle_account_edits();
7111
 
7112
  $this->do_action( 'account_page_load_before_departure' );
@@ -7122,7 +9610,11 @@
7122
  $this->_logger->entrance();
7123
 
7124
  $vars = array( 'slug' => $this->_slug );
7125
- fs_require_once_template( 'account.php', $vars );
 
 
 
 
7126
  }
7127
 
7128
  /**
@@ -7461,18 +9953,6 @@
7461
  private $_action_links_hooked = false;
7462
  private $_action_links = array();
7463
 
7464
- /**
7465
- * @author Vova Feldman (@svovaf)
7466
- * @since 1.0.0
7467
- *
7468
- * @return bool
7469
- */
7470
- private function is_plugin_action_links_hooked() {
7471
- $this->_logger->entrance( json_encode( $this->_action_links_hooked ) );
7472
-
7473
- return $this->_action_links_hooked;
7474
- }
7475
-
7476
  /**
7477
  * Hook to plugin action links filter.
7478
  *
@@ -7543,17 +10023,17 @@
7543
  __fs( 'upgrade', $this->_slug ),
7544
  $this->get_upgrade_url(),
7545
  false,
7546
- 20,
7547
  'upgrade'
7548
  );
7549
  }
7550
 
7551
- if ( $this->_has_addons() ) {
7552
  $this->add_plugin_action_link(
7553
  __fs( 'add-ons', $this->_slug ),
7554
  $this->_get_admin_page_url( 'addons' ),
7555
  false,
7556
- WP_FS__DEFAULT_PRIORITY,
7557
  'addons'
7558
  );
7559
  }
@@ -7561,12 +10041,41 @@
7561
  }
7562
 
7563
  /**
7564
- * Forward page to activation page.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7565
  *
7566
  * @author Vova Feldman (@svovaf)
7567
- * @since 1.0.3
 
 
7568
  */
7569
- function _redirect_on_activation_hook() {
7570
  $url = false;
7571
  $plugin_fs = false;
7572
 
@@ -7594,6 +10103,18 @@
7594
  }
7595
  }
7596
 
 
 
 
 
 
 
 
 
 
 
 
 
7597
  if ( is_string( $url ) ) {
7598
  fs_redirect( $url );
7599
  exit();
@@ -7614,27 +10135,48 @@
7614
  function _modify_plugin_action_links_hook( $links, $file ) {
7615
  $this->_logger->entrance();
7616
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7617
  ksort( $this->_action_links );
7618
 
7619
  foreach ( $this->_action_links as $new_links ) {
7620
  foreach ( $new_links as $link ) {
7621
- $links[ $link['key'] ] = '<a href="' . $link['href'] . '"' . ( $link['external'] ? ' target="_blank"' : '' ) . '>' . $link['label'] . '</a>';
7622
  }
7623
  }
7624
 
7625
- /*
7626
- * This HTML element is used to identify the correct plugin when attaching an event to its Deactivate link.
7627
- *
7628
- * If user is paying or in trial and have the free version installed,
7629
- * assume that the deactivation is for the upgrade process, so this is not needed.
7630
- */
7631
- if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
7632
- if ( isset( $links['deactivate'] ) ) {
7633
- $links['deactivate'] .= '<i class="fs-slug" data-slug="' . $this->_slug . '"></i>';
7634
  }
 
 
 
7635
  }
7636
 
7637
- return $links;
7638
  }
7639
 
7640
  /**
@@ -7666,6 +10208,41 @@
7666
  $this->_admin_notices->add_sticky( $message, $id, $title, $type );
7667
  }
7668
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7669
  /* Plugin Auto-Updates (@since 1.0.4)
7670
  ------------------------------------------------------------------------------------------------------------------*/
7671
  /**
96
  */
97
  private $_enable_anonymous;
98
 
99
+ /**
100
+ * @since 1.1.7.5
101
+ * @var bool Hints the SDK if plugin should run in anonymous mode (only adds feedback form).
102
+ */
103
+ private $_anonymous_mode;
104
+
105
+ /**
106
+ * @since 1.1.9
107
+ * @var bool Hints the SDK if plugin have any free plans.
108
+ */
109
+ private $_is_premium_only;
110
+
111
  /**
112
  * @since 1.0.8
113
  * @var bool Hints the SDK if the plugin has any paid plans.
152
  /**
153
  * @since 1.0.4
154
  *
155
+ * @var FS_Plugin|false
156
  */
157
  private $_parent_plugin = false;
158
  /**
227
  */
228
  private static $_instances = array();
229
 
230
+ // Reason IDs
231
+ const REASON_NO_LONGER_NEEDED = 1;
232
+ const REASON_FOUND_A_BETTER_PLUGIN = 2;
233
+ const REASON_NEEDED_FOR_A_SHORT_PERIOD = 3;
234
+ const REASON_BROKE_MY_SITE = 4;
235
+ const REASON_SUDDENLY_STOPPED_WORKING = 5;
236
+ const REASON_CANT_PAY_ANYMORE = 6;
237
+ const REASON_OTHER = 7;
238
+ const REASON_DIDNT_WORK = 8;
239
+ const REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION = 9;
240
+ const REASON_COULDNT_MAKE_IT_WORK = 10;
241
+ const REASON_GREAT_BUT_NEED_SPECIFIC_FEATURE = 11;
242
+ const REASON_NOT_WORKING = 12;
243
+ const REASON_NOT_WHAT_I_WAS_LOOKING_FOR = 13;
244
+ const REASON_DIDNT_WORK_AS_EXPECTED = 14;
245
+ const REASON_TEMPORARY_DEACTIVATION = 15;
246
 
247
  /* Ctor
248
  ------------------------------------------------------------------------------------------------------------------*/
249
 
250
+ /**
251
+ * Main singleton instance.
252
+ *
253
+ * @author Vova Feldman (@svovaf)
254
+ * @since 1.0.0
255
+ *
256
+ * @param string $slug
257
+ * @param bool $is_init Since 1.2.1 Is initiation sequence.
258
+ */
259
+ private function __construct( $slug, $is_init = false ) {
260
  $this->_slug = $slug;
261
 
262
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
263
 
264
  $this->_storage = FS_Key_Value_Storage::instance( 'plugin_data', $this->_slug );
265
 
266
+ $this->_plugin_main_file_path = $this->_find_caller_plugin_file( $is_init );
267
  $this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
268
  $this->_plugin_basename = plugin_basename( $this->_plugin_main_file_path );
269
  $this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
294
  is_object( $this->_plugin ) ? $this->_plugin->title : ''
295
  );
296
 
297
+ if ( 'true' === fs_request_get( 'fs_clear_api_cache' ) ||
298
+ 'true' === fs_request_is_action( 'restart_freemius' )
299
+ ) {
300
  FS_Api::clear_cache();
301
  }
302
 
364
  * @param string $sdk_version
365
  */
366
  function _data_migration( $sdk_prev_version, $sdk_version ) {
367
+ /**
368
+ * @since 1.1.7.3 Fixed unwanted connectivity test cleanup.
369
+ */
370
+ if ( empty( $sdk_prev_version ) ) {
371
+ return;
372
+ }
373
+
374
  if ( version_compare( $sdk_prev_version, '1.1.5', '<' ) &&
375
  version_compare( $sdk_version, '1.1.5', '>=' )
376
  ) {
394
  }
395
  }
396
 
397
+ /**
398
+ * This action is connected to the 'plugins_loaded' hook and helps to determine
399
+ * if this is a new plugin installation or a plugin update.
400
+ *
401
+ * There are 3 different use-cases:
402
+ * 1) New plugin installation right with Freemius:
403
+ * 1.1 _activate_plugin_event_hook() will be executed first
404
+ * 1.2 Since $this->_storage->is_plugin_new_install is not set,
405
+ * and $this->_storage->plugin_last_version is not set,
406
+ * $this->_storage->is_plugin_new_install will be set to TRUE.
407
+ * 1.3 When _plugins_loaded() will be executed, $this->_storage->is_plugin_new_install will
408
+ * be already set to TRUE.
409
+ *
410
+ * 2) Plugin update, didn't have Freemius before, and now have the SDK:
411
+ * 2.1 _activate_plugin_event_hook() will not be executed, because
412
+ * the activation hook do NOT fires on updates since WP 3.1.
413
+ * 2.2 When _plugins_loaded() will be executed, $this->_storage->is_plugin_new_install will
414
+ * be empty, therefore, it will be set to FALSE.
415
+ *
416
+ * 3) Plugin update, had Freemius in prev version as well:
417
+ * 3.1 _version_updates_handler() will be executed 1st, since FS was installed
418
+ * before, $this->_storage->plugin_last_version will NOT be empty,
419
+ * therefore, $this->_storage->is_plugin_new_install will be set to FALSE.
420
+ * 3.2 When _plugins_loaded() will be executed, $this->_storage->is_plugin_new_install is
421
+ * already set, therefore, it will not be modified.
422
+ *
423
+ * Use-case #3 is backward compatible, #3.1 will be executed since 1.0.9.
424
+ *
425
+ * NOTE:
426
+ * The only fallback of this mechanism is if an admin updates a plugin based on use-case #2,
427
+ * and then, the next immediate PageView is the plugin's main settings page, it will not
428
+ * show the opt-in right away. The reason it will happen is because Freemius execution
429
+ * will be turned off till the plugin is fully loaded at least once
430
+ * (till $this->_storage->was_plugin_loaded is TRUE).
431
+ *
432
+ * @author Vova Feldman (@svovaf)
433
+ * @since 1.1.9
434
+ *
435
+ */
436
+ function _plugins_loaded() {
437
+ // Update flag that plugin was loaded with Freemius at least once.
438
+ $this->_storage->was_plugin_loaded = true;
439
+
440
+ if ( ! isset( $this->_storage->is_plugin_new_install ) ) {
441
+ $this->_storage->is_plugin_new_install = false;
442
+ }
443
+ }
444
+
445
  /**
446
  * @author Vova Feldman (@svovaf)
447
  * @since 1.0.9
454
  '_activate_plugin_event_hook'
455
  ) );
456
 
457
+ /**
458
+ * Part of the mechanism to identify new plugin install vs. plugin update.
459
+ *
460
+ * @author Vova Feldman (@svovaf)
461
+ * @since 1.1.9
462
+ */
463
+ if ( empty( $this->_storage->was_plugin_loaded ) ) {
464
+ if ( $this->is_activation_mode( false ) ) {
465
+ add_action( 'plugins_loaded', array( &$this, '_plugins_loaded' ) );
466
+ } else {
467
+ // If was activated before, then it was already loaded before.
468
+ $this->_plugins_loaded();
469
+ }
470
+ }
471
 
472
  if ( ! $this->is_ajax() ) {
473
  if ( ! $this->is_addon() ) {
486
  $this->add_action( 'sdk_version_update', array( &$this, '_data_migration' ), WP_FS__DEFAULT_PRIORITY, 2 );
487
  }
488
 
489
+ /**
490
+ * Keeping the uninstall hook registered for free or premium plugin version may result to a fatal error that
491
+ * could happen when a user tries to uninstall either version while one of them is still active. Uninstalling a
492
+ * plugin will trigger inclusion of the free or premium version and if one of them is active during the
493
+ * uninstallation, a fatal error may occur in case the plugin's class or functions are already defined.
494
+ *
495
+ * @author Leo Fajardo (leorw)
496
+ *
497
+ * @since 1.2.0
498
+ */
499
+ private function unregister_uninstall_hook() {
500
+ $uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
501
+ unset( $uninstallable_plugins[ $this->_free_plugin_basename ] );
502
+ unset( $uninstallable_plugins[ $this->premium_plugin_basename() ] );
503
+
504
+ update_option( 'uninstall_plugins', $uninstallable_plugins );
505
+ }
506
+
507
+ /**
508
+ * @since 1.2.0 Invalidate module's main file cache, otherwise, FS_Plugin_Updater will not fetch updates.
509
+ */
510
+ private function clear_module_main_file_cache() {
511
+ if ( ! isset( $this->_storage->plugin_main_file ) ||
512
+ empty( $this->_storage->plugin_main_file->path )
513
+ ) {
514
+ return;
515
+ }
516
+
517
+ // Store cached path (2nd layer cache).
518
+ $this->_storage->plugin_main_file->prev_path = $this->_storage->plugin_main_file->path;
519
+
520
+ // Clear cached path.
521
+ unset( $this->_storage->plugin_main_file->path );
522
+ }
523
+
524
  /**
525
  * @author Vova Feldman (@svovaf)
526
  * @since 1.0.9
528
  private function _register_account_hooks() {
529
  if ( is_admin() ) {
530
  if ( ! $this->is_ajax() ) {
531
+ if ( $this->apply_filters( 'show_trial', true ) && $this->has_trial_plan() ) {
532
  $last_time_trial_promotion_shown = $this->_storage->get( 'trial_promotion_shown', false );
533
  if ( ! $this->_site->is_trial_utilized() &&
534
  (
545
  // If user is paying or in trial and have the free version installed,
546
  // assume that the deactivation is for the upgrade process.
547
  if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
548
+ $this->add_ajax_action(
549
+ 'submit_uninstall_reason',
550
+ array( &$this, '_submit_uninstall_reason_action' )
551
+ );
552
 
553
  global $pagenow;
554
  if ( 'plugins.php' === $pagenow ) {
555
  add_action( 'admin_footer', array( &$this, '_add_deactivation_feedback_dialog_box' ) );
556
  }
557
  }
558
+
559
+ if ( ! $this->is_addon() ) {
560
+ if ( $this->is_registered() ) {
561
+ $this->add_filter( 'after_code_type_change', array( &$this, '_after_code_type_change' ) );
562
+ }
563
+ }
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Leverage backtrace to find caller plugin file path.
569
+ *
570
+ * @author Vova Feldman (@svovaf)
571
+ * @since 1.0.6
572
+ *
573
+ * @param bool $is_init Is initiation sequence.
574
+ *
575
+ * @return string
576
+ *
577
+ * @uses fs_find_caller_plugin_file
578
+ */
579
+ private function _find_caller_plugin_file( $is_init = false ) {
580
+ // Try to load the cached value of the file path.
581
+ if ( isset( $this->_storage->plugin_main_file ) ) {
582
+ if ( file_exists( $this->_storage->plugin_main_file->path ) ) {
583
+ return $this->_storage->plugin_main_file->path;
584
+ }
585
+ }
586
+
587
+ /**
588
+ * @since 1.2.1
589
+ *
590
+ * `clear_module_main_file_cache()` is clearing the plugin's cached path on
591
+ * deactivation. Therefore, if any plugin/theme was initiating `Freemius`
592
+ * with that plugin's slug, it was overriding the empty plugin path with a wrong path.
593
+ *
594
+ * So, we've added a special mechanism with a 2nd layer of cache that uses `prev_path`
595
+ * when the class instantiator isn't the module.
596
+ */
597
+ if ( ! $is_init ) {
598
+ // Fetch prev path cache.
599
+ if ( isset( $this->_storage->plugin_main_file ) &&
600
+ isset( $this->_storage->plugin_main_file->prev_path )
601
+ ) {
602
+ if ( file_exists( $this->_storage->plugin_main_file->prev_path ) ) {
603
+ return $this->_storage->plugin_main_file->prev_path;
604
+ }
605
+ }
606
+
607
+ wp_die(
608
+ __fs( 'failed-finding-main-path', $this->_slug ),
609
+ __fs( 'error' ),
610
+ array( 'back_link' => true )
611
+ );
612
  }
613
+
614
+ /**
615
+ * @since 1.2.1
616
+ *
617
+ * Only the original instantiator that calls dynamic_init can modify the module's path.
618
+ */
619
+ // Find caller module.
620
+ $plugin_file = fs_find_caller_plugin_file();
621
+
622
+ $this->_storage->plugin_main_file = (object) array(
623
+ 'path' => fs_normalize_path( $plugin_file ),
624
+ );
625
+
626
+ return $plugin_file;
627
  }
628
 
629
+
630
+ #region Deactivation Feedback Form ------------------------------------------------------------------
631
+
632
  /**
633
  * Displays a confirmation and feedback dialog box when the user clicks on the "Deactivate" link on the plugins
634
  * page.
638
  * @since 1.1.2
639
  */
640
  function _add_deactivation_feedback_dialog_box() {
 
 
641
  /* Check the type of user:
642
  * 1. Long-term (long-term)
643
  * 2. Non-registered and non-anonymous short-term (non-registered-and-non-anonymous-short-term).
681
  /**
682
  * @todo Deactivation form core functions should be loaded only once! Otherwise, when there are multiple Freemius powered plugins the same code is loaded multiple times. The only thing that should be loaded differently is the various deactivation reasons object based on the state of the plugin.
683
  */
684
+ fs_require_template( 'forms/deactivation/form.php', $vars );
685
  }
686
 
687
  /**
693
  * @return array The uninstall reasons for the specified user type.
694
  */
695
  function _get_uninstall_reasons( $user_type = 'long-term' ) {
696
+ $internal_message_template_var = array(
697
+ 'slug' => $this->_slug
698
+ );
699
+
700
+ if ( $this->is_registered() && false !== $this->get_plan() && $this->get_plan()->has_technical_support() ) {
701
+ $contact_support_template = fs_get_template( 'forms/deactivation/contact.php', $internal_message_template_var );
702
+ } else {
703
+ $contact_support_template = '';
704
+ }
705
+
706
  $reason_found_better_plugin = array(
707
+ 'id' => self::REASON_FOUND_A_BETTER_PLUGIN,
708
  'text' => __fs( 'reason-found-a-better-plugin', $this->_slug ),
709
  'input_type' => 'textfield',
710
  'input_placeholder' => __fs( 'placeholder-plugin-name', $this->_slug )
711
  );
712
 
713
+ $reason_temporary_deactivation = array(
714
+ 'id' => self::REASON_TEMPORARY_DEACTIVATION,
715
+ 'text' => __fs( 'reason-temporary-deactivation', $this->_slug ),
716
+ 'input_type' => '',
717
+ 'input_placeholder' => ''
718
+ );
719
+
720
  $reason_other = array(
721
+ 'id' => self::REASON_OTHER,
722
  'text' => __fs( 'reason-other', $this->_slug ),
723
  'input_type' => 'textfield',
724
  'input_placeholder' => ''
726
 
727
  $long_term_user_reasons = array(
728
  array(
729
+ 'id' => self::REASON_NO_LONGER_NEEDED,
730
  'text' => __fs( 'reason-no-longer-needed', $this->_slug ),
731
  'input_type' => '',
732
  'input_placeholder' => ''
733
  ),
734
  $reason_found_better_plugin,
735
  array(
736
+ 'id' => self::REASON_NEEDED_FOR_A_SHORT_PERIOD,
737
  'text' => __fs( 'reason-needed-for-a-short-period', $this->_slug ),
738
  'input_type' => '',
739
  'input_placeholder' => ''
740
  ),
741
  array(
742
+ 'id' => self::REASON_BROKE_MY_SITE,
743
  'text' => __fs( 'reason-broke-my-site', $this->_slug ),
744
  'input_type' => '',
745
+ 'input_placeholder' => '',
746
+ 'internal_message' => $contact_support_template
747
  ),
748
  array(
749
+ 'id' => self::REASON_SUDDENLY_STOPPED_WORKING,
750
  'text' => __fs( 'reason-suddenly-stopped-working', $this->_slug ),
751
  'input_type' => '',
752
+ 'input_placeholder' => '',
753
+ 'internal_message' => $contact_support_template
754
  )
755
  );
756
 
757
  if ( $this->is_paying() ) {
758
  $long_term_user_reasons[] = array(
759
+ 'id' => self::REASON_CANT_PAY_ANYMORE,
760
  'text' => __fs( 'reason-cant-pay-anymore', $this->_slug ),
761
  'input_type' => 'textfield',
762
  'input_placeholder' => __fs( 'placeholder-comfortable-price', $this->_slug )
763
  );
764
  }
765
 
766
+ $reason_dont_share_info = array(
767
+ 'id' => self::REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION,
768
+ 'text' => __fs( 'reason-dont-like-to-share-my-information', $this->_slug ),
769
+ 'input_type' => '',
770
+ 'input_placeholder' => ''
771
+ );
772
+
773
+ /**
774
+ * If the current user has selected the "don't share data" reason in the deactivation feedback modal, inform the
775
+ * user by showing additional message that he doesn't have to share data and can just choose to skip the opt-in
776
+ * (the Skip button is included in the message to show). This message will only be shown if anonymous mode is
777
+ * enabled and the user's account is currently not in pending activation state (similar to the way the Skip
778
+ * button in the opt-in form is shown/hidden).
779
+ */
780
+ if ( $this->is_enable_anonymous() && ! $this->is_pending_activation() ) {
781
+ $reason_dont_share_info['internal_message'] = fs_get_template( 'forms/deactivation/retry-skip.php', $internal_message_template_var );
782
+ }
783
 
784
  $uninstall_reasons = array(
785
  'long-term' => $long_term_user_reasons,
786
  'non-registered-and-non-anonymous-short-term' => array(
787
  array(
788
+ 'id' => self::REASON_DIDNT_WORK,
789
  'text' => __fs( 'reason-didnt-work', $this->_slug ),
790
  'input_type' => '',
791
  'input_placeholder' => ''
792
  ),
793
+ $reason_dont_share_info,
794
+ $reason_found_better_plugin
 
 
 
 
 
 
795
  ),
796
  'short-term' => array(
797
  array(
798
+ 'id' => self::REASON_COULDNT_MAKE_IT_WORK,
799
  'text' => __fs( 'reason-couldnt-make-it-work', $this->_slug ),
800
  'input_type' => '',
801
+ 'input_placeholder' => '',
802
+ 'internal_message' => $contact_support_template
803
  ),
804
  $reason_found_better_plugin,
805
  array(
806
+ 'id' => self::REASON_GREAT_BUT_NEED_SPECIFIC_FEATURE,
807
  'text' => __fs( 'reason-great-but-need-specific-feature', $this->_slug ),
808
  'input_type' => 'textarea',
809
  'input_placeholder' => __fs( 'placeholder-feature', $this->_slug )
810
  ),
811
  array(
812
+ 'id' => self::REASON_NOT_WORKING,
813
  'text' => __fs( 'reason-not-working', $this->_slug ),
814
  'input_type' => 'textarea',
815
  'input_placeholder' => __fs( 'placeholder-share-what-didnt-work', $this->_slug )
816
  ),
817
  array(
818
+ 'id' => self::REASON_NOT_WHAT_I_WAS_LOOKING_FOR,
819
  'text' => __fs( 'reason-not-what-i-was-looking-for', $this->_slug ),
820
  'input_type' => 'textarea',
821
  'input_placeholder' => __fs( 'placeholder-what-youve-been-looking-for', $this->_slug )
822
  ),
823
  array(
824
+ 'id' => self::REASON_DIDNT_WORK_AS_EXPECTED,
825
  'text' => __fs( 'reason-didnt-work-as-expected', $this->_slug ),
826
  'input_type' => 'textarea',
827
  'input_placeholder' => __fs( 'placeholder-what-did-you-expect', $this->_slug )
828
+ )
 
829
  )
830
  );
831
 
832
+ // Randomize the reasons for the current user type.
833
+ shuffle( $uninstall_reasons[ $user_type ] );
834
+
835
+ // Keep the following reasons as the last items in the list.
836
+ $uninstall_reasons[ $user_type ][] = $reason_temporary_deactivation;
837
+ $uninstall_reasons[ $user_type ][] = $reason_other;
838
+
839
  $uninstall_reasons = $this->apply_filters( 'uninstall_reasons', $uninstall_reasons );
840
 
841
  return $uninstall_reasons[ $user_type ];
848
  * @since 1.1.2
849
  */
850
  function _submit_uninstall_reason_action() {
851
+ $reason_id = fs_request_get( 'reason_id' );
852
+
853
+ // Check if the given reason ID is an unsigned integer.
854
+ if ( ! ctype_digit( $reason_id ) ) {
855
  exit;
856
  }
857
 
858
+ $reason_info = trim( fs_request_get( 'reason_info', '' ) );
859
+ if ( ! empty( $reason_info ) ) {
860
+ $reason_info = substr( $reason_info, 0, 128 );
861
+ }
862
 
863
  $reason = (object) array(
864
+ 'id' => $reason_id,
865
+ 'info' => $reason_info,
866
+ 'is_anonymous' => fs_request_get_bool( 'is_anonymous' )
867
  );
868
 
869
  $this->_storage->store( 'uninstall_reason', $reason );
873
  exit;
874
  }
875
 
876
+ #endregion Deactivation Feedback Form ------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
877
 
878
  #region Instance ------------------------------------------------------------------
879
 
883
  * @author Vova Feldman (@svovaf)
884
  * @since 1.0.0
885
  *
886
+ * @param string $slug
887
+ * @param bool $is_init Is initiation sequence.
888
  *
889
  * @return Freemius
890
  */
891
+ static function instance( $slug, $is_init = false ) {
892
  $slug = strtolower( $slug );
893
 
894
  if ( ! isset( self::$_instances[ $slug ] ) ) {
896
  self::_load_required_static();
897
  }
898
 
899
+ self::$_instances[ $slug ] = new Freemius( $slug, $is_init );
900
  }
901
 
902
  return self::$_instances[ $slug ];
1010
  * @author Vova Feldman (@svovaf)
1011
  * @since 1.0.7
1012
  *
1013
+ * @param bool $and_on
1014
+ *
1015
  * @return bool
1016
  */
1017
+ function is_activation_mode( $and_on = true ) {
1018
  return (
1019
+ ( $this->is_on() || ! $and_on ) &&
1020
  ! $this->is_registered() &&
1021
+ ( ! $this->is_enable_anonymous() ||
1022
  ( ! $this->is_anonymous() && ! $this->is_pending_activation() ) )
1023
  );
1024
  }
1025
 
1026
+ /**
1027
+ * Get collection of all active plugins.
1028
+ *
1029
+ * @author Vova Feldman (@svovaf)
1030
+ * @since 1.0.9
1031
+ *
1032
+ * @return array[string]array
1033
+ */
1034
+ private static function get_active_plugins() {
1035
+ self::require_plugin_essentials();
1036
+
1037
+ $active_plugin = array();
1038
+ $all_plugins = get_plugins();
1039
+ $active_plugins_basenames = get_option( 'active_plugins' );
1040
+
1041
+ foreach ( $active_plugins_basenames as $plugin_basename ) {
1042
+ $active_plugin[ $plugin_basename ] = $all_plugins[ $plugin_basename ];
1043
+ }
1044
+
1045
+ return $active_plugin;
1046
+ }
1047
+
1048
+ /**
1049
+ * Get collection of all plugins.
1050
+ *
1051
+ * @author Vova Feldman (@svovaf)
1052
+ * @since 1.1.8
1053
+ *
1054
+ * @return array Key is the plugin file path and the value is an array of the plugin data.
1055
+ */
1056
+ private static function get_all_plugins() {
1057
+ self::require_plugin_essentials();
1058
+
1059
+ $all_plugins = get_plugins();
1060
+ $active_plugins_basenames = get_option( 'active_plugins' );
1061
+
1062
+ foreach ( $all_plugins as $basename => &$data ) {
1063
+ // By default set to inactive (next foreach update the active plugins).
1064
+ $data['is_active'] = false;
1065
+ // Enrich with plugin slug.
1066
+ $data['slug'] = self::get_plugin_slug( $basename );
1067
+ }
1068
+
1069
+ // Flag active plugins.
1070
+ foreach ( $active_plugins_basenames as $basename ) {
1071
+ if ( isset( $all_plugins[ $basename ] ) ) {
1072
+ $all_plugins[ $basename ]['is_active'] = true;
1073
+ }
1074
+ }
1075
+
1076
+ return $all_plugins;
1077
+ }
1078
+
1079
+
1080
+ /**
1081
+ * Cached result of get_site_transient( 'update_plugins' )
1082
+ *
1083
+ * @author Vova Feldman (@svovaf)
1084
+ * @since 1.1.8
1085
+ *
1086
+ * @var object
1087
+ */
1088
+ private static $_plugins_info;
1089
+
1090
+ /**
1091
+ * Helper function to get specified plugin's slug.
1092
+ *
1093
+ * @author Vova Feldman (@svovaf)
1094
+ * @since 1.1.8
1095
+ *
1096
+ * @param $basename
1097
+ *
1098
+ * @return string
1099
+ */
1100
+ private static function get_plugin_slug( $basename ) {
1101
+ if ( ! isset( self::$_plugins_info ) ) {
1102
+ self::$_plugins_info = get_site_transient( 'update_plugins' );
1103
+ }
1104
+
1105
+ $slug = '';
1106
+
1107
+ if ( is_object( self::$_plugins_info ) ) {
1108
+ if ( isset( self::$_plugins_info->no_update ) &&
1109
+ isset( self::$_plugins_info->no_update[ $basename ] ) &&
1110
+ ! empty( self::$_plugins_info->no_update[ $basename ]->slug )
1111
+ ) {
1112
+ $slug = self::$_plugins_info->no_update[ $basename ]->slug;
1113
+ } else if ( isset( self::$_plugins_info->response ) &&
1114
+ isset( self::$_plugins_info->response[ $basename ] ) &&
1115
+ ! empty( self::$_plugins_info->response[ $basename ]->slug )
1116
+ ) {
1117
+ $slug = self::$_plugins_info->response[ $basename ]->slug;
1118
+ }
1119
+ }
1120
+
1121
+ if ( empty( $slug ) ) {
1122
+ // Try to find slug from FS data.
1123
+ $slug = self::find_slug_by_basename( $basename );
1124
+ }
1125
+
1126
+ if ( empty( $slug ) ) {
1127
+ // Fallback to plugin's folder name.
1128
+ $slug = dirname( $basename );
1129
+ }
1130
+
1131
+ return $slug;
1132
+ }
1133
+
1134
  private static $_statics_loaded = false;
1135
 
1136
  /**
1157
 
1158
  add_action( 'admin_menu', array( 'Freemius', 'add_debug_page' ) );
1159
 
1160
+ add_action( "wp_ajax_fs_toggle_debug_mode", array( 'Freemius', '_toggle_debug_mode' ) );
1161
+
1162
+ add_action( 'plugins_loaded', array( 'Freemius', '_load_textdomain' ), 1 );
1163
+
1164
  self::$_statics_loaded = true;
1165
  }
1166
 
1167
+ /**
1168
+ * Load framework's text domain.
1169
+ *
1170
+ * @author Vova Feldman (@svovaf)
1171
+ * @since 1.2.1
1172
+ */
1173
+ static function _load_textdomain() {
1174
+ if ( ! is_admin() ) {
1175
+ return;
1176
+ }
1177
+
1178
+ global $fs_active_plugins;
1179
+
1180
+ load_plugin_textdomain(
1181
+ 'freemius',
1182
+ false,
1183
+ $fs_active_plugins->newest->sdk_path . '/languages/'
1184
+ );
1185
+
1186
+ // @todo Load for themes.
1187
+ }
1188
+
1189
  #region Debugging ------------------------------------------------------------------
1190
 
1191
  /**
1203
 
1204
  if ( WP_FS__DEV_MODE ) {
1205
  // Add top-level debug menu item.
1206
+ $hook = add_menu_page(
1207
  $title,
1208
  $title,
1209
  'manage_options',
1225
  add_action( "load-$hook", array( 'Freemius', '_debug_page_actions' ) );
1226
  }
1227
 
1228
+ /**
1229
+ * @author Vova Feldman (@svovaf)
1230
+ * @since 1.1.7.3
1231
+ */
1232
+ static function _toggle_debug_mode() {
1233
+ if ( in_array( $_POST['is_on'], array( 0, 1 ) ) ) {
1234
+ update_option( 'fs_debug_mode', $_POST['is_on'] );
1235
+ }
1236
+
1237
+ exit;
1238
+ }
1239
+
1240
  /**
1241
  * @author Vova Feldman (@svovaf)
1242
  * @since 1.0.8
1244
  static function _debug_page_actions() {
1245
  self::_clean_admin_content_section();
1246
 
1247
+ if ( fs_request_is_action( 'restart_freemius' ) ) {
1248
+ check_admin_referer( 'restart_freemius' );
1249
 
1250
  self::$_accounts->clear( true );
1251
 
1252
+
1253
  return;
1254
  }
1255
  }
1265
  $users = self::get_all_users();
1266
  $addons = self::get_all_addons();
1267
  $account_addons = self::get_all_account_addons();
1268
+ $licenses = self::get_all_licenses();
1269
 
1270
  // $plans = self::get_all_plans();
1271
  // $licenses = self::get_all_licenses();
1275
  'users' => $users,
1276
  'addons' => $addons,
1277
  'account_addons' => $account_addons,
1278
+ 'licenses' => $licenses,
1279
  );
1280
+
1281
+ fs_enqueue_local_style( 'fs_account', '/admin/debug.css' );
1282
  fs_require_once_template( 'debug.php', $vars );
1283
  }
1284
 
1314
  return false;
1315
  }
1316
 
1317
+ /**
1318
+ * @author Vova Feldman (@svovaf)
1319
+ * @since 1.1.7.3
1320
+ *
1321
+ * @param bool $flush_if_no_connectivity
1322
+ *
1323
+ * @return bool
1324
+ */
1325
+ private function should_run_connectivity_test( $flush_if_no_connectivity = false ) {
1326
+ if ( ! isset( $this->_storage->connectivity_test ) ) {
1327
+ // Connectivity test was never executed, or cache was cleared.
1328
+ return true;
1329
+ }
1330
+
1331
+ if ( WP_FS__PING_API_ON_IP_OR_HOST_CHANGES ) {
1332
+ if ( WP_FS__IS_HTTP_REQUEST ) {
1333
+ if ( $_SERVER['HTTP_HOST'] != $this->_storage->connectivity_test['host'] ) {
1334
+ // Domain changed.
1335
+ return true;
1336
+ }
1337
+
1338
+ if ( WP_FS__REMOTE_ADDR != $this->_storage->connectivity_test['server_ip'] ) {
1339
+ // Server IP changed.
1340
+ return true;
1341
+ }
1342
+ }
1343
+ }
1344
+
1345
+ if ( $this->_storage->connectivity_test['is_connected'] &&
1346
+ $this->_storage->connectivity_test['is_active']
1347
+ ) {
1348
+ // API connected and Freemius is active - no need to run connectivity check.
1349
+ return false;
1350
+ }
1351
+
1352
+ if ( $flush_if_no_connectivity ) {
1353
+ /**
1354
+ * If explicitly asked to flush when no connectivity - do it only
1355
+ * if at least 10 sec passed from the last API connectivity test.
1356
+ */
1357
+ return ( isset( $this->_storage->connectivity_test['timestamp'] ) &&
1358
+ ( WP_FS__SCRIPT_START_TIME - $this->_storage->connectivity_test['timestamp'] ) > 10 );
1359
+ }
1360
+
1361
+ /**
1362
+ * @since 1.1.7 Don't check for connectivity on plugin downgrade.
1363
+ */
1364
+ $version = $this->get_plugin_version();
1365
+ if ( version_compare( $version, $this->_storage->connectivity_test['version'], '>' ) ) {
1366
+ // If it's a plugin version upgrade and Freemius is off or no connectivity, run connectivity test.
1367
+ return true;
1368
+ }
1369
+
1370
+ return false;
1371
+ }
1372
+
1373
+ /**
1374
+ * @author Vova Feldman (@svovaf)
1375
+ * @since 1.1.7.4
1376
+ *
1377
+ * @return object|false
1378
+ */
1379
+ private function ping() {
1380
+ if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY ) {
1381
+ return false;
1382
+ }
1383
+
1384
+ $version = $this->get_plugin_version();
1385
+
1386
+ $is_update = $this->apply_filters( 'is_plugin_update', $this->is_plugin_update() );
1387
+
1388
+ return $this->get_api_plugin_scope()->ping(
1389
+ $this->get_anonymous_id(),
1390
+ array(
1391
+ 'is_update' => json_encode( $is_update ),
1392
+ 'version' => $version,
1393
+ 'sdk' => $this->version,
1394
+ 'is_admin' => json_encode( is_admin() ),
1395
+ 'is_ajax' => json_encode( $this->is_ajax() ),
1396
+ 'is_cron' => json_encode( $this->is_cron() ),
1397
+ 'is_http' => json_encode( WP_FS__IS_HTTP_REQUEST ),
1398
+ )
1399
+ );
1400
+ }
1401
+
1402
  /**
1403
  * Check if there's any connectivity issue to Freemius API.
1404
  *
1405
  * @author Vova Feldman (@svovaf)
1406
  * @since 1.0.9
1407
  *
1408
+ * @param bool $flush_if_no_connectivity
1409
  *
1410
  * @return bool
1411
  */
1412
+ function has_api_connectivity( $flush_if_no_connectivity = false ) {
1413
+ $this->_logger->entrance();
1414
+
1415
+ if ( isset( $this->_has_api_connection ) && ( $this->_has_api_connection || ! $flush_if_no_connectivity ) ) {
1416
  return $this->_has_api_connection;
1417
  }
1418
 
 
 
1419
  if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY &&
1420
  isset( $this->_storage->connectivity_test ) &&
1421
  true === $this->_storage->connectivity_test['is_connected']
1423
  unset( $this->_storage->connectivity_test );
1424
  }
1425
 
1426
+ if ( ! $this->should_run_connectivity_test( $flush_if_no_connectivity ) ) {
1427
+ $this->_has_api_connection = $this->_storage->connectivity_test['is_connected'];
1428
+ /**
1429
+ * @since 1.1.6 During dev mode, if there's connectivity - turn Freemius on regardless the configuration.
1430
+ */
1431
+ $this->_is_on = $this->_storage->connectivity_test['is_active'] ||
1432
+ ( WP_FS__DEV_MODE && $this->_has_api_connection && ! WP_FS__SIMULATE_FREEMIUS_OFF );
 
 
 
 
 
1433
 
1434
+ return $this->_has_api_connection;
 
 
1435
  }
1436
 
1437
+ $pong = $this->ping();
1438
+ $is_connected = $this->get_api_plugin_scope()->is_valid_ping( $pong );
1439
 
1440
+ if ( ! $is_connected ) {
1441
+ // API failure.
1442
+ $this->_add_connectivity_issue_message( $pong );
 
 
1443
  }
1444
 
1445
+ $this->store_connectivity_info( $pong, $is_connected );
 
 
1446
 
1447
+ return $this->_has_api_connection;
1448
+ }
1449
+
1450
+ /**
1451
+ * @author Vova Feldman (@svovaf)
1452
+ * @since 1.1.7.4
1453
+ *
1454
+ * @param object $pong
1455
+ * @param bool $is_connected
1456
+ */
1457
+ private function store_connectivity_info( $pong, $is_connected ) {
1458
+ $this->_logger->entrance();
1459
+
1460
+ $version = $this->get_plugin_version();
1461
+
1462
+ if ( ! $is_connected || WP_FS__SIMULATE_FREEMIUS_OFF ) {
1463
+ $is_active = false;
1464
+ } else {
1465
+ $is_active = ( isset( $pong->is_active ) && true == $pong->is_active );
1466
  }
1467
 
1468
+ $is_active = $this->apply_filters(
1469
+ 'is_on',
1470
+ $is_active,
1471
+ $this->is_plugin_update(),
1472
+ $version
1473
+ );
1474
 
1475
  $this->_storage->connectivity_test = array(
1476
  'is_connected' => $is_connected,
1483
  );
1484
 
1485
  $this->_has_api_connection = $is_connected;
1486
+ $this->_is_on = $is_active || ( WP_FS__DEV_MODE && $is_connected && ! WP_FS__SIMULATE_FREEMIUS_OFF );
1487
+ }
1488
 
1489
+ /**
1490
+ * Force turning Freemius on.
1491
+ *
1492
+ * @author Vova Feldman (@svovaf)
1493
+ * @since 1.1.8.1
1494
+ *
1495
+ * @return bool TRUE if successfully turned on.
1496
+ */
1497
+ private function turn_on() {
1498
+ $this->_logger->entrance();
1499
+
1500
+ if ( $this->is_on() || ! isset( $this->_storage->connectivity_test['is_active'] ) ) {
1501
+ return false;
1502
+ }
1503
+
1504
+ $updated_connectivity = $this->_storage->connectivity_test;
1505
+ $updated_connectivity['is_active'] = true;
1506
+ $updated_connectivity['timestamp'] = WP_FS__SCRIPT_START_TIME;
1507
+ $this->_storage->connectivity_test = $updated_connectivity;
1508
+
1509
+ $this->_is_on = true;
1510
+
1511
+ return true;
1512
  }
1513
 
1514
  /**
1520
  * @return string
1521
  */
1522
  function get_anonymous_id() {
1523
+ $unique_id = self::$_accounts->get_option( 'unique_id' );
1524
+
1525
+ if ( empty( $unique_id ) || ! is_string( $unique_id ) ) {
1526
  $key = get_site_url();
1527
 
1528
  // If localhost, assign microtime instead of domain.
1529
+ if ( WP_FS__IS_LOCALHOST ||
1530
+ false !== strpos( $key, 'localhost' ) ||
1531
+ false === strpos( $key, '.' )
1532
+ ) {
1533
  $key = microtime();
1534
  }
1535
 
1536
+ $unique_id = md5( $key );
1537
+
1538
+ self::$_accounts->set_option( 'unique_id', $unique_id, true );
1539
  }
1540
 
1541
+ $this->_logger->departure( $unique_id );
1542
+
1543
+ return $unique_id;
1544
+ }
1545
+
1546
+ /**
1547
+ * @author Vova Feldman (@svovaf)
1548
+ * @since 1.1.7.4
1549
+ *
1550
+ * @return \WP_User
1551
+ */
1552
+ static function _get_current_wp_user() {
1553
+ self::require_pluggable_essentials();
1554
+
1555
+ return wp_get_current_user();
1556
  }
1557
 
1558
  /**
1562
  * @since 1.0.9
1563
  *
1564
  * @param mixed $api_result
1565
+ * @param bool $is_first_failure
1566
  */
1567
+ function _add_connectivity_issue_message( $api_result, $is_first_failure = true ) {
1568
  if ( $this->_enable_anonymous ) {
1569
  // Don't add message if can run anonymously.
1570
  return;
1574
  require_once( ABSPATH . 'wp-includes/functions.php' );
1575
  }
1576
 
1577
+ $current_user = self::_get_current_wp_user();
 
 
1578
  // $admin_email = get_option( 'admin_email' );
1579
  $admin_email = $current_user->user_email;
1580
 
1581
  $message = false;
1582
  if ( is_object( $api_result ) &&
1583
+ isset( $api_result->error ) &&
1584
+ isset( $api_result->error->code )
1585
  ) {
1586
  switch ( $api_result->error->code ) {
1587
  case 'curl_missing':
1679
  )
1680
  );
1681
  break;
1682
+ // default:
1683
+ // $message = __fs( 'connectivity-test-fails-message', $this->_slug );
1684
+ // break;
1685
  }
1686
  }
1687
 
1688
+ $message_id = 'failed_connect_api';
1689
+ $type = 'error';
1690
+
1691
  if ( false === $message ) {
1692
+ if ( $is_first_failure ) {
1693
+ // First attempt failed.
1694
+ $message = sprintf(
1695
+ __fs( 'x-requires-access-to-api', $this->_slug ) . ' ' .
1696
+ __fs( 'connectivity-test-fails-message', $this->_slug ) . ' ' .
1697
+ __fs( 'connectivity-test-maybe-temporary', $this->_slug ) . '<br><br>' .
1698
+ '%s',
1699
+ '<b>' . $this->get_plugin_name() . '</b>',
1700
  sprintf(
1701
+ '<div id="fs_firewall_issue_options">%s %s</div>',
1702
+ sprintf(
1703
+ '<a class="button button-primary fs-resolve" data-type="retry_ping" href="#">%s</a>',
1704
+ __fs( 'yes-do-your-thing', $this->_slug )
1705
+ ),
1706
+ sprintf(
1707
+ '<a href="%s" class="button">%s</a>',
1708
+ 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 ),
1709
+ __fs( 'no-deactivate', $this->_slug )
1710
  )
1711
+ )
1712
+ );
1713
+
1714
+ $message_id = 'failed_connect_api_first';
1715
+ $type = 'promotion';
1716
+ } else {
1717
+ // Second connectivity attempt failed.
1718
+ $message = sprintf(
1719
+ __fs( 'x-requires-access-to-api', $this->_slug ) . ' ' .
1720
+ __fs( 'connectivity-test-fails-message', $this->_slug ) . ' ' .
1721
+ __fs( 'happy-to-resolve-issue-asap', $this->_slug ) .
1722
+ ' %s',
1723
+ '<b>' . $this->get_plugin_name() . '</b>',
1724
  sprintf(
1725
+ '<ol id="fs_firewall_issue_options"><li>%s</li><li>%s</li><li>%s</li></ol>',
1726
+ sprintf(
1727
+ '<a class="fs-resolve" data-type="general" href="#"><b>%s</b></a>%s',
1728
+ __fs( 'fix-issue-title', $this->_slug ),
1729
+ ' - ' . sprintf(
1730
+ __fs( 'fix-issue-desc', $this->_slug ),
1731
+ '<a href="mailto:' . $admin_email . '">' . $admin_email . '</a>'
1732
+ )
1733
+ ),
1734
+ sprintf(
1735
+ '<a href="%s" target="_blank"><b>%s</b></a>%s',
1736
+ sprintf( 'https://wordpress.org/plugins/%s/download/', $this->_slug ),
1737
+ __fs( 'install-previous-title', $this->_slug ),
1738
+ ' - ' . __fs( 'install-previous-desc', $this->_slug )
1739
+ ),
1740
+ sprintf(
1741
+ '<a href="%s"><b>%s</b></a>%s',
1742
+ 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 ),
1743
+ __fs( 'deactivate-plugin-title', $this->_slug ),
1744
+ ' - ' . __fs( 'deactivate-plugin-desc', $this->_slug )
1745
+ )
1746
  )
1747
+ );
1748
+ }
1749
  }
1750
 
1751
  $this->_admin_notices->add_sticky(
1752
  $message,
1753
+ $message_id,
1754
  __fs( 'oops', $this->_slug ) . '...',
1755
+ $type
1756
  );
1757
  }
1758
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1759
  /**
1760
  * Handle user request to resolve connectivity issue.
1761
  * This method will send an email to Freemius API technical staff for resolution.
1767
  function _email_about_firewall_issue() {
1768
  $this->_admin_notices->remove_sticky( 'failed_connect_api' );
1769
 
1770
+ $pong = $this->ping();
1771
 
1772
+ $is_connected = $this->get_api_plugin_scope()->is_valid_ping( $pong );
1773
+
1774
+ if ( $is_connected ) {
1775
+ $this->store_connectivity_info( $pong, $is_connected );
1776
+
1777
+ echo $this->get_after_plugin_activation_redirect_url();
1778
+ exit;
1779
+ }
1780
 
1781
+ $current_user = self::_get_current_wp_user();
1782
+ $admin_email = $current_user->user_email;
1783
 
1784
  $error_type = fs_request_get( 'error_type', 'general' );
1785
 
1810
  $custom_email_sections['api_error'] = array(
1811
  'title' => 'API Error',
1812
  'rows' => array(
1813
+ 'ping' => array( is_string( $pong ) ? htmlentities( $pong ) : json_encode( $pong ) )
1814
+ )
1815
+ );
1816
+
1817
+ // Add PHP info for deeper investigation.
1818
+ ob_start();
1819
+ phpinfo();
1820
+ $php_info = ob_get_clean();
1821
+ $custom_email_sections['php_info'] = array(
1822
+ 'title' => 'PHP Info',
1823
+ 'rows' => array(
1824
+ 'info' => array( $php_info )
1825
  )
1826
  );
1827
 
1847
  exit;
1848
  }
1849
 
1850
+ /**
1851
+ * Handle connectivity test retry approved by the user.
1852
+ *
1853
+ * @author Vova Feldman (@svovaf)
1854
+ * @since 1.1.7.4
1855
+ */
1856
+ function _retry_connectivity_test() {
1857
+ $this->_admin_notices->remove_sticky( 'failed_connect_api_first' );
1858
+
1859
+ $pong = $this->ping();
1860
+
1861
+ $is_connected = $this->get_api_plugin_scope()->is_valid_ping( $pong );
1862
+
1863
+ if ( $is_connected ) {
1864
+ $this->store_connectivity_info( $pong, $is_connected );
1865
+
1866
+ echo $this->get_after_plugin_activation_redirect_url();
1867
+ } else {
1868
+ // Add connectivity issue message after 2nd failed attempt.
1869
+ $this->_add_connectivity_issue_message( $pong, false );
1870
+
1871
+ echo "1";
1872
+ }
1873
+
1874
+ exit;
1875
+ }
1876
+
1877
  static function _add_firewall_issues_javascript() {
1878
  $params = array();
1879
  fs_require_once_template( 'firewall-issues-js.php', $params );
1956
  * @return array
1957
  */
1958
  private function get_email_sections() {
 
 
1959
  // Retrieve the current user's information so that we can get the user's email, first name, and last name below.
1960
+ $current_user = self::_get_current_wp_user();
1961
 
1962
  // Retrieve the cURL version information so that we can get the version number below.
1963
  $curl_version_information = curl_version();
1964
 
1965
+ $active_plugin = self::get_active_plugins();
1966
 
1967
  // Generate the list of active plugins separated by new line.
1968
  $active_plugin_string = '';
1996
  'site' => array(
1997
  'title' => 'Site',
1998
  'rows' => array(
1999
+ 'unique_id' => array( 'Address', $this->get_anonymous_id() ),
2000
  'address' => array( 'Address', site_url() ),
2001
  'host' => array(
2002
  'HTTP_HOST',
2056
  ) );
2057
  }
2058
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2059
  /**
2060
  * Dynamic initiator, originally created to support initiation
2061
  * with parent_id for add-ons.
2070
  function dynamic_init( array $plugin_info ) {
2071
  $this->_logger->entrance();
2072
 
2073
+ $this->parse_settings( $plugin_info );
 
 
 
 
 
 
 
 
 
 
 
2074
 
2075
+ if ( $this->should_stop_execution() ) {
2076
+ return;
 
 
 
2077
  }
2078
 
2079
+ if ( ! $this->is_registered() ) {
2080
+ if ( $this->is_anonymous() ) {
2081
+ // If user skipped, no need to test connectivity.
2082
+ $this->_has_api_connection = true;
2083
+ $this->_is_on = true;
2084
+ } else {
2085
+ if ( ! $this->has_api_connectivity() ) {
2086
+ if ( $this->_admin_notices->has_sticky( 'failed_connect_api_first' ) ||
2087
+ $this->_admin_notices->has_sticky( 'failed_connect_api' )
2088
+ ) {
2089
+ if ( ! $this->_enable_anonymous ) {
2090
+ // If anonymous mode is disabled, add firewall admin-notice message.
2091
+ add_action( 'admin_footer', array( 'Freemius', '_add_firewall_issues_javascript' ) );
2092
+
2093
+ $this->add_ajax_action( 'resolve_firewall_issues', array(
2094
+ &$this,
2095
+ '_email_about_firewall_issue'
2096
+ ) );
2097
+
2098
+ $this->add_ajax_action( 'retry_connectivity_test', array(
2099
+ &$this,
2100
+ '_retry_connectivity_test'
2101
+ ) );
2102
+ }
2103
+ }
2104
 
2105
+ return;
2106
+ } else {
2107
+ $this->_admin_notices->remove_sticky( array(
2108
+ 'failed_connect_api_first',
2109
+ 'failed_connect_api',
2110
+ ) );
2111
+
2112
+ if ( $this->_anonymous_mode ) {
2113
+ // Simulate anonymous mode.
2114
+ $this->_is_anonymous = true;
2115
+ }
2116
+ }
2117
+ }
2118
 
2119
+ // Check if Freemius is on for the current plugin.
2120
+ // This MUST be executed after all the plugin variables has been loaded.
2121
+ if ( ! $this->is_on() ) {
2122
+ return;
2123
+ }
2124
  }
 
2125
 
2126
+ if ( $this->has_api_connectivity() ) {
2127
+ if ( $this->is_cron() ) {
2128
+ $this->hook_callback_to_sync_cron();
2129
+ } else if ( $this->is_user_in_admin() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2130
  /**
2131
+ * Schedule daily data sync cron if:
2132
+ *
2133
+ * 1. User opted-in (for tracking).
2134
+ * 2. If skipped, but later upgraded (opted-in via upgrade).
2135
  *
2136
  * @author Vova Feldman (@svovaf)
2137
+ * @since 1.1.7.3
2138
  *
 
2139
  */
2140
+ if ( $this->is_registered() ) {
2141
+ if ( ! $this->is_sync_cron_on() ) {
2142
+ $this->schedule_sync_cron();
 
 
 
 
 
 
 
 
 
 
2143
  }
2144
  }
2145
 
2146
+ /**
2147
+ * Check if requested for manual blocking background sync.
2148
+ */
2149
+ if ( fs_request_has( 'background_sync' ) ) {
2150
+ $this->run_manual_sync();
2151
+ }
 
2152
  }
2153
  }
2154
 
2155
+ if ( $this->is_registered() ) {
2156
+ $this->hook_callback_to_install_sync();
 
 
 
 
 
 
 
 
2157
  }
2158
 
2159
  if ( $this->is_addon() ) {
2160
  if ( $this->is_parent_plugin_installed() ) {
2161
  // Link to parent FS.
2162
+ $this->_parent = self::get_instance_by_id( $this->_plugin->parent_plugin_id );
2163
 
2164
  // Get parent plugin reference.
2165
  $this->_parent_plugin = $this->_parent->get_plugin();
2166
  }
2167
  }
2168
 
2169
+ if ( $this->is_user_in_admin() ) {
2170
  global $pagenow;
2171
  if ( 'plugins.php' === $pagenow ) {
2172
  $this->hook_plugin_action_links();
2174
 
2175
  if ( $this->is_addon() ) {
2176
  if ( ! $this->is_parent_plugin_installed() ) {
2177
+ $parent_name = $this->get_option( $plugin_info, 'parent_name', null );
2178
+
2179
+ if ( isset( $plugin_info['parent'] ) ) {
2180
+ $parent_name = $this->get_option( $plugin_info['parent'], 'name', null );
2181
+ }
2182
+
2183
  $this->_admin_notices->add(
2184
+ ( ! empty( $parent_name ) ?
2185
+ sprintf( __fs( 'addon-x-cannot-run-without-y', $this->_slug ), $this->get_plugin_name(), $parent_name ) :
2186
  sprintf( __fs( 'addon-x-cannot-run-without-parent', $this->_slug ), $this->get_plugin_name() )
2187
  ),
2188
  __fs( 'oops', $this->_slug ) . '...',
2199
  // @todo This should be only executed on activation. It should be migrated to register_activation_hook() together with other activation related logic.
2200
  if ( $this->is_premium() ) {
2201
  // Remove add-on download admin-notice.
2202
+ $this->_parent->_admin_notices->remove_sticky( array(
2203
+ 'addon_plan_upgraded_' . $this->_slug,
2204
+ 'no_addon_license_' . $this->_slug,
2205
+ ) );
2206
  }
2207
+
2208
+ $this->deactivate_premium_only_addon_without_license();
2209
  }
2210
  } else {
2211
  add_action( 'admin_init', array( &$this, '_admin_init_action' ) );
2212
 
2213
+ if ( $this->has_addons() &&
2214
  'plugin-information' === fs_request_get( 'tab', false ) &&
2215
  $this->get_id() == fs_request_get( 'parent_plugin_id', false )
2216
  ) {
2217
+ require_once WP_FS__DIR_INCLUDES . '/fs-plugin-info-dialog.php';
 
2218
 
2219
+ new FS_Plugin_Info_Dialog( $this );
 
 
 
 
 
 
 
 
 
2220
  }
2221
  }
2222
 
2234
 
2235
  $this->do_action( 'initiated' );
2236
 
2237
+ if ( $this->_storage->prev_is_premium !== $this->_plugin->is_premium ) {
2238
+ if ( isset( $this->_storage->prev_is_premium ) ) {
2239
+ $this->apply_filters(
2240
+ 'after_code_type_change',
2241
+ // New code type.
2242
+ $this->_plugin->is_premium
2243
+ );
2244
+ } else {
2245
+ // Set for code type for the first time.
2246
+ $this->_storage->prev_is_premium = $this->_plugin->is_premium;
2247
+ }
2248
+ }
2249
+
2250
  if ( ! $this->is_addon() ) {
2251
  if ( $this->is_registered() ) {
2252
  // Fix for upgrade from versions < 1.0.9.
2253
  if ( ! isset( $this->_storage->activation_timestamp ) ) {
2254
  $this->_storage->activation_timestamp = WP_FS__SCRIPT_START_TIME;
2255
  }
 
 
 
 
 
 
 
 
 
 
 
2256
 
2257
  $this->do_action( 'after_init_plugin_registered' );
2258
  } else if ( $this->is_anonymous() ) {
2269
  $this->do_action( 'after_init_addon_pending_activations' );
2270
  }
2271
  }
2272
+
2273
+ // Add license activation link and AJAX request handler.
2274
+ if ( $this->has_paid_plan() ) {
2275
+ global $pagenow;
2276
+ if ( 'plugins.php' === $pagenow ) {
2277
+ /**
2278
+ * @since 1.2.0 Add license action link only on plugins page.
2279
+ */
2280
+ $this->_add_license_action_link();
2281
+ $this->_require_license_activation_dialog();
2282
+ }
2283
+
2284
+ if ( $this->is_ajax_action( array(
2285
+ 'activate_license',
2286
+ 'resend_license_key'
2287
+ ) )
2288
+ ) {
2289
+ // Hook license activation and resend AJAX callbacks.
2290
+ $this->_require_license_activation_dialog();
2291
+ }
2292
+ }
2293
+ }
2294
+
2295
+ /**
2296
+ * Parse plugin's settings (as defined by the plugin dev).
2297
+ *
2298
+ * @author Vova Feldman (@svovaf)
2299
+ * @since 1.1.7.3
2300
+ *
2301
+ * @param array $plugin_info
2302
+ *
2303
+ * @throws \Freemius_Exception
2304
+ */
2305
+ private function parse_settings( &$plugin_info ) {
2306
+ $this->_logger->entrance();
2307
+
2308
+ $id = $this->get_numeric_option( $plugin_info, 'id', false );
2309
+ $public_key = $this->get_option( $plugin_info, 'public_key', false );
2310
+ $secret_key = $this->get_option( $plugin_info, 'secret_key', null );
2311
+ $parent_id = $this->get_numeric_option( $plugin_info, 'parent_id', null );
2312
+ $parent_name = $this->get_option( $plugin_info, 'parent_name', null );
2313
+
2314
+ /**
2315
+ * @author Vova Feldman (@svovaf)
2316
+ * @since 1.1.9 Try to pull secret key from external config.
2317
+ */
2318
+ if ( is_null( $secret_key ) && defined( "WP_FS__{$this->_slug}_SECRET_KEY" ) ) {
2319
+ $secret_key = constant( "WP_FS__{$this->_slug}_SECRET_KEY" );
2320
+ }
2321
+
2322
+ if ( isset( $plugin_info['parent'] ) ) {
2323
+ $parent_id = $this->get_numeric_option( $plugin_info['parent'], 'id', null );
2324
+ // $parent_slug = $this->get_option( $plugin_info['parent'], 'slug', null );
2325
+ // $parent_public_key = $this->get_option( $plugin_info['parent'], 'public_key', null );
2326
+ $parent_name = $this->get_option( $plugin_info['parent'], 'name', null );
2327
+ }
2328
+
2329
+ if ( false === $id ) {
2330
+ throw new Freemius_Exception( 'Plugin id parameter is not set.' );
2331
+ }
2332
+ if ( false === $public_key ) {
2333
+ throw new Freemius_Exception( 'Plugin public_key parameter is not set.' );
2334
+ }
2335
+
2336
+ $plugin = ( $this->_plugin instanceof FS_Plugin ) ?
2337
+ $this->_plugin :
2338
+ new FS_Plugin();
2339
+
2340
+ $plugin->update( array(
2341
+ 'id' => $id,
2342
+ 'public_key' => $public_key,
2343
+ 'slug' => $this->_slug,
2344
+ 'parent_plugin_id' => $parent_id,
2345
+ 'version' => $this->get_plugin_version(),
2346
+ 'title' => $this->get_plugin_name(),
2347
+ 'file' => $this->_plugin_basename,
2348
+ 'is_premium' => $this->get_bool_option( $plugin_info, 'is_premium', true ),
2349
+ 'is_live' => $this->get_bool_option( $plugin_info, 'is_live', true ),
2350
+ // 'secret_key' => $secret_key,
2351
+ ) );
2352
+
2353
+ if ( $plugin->is_updated() ) {
2354
+ // Update plugin details.
2355
+ $this->_plugin = FS_Plugin_Manager::instance( $this->_slug )->store( $plugin );
2356
+ }
2357
+ // Set the secret key after storing the plugin, we don't want to store the key in the storage.
2358
+ $this->_plugin->secret_key = $secret_key;
2359
+
2360
+ if ( ! isset( $plugin_info['menu'] ) ) {
2361
+ // Back compatibility to 1.1.2
2362
+ $plugin_info['menu'] = array(
2363
+ 'slug' => isset( $plugin_info['menu_slug'] ) ?
2364
+ $plugin_info['menu_slug'] :
2365
+ $this->_slug
2366
+ );
2367
+ }
2368
+
2369
+ $this->_menu = FS_Admin_Menu_Manager::instance( $this->_slug );
2370
+ $this->_menu->init( $plugin_info['menu'], $this->is_addon() );
2371
+
2372
+ $this->_has_addons = $this->get_bool_option( $plugin_info, 'has_addons', false );
2373
+ $this->_has_paid_plans = $this->get_bool_option( $plugin_info, 'has_paid_plans', true );
2374
+ $this->_is_org_compliant = $this->get_bool_option( $plugin_info, 'is_org_compliant', true );
2375
+ $this->_is_premium_only = $this->get_bool_option( $plugin_info, 'is_premium_only', false );
2376
+ if ( $this->_is_premium_only ) {
2377
+ // If premium only plugin, disable anonymous mode.
2378
+ $this->_enable_anonymous = false;
2379
+ $this->_anonymous_mode = false;
2380
+ } else {
2381
+ $this->_enable_anonymous = $this->get_bool_option( $plugin_info, 'enable_anonymous', true );
2382
+ $this->_anonymous_mode = $this->get_bool_option( $plugin_info, 'anonymous_mode', false );
2383
+ }
2384
+ $this->_permissions = $this->get_option( $plugin_info, 'permissions', array() );
2385
+ }
2386
+
2387
+ /**
2388
+ * @param string[] $options
2389
+ * @param string $key
2390
+ * @param mixed $default
2391
+ *
2392
+ * @return bool
2393
+ */
2394
+ private function get_option( &$options, $key, $default = false ) {
2395
+ return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
2396
+ }
2397
+
2398
+ private function get_bool_option( &$options, $key, $default = false ) {
2399
+ return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
2400
+ }
2401
+
2402
+ private function get_numeric_option( &$options, $key, $default = false ) {
2403
+ return isset( $options[ $key ] ) && is_numeric( $options[ $key ] ) ? $options[ $key ] : $default;
2404
+ }
2405
+
2406
+ /**
2407
+ * Gate keeper.
2408
+ *
2409
+ * @author Vova Feldman (@svovaf)
2410
+ * @since 1.1.7.3
2411
+ *
2412
+ * @return bool
2413
+ */
2414
+ private function should_stop_execution() {
2415
+ if ( empty( $this->_storage->was_plugin_loaded ) ) {
2416
+ /**
2417
+ * Don't execute Freemius until plugin was fully loaded at least once,
2418
+ * to give the opportunity for the activation hook to run before pinging
2419
+ * the API for connectivity test. This logic is relevant for the
2420
+ * identification of new plugin install vs. plugin update.
2421
+ *
2422
+ * @author Vova Feldman (@svovaf)
2423
+ * @since 1.1.9
2424
+ */
2425
+ return true;
2426
+ }
2427
+
2428
+ if ( $this->is_activation_mode() ) {
2429
+ if ( ! is_admin() ) {
2430
+ /**
2431
+ * If in activation mode, don't execute Freemius outside of the
2432
+ * admin dashboard.
2433
+ *
2434
+ * @author Vova Feldman (@svovaf)
2435
+ * @since 1.1.7.3
2436
+ */
2437
+ return true;
2438
+ }
2439
+
2440
+ if ( ! WP_FS__IS_HTTP_REQUEST ) {
2441
+ /**
2442
+ * If in activation and executed without HTTP context (e.g. CLI, Cronjob),
2443
+ * then don't start Freemius.
2444
+ *
2445
+ * @author Vova Feldman (@svovaf)
2446
+ * @since 1.1.6.3
2447
+ *
2448
+ * @link https://wordpress.org/support/topic/errors-in-the-freemius-class-when-running-in-wordpress-in-cli
2449
+ */
2450
+ return true;
2451
+ }
2452
+
2453
+ if ( $this->is_cron() ) {
2454
+ /**
2455
+ * If in activation mode, don't execute Freemius during wp crons
2456
+ * (wp crons have HTTP context - called as HTTP request).
2457
+ *
2458
+ * @author Vova Feldman (@svovaf)
2459
+ * @since 1.1.7.3
2460
+ */
2461
+ return true;
2462
+ }
2463
+
2464
+ if ( $this->is_ajax() &&
2465
+ ! $this->_admin_notices->has_sticky( 'failed_connect_api_first' ) &&
2466
+ ! $this->_admin_notices->has_sticky( 'failed_connect_api' )
2467
+ ) {
2468
+ /**
2469
+ * During activation, if running in AJAX mode, unless there's a sticky
2470
+ * connectivity issue notice, don't run Freemius.
2471
+ *
2472
+ * @author Vova Feldman (@svovaf)
2473
+ * @since 1.1.7.3
2474
+ */
2475
+ return true;
2476
+ }
2477
+ }
2478
+
2479
+ return false;
2480
+ }
2481
+
2482
+ /**
2483
+ * Triggered after code type has changed.
2484
+ *
2485
+ * @author Vova Feldman (@svovaf)
2486
+ * @since 1.1.9.1
2487
+ */
2488
+ function _after_code_type_change() {
2489
+ $this->_logger->entrance();
2490
+
2491
+ add_action( is_admin() ? 'admin_init' : 'init', array(
2492
+ &$this,
2493
+ '_plugin_code_type_changed'
2494
+ ) );
2495
  }
2496
 
2497
  /**
2501
  * @since 1.0.9
2502
  */
2503
  function _plugin_code_type_changed() {
2504
+ $this->_logger->entrance();
2505
+
2506
+ // Schedule code type changes event.
2507
+ // $this->sync_install();
2508
+ $this->schedule_install_sync();
2509
 
2510
  if ( $this->is_premium() ) {
2511
  // Activated premium code.
2524
  __fs( 'woot', $this->_slug ) . '!'
2525
  );
2526
  } else {
2527
+ // Remove sticky message related to premium code activation.
2528
+ $this->_admin_notices->remove_sticky( 'premium_activated' );
2529
+
2530
  // Activated free code (after had the premium before).
2531
  $this->do_action( 'after_free_version_reactivation' );
2532
 
2535
  sprintf(
2536
  __fs( 'you-have-x-license', $this->_slug ),
2537
  $this->_site->plan->title
2538
+ ) . $this->get_complete_upgrade_instructions(),
 
 
 
2539
  'plan_upgraded',
2540
  __fs( 'yee-haw', $this->_slug ) . '!'
2541
  );
2542
  }
2543
  }
2544
 
2545
+ /**
2546
+ * Unregister the uninstall hook for the other version of the plugin (with different code type) to avoid
2547
+ * triggering a fatal error when uninstalling that plugin. For example, after deactivating the "free" version
2548
+ * of a specific plugin, its uninstall hook should be unregistered after the "premium" version has been
2549
+ * activated. If we don't do that, a fatal error will occur when we try to uninstall the "free" version since
2550
+ * the main file of the "free" version will be loaded first before calling the hooked callback. Since the
2551
+ * free and premium versions are almost identical (same class or have same functions), a fatal error like
2552
+ * "Cannot redeclare class MyClass" or "Cannot redeclare my_function()" will occur.
2553
+ */
2554
+ $this->unregister_uninstall_hook();
2555
+
2556
+ $this->clear_module_main_file_cache();
2557
+
2558
  // Update is_premium of latest version.
2559
  $this->_storage->prev_is_premium = $this->_plugin->is_premium;
2560
  }
2564
  #region Add-ons -------------------------------------------------------------------------
2565
 
2566
  /**
2567
+ * Check if add-on installed and activated on site.
2568
  *
2569
  * @author Vova Feldman (@svovaf)
2570
  * @since 1.0.6
2571
  *
2572
+ * @param string|number $slug_or_id
 
 
2573
  *
2574
+ * @return bool
2575
  */
2576
+ function is_addon_activated( $slug_or_id ) {
2577
+ return self::has_instance( $slug_or_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2578
  }
2579
 
2580
  /**
2581
+ * Check if add-on was connected to install
2582
  *
2583
  * @author Vova Feldman (@svovaf)
2584
+ * @since 1.1.7
2585
  *
2586
+ * @param string $slug
2587
  *
2588
  * @return bool
2589
  */
2590
+ function is_addon_connected( $slug ) {
2591
+ $sites = self::get_all_sites();
2592
+
2593
+ if ( ! isset( $sites[ $slug ] ) ) {
2594
+ return false;
2595
+ }
2596
+
2597
+ $site = $sites[ $slug ];
2598
+
2599
+ $plugin = FS_Plugin_Manager::instance( $slug )->get();
2600
+
2601
+ if ( $plugin->parent_plugin_id != $this->_plugin->id ) {
2602
+ // The given slug do NOT belong to any of the plugin's add-ons.
2603
+ return false;
2604
+ }
2605
+
2606
+ return ( is_object( $site ) &&
2607
+ is_numeric( $site->id ) &&
2608
+ is_numeric( $site->user_id ) &&
2609
+ is_object( $site->plan )
2610
+ );
2611
  }
2612
 
2613
  /**
2641
  self::instance( $slug )->get_plugin_basename();
2642
  }
2643
 
2644
+ $premium_basename = $slug . '-premium/' . $slug . '.php';
2645
+
2646
+ if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_basename ) ) ) {
2647
+ return $premium_basename;
2648
+ }
2649
+
2650
+ $free_basename = $slug . '/' . $slug . '.php';
2651
+
2652
+ return $free_basename;
2653
  }
2654
 
2655
  /**
2682
  * @return bool
2683
  */
2684
  function has_installed_addons() {
2685
+ if ( ! $this->has_addons() ) {
2686
  return false;
2687
  }
2688
 
2694
  }
2695
  }
2696
 
2697
+ return false;
2698
+ }
2699
+
2700
+ /**
2701
+ * Tell Freemius that the current plugin is an add-on.
2702
+ *
2703
+ * @author Vova Feldman (@svovaf)
2704
+ * @since 1.0.6
2705
+ *
2706
+ * @param number $parent_plugin_id The parent plugin ID
2707
+ */
2708
+ function init_addon( $parent_plugin_id ) {
2709
+ $this->_plugin->parent_plugin_id = $parent_plugin_id;
2710
+ }
2711
+
2712
+ /**
2713
+ * @author Vova Feldman (@svovaf)
2714
+ * @since 1.0.6
2715
+ *
2716
+ * @return bool
2717
+ */
2718
+ function is_addon() {
2719
+ return isset( $this->_plugin->parent_plugin_id ) && is_numeric( $this->_plugin->parent_plugin_id );
2720
+ }
2721
+
2722
+ /**
2723
+ * Deactivate add-on if it's premium only and the user does't have a valid license.
2724
+ *
2725
+ * @param bool $is_after_trial_cancel
2726
+ *
2727
+ * @return bool If add-on was deactivated.
2728
+ */
2729
+ private function deactivate_premium_only_addon_without_license( $is_after_trial_cancel = false ) {
2730
+ if ( ! $this->has_free_plan() &&
2731
+ ! $this->has_features_enabled_license() &&
2732
+ ! $this->_has_premium_license()
2733
+ ) {
2734
+ // IF wrapper is turned off because activation_timestamp is currently only stored for plugins (not addons).
2735
+ // if (empty($this->_storage->activation_timestamp) ||
2736
+ // (WP_FS__SCRIPT_START_TIME - $this->_storage->activation_timestamp) > 30
2737
+ // ) {
2738
+ /**
2739
+ * @todo When it's first fail, there's no reason to try and re-sync because the licenses were just synced after initial activation.
2740
+ *
2741
+ * Retry syncing the user add-on licenses.
2742
+ */
2743
+ // Sync licenses.
2744
+ $this->_sync_licenses();
2745
+ // }
2746
+
2747
+ // Try to activate premium license.
2748
+ $this->_activate_license( true );
2749
+
2750
+ if ( ! $this->has_free_plan() &&
2751
+ ! $this->has_features_enabled_license() &&
2752
+ ! $this->_has_premium_license()
2753
+ ) {
2754
+ // @todo Check if deactivate plugins also call the deactivation hook.
2755
+
2756
+ deactivate_plugins( array( $this->_plugin_basename ), true );
2757
+
2758
+ $this->_parent->_admin_notices->add_sticky(
2759
+ sprintf(
2760
+ __fs( ( $is_after_trial_cancel ?
2761
+ 'addon-trial-cancelled-message' :
2762
+ 'addon-no-license-message' ),
2763
+ $this->_parent->_slug
2764
+ ),
2765
+ '<b>' . $this->_plugin->title . '</b>'
2766
+ ) . ' ' . sprintf(
2767
+ '<a href="%s" aria-label="%s" class="button button-primary" style="margin-left: 10px; vertical-align: middle;">%s &nbsp;&#10140;</a>',
2768
+ $this->_parent->addon_url( $this->_slug ),
2769
+ esc_attr( sprintf( __fs( 'more-information-about-x', $this->_parent->_slug ), $this->_plugin->title ) ),
2770
+ __fs( 'purchase-license', $this->_parent->_slug )
2771
+ ),
2772
+ 'no_addon_license_' . $this->_slug,
2773
+ ( $is_after_trial_cancel ? '' : __fs( 'oops', $this->_parent->_slug ) . '...' ),
2774
+ ( $is_after_trial_cancel ? 'success' : 'error' )
2775
+ );
2776
+
2777
+ return true;
2778
+ }
2779
+ }
2780
+
2781
+ return false;
2782
+ }
2783
+
2784
+ #endregion ------------------------------------------------------------------
2785
+
2786
+ #region Sandbox ------------------------------------------------------------------
2787
+
2788
+ /**
2789
+ * Set Freemius into sandbox mode for debugging.
2790
+ *
2791
+ * @author Vova Feldman (@svovaf)
2792
+ * @since 1.0.4
2793
+ *
2794
+ * @param string $secret_key
2795
+ */
2796
+ function init_sandbox( $secret_key ) {
2797
+ $this->_plugin->secret_key = $secret_key;
2798
+
2799
+ // Update plugin details.
2800
+ FS_Plugin_Manager::instance( $this->_slug )->update( $this->_plugin, true );
2801
+ }
2802
+
2803
+ /**
2804
+ * Check if running payments in sandbox mode.
2805
+ *
2806
+ * @author Vova Feldman (@svovaf)
2807
+ * @since 1.0.4
2808
+ *
2809
+ * @return bool
2810
+ */
2811
+ function is_payments_sandbox() {
2812
+ return ( ! $this->is_live() ) || isset( $this->_plugin->secret_key );
2813
+ }
2814
+
2815
+ #endregion Sandbox ------------------------------------------------------------------
2816
+
2817
+ /**
2818
+ * Check if running test vs. live plugin.
2819
+ *
2820
+ * @author Vova Feldman (@svovaf)
2821
+ * @since 1.0.5
2822
+ *
2823
+ * @return bool
2824
+ */
2825
+ function is_live() {
2826
+ return $this->_plugin->is_live;
2827
+ }
2828
+
2829
+ /**
2830
+ * Check if the user skipped connecting the account with Freemius.
2831
+ *
2832
+ * @author Vova Feldman (@svovaf)
2833
+ * @since 1.0.7
2834
+ *
2835
+ * @return bool
2836
+ */
2837
+ function is_anonymous() {
2838
+ if ( ! isset( $this->_is_anonymous ) ) {
2839
+ if ( ! isset( $this->_storage->is_anonymous ) ) {
2840
+ // Not skipped.
2841
+ $this->_is_anonymous = false;
2842
+ } else if ( is_bool( $this->_storage->is_anonymous ) ) {
2843
+ // For back compatibility, since the variable was boolean before.
2844
+ $this->_is_anonymous = $this->_storage->is_anonymous;
2845
+
2846
+ // Upgrade stored data format to 1.1.3 format.
2847
+ $this->set_anonymous_mode( $this->_storage->is_anonymous );
2848
+ } else {
2849
+ // Version 1.1.3 and later.
2850
+ $this->_is_anonymous = $this->_storage->is_anonymous['is'];
2851
+ }
2852
+ }
2853
+
2854
+ return $this->_is_anonymous;
2855
+ }
2856
+
2857
+ /**
2858
+ * Check if user connected his account and install pending email activation.
2859
+ *
2860
+ * @author Vova Feldman (@svovaf)
2861
+ * @since 1.0.7
2862
+ *
2863
+ * @return bool
2864
+ */
2865
+ function is_pending_activation() {
2866
+ return $this->_storage->get( 'is_pending_activation', false );
2867
+ }
2868
+
2869
+ /**
2870
+ * Check if plugin must be WordPress.org compliant.
2871
+ *
2872
+ * @since 1.0.7
2873
+ *
2874
+ * @return bool
2875
+ */
2876
+ function is_org_repo_compliant() {
2877
+ return $this->_is_org_compliant;
2878
+ }
2879
+
2880
+ #region Daily Sync Cron ------------------------------------------------------------------
2881
+
2882
+ /**
2883
+ * @author Vova Feldman (@svovaf)
2884
+ * @since 1.1.7.3
2885
+ */
2886
+ private function run_manual_sync() {
2887
+ $this->require_pluggable_essentials();
2888
+
2889
+ if ( ! current_user_can( 'activate_plugins' ) ) {
2890
+ return;
2891
+ }
2892
+
2893
+ // Run manual sync.
2894
+ $this->_sync_cron();
2895
+
2896
+ // Reschedule next cron to run 24 hours from now (performance optimization).
2897
+ $this->clear_sync_cron();
2898
+
2899
+ $this->schedule_sync_cron( time() + WP_FS__TIME_24_HOURS_IN_SEC, false );
2900
+ }
2901
+
2902
+ /**
2903
+ * Data sync cron job. Replaces the background sync non blocking HTTP request
2904
+ * that doesn't halt page loading.
2905
+ *
2906
+ * @author Vova Feldman (@svovaf)
2907
+ * @since 1.1.7.3
2908
+ */
2909
+ function _sync_cron() {
2910
+ $this->_logger->entrance();
2911
+
2912
+ // Store the last time data sync was executed.
2913
+ $this->_storage->sync_timestamp = time();
2914
+
2915
+ // Check if API is temporary down.
2916
+ if ( FS_Api::is_temporary_down() ) {
2917
+ return;
2918
+ }
2919
+
2920
+ // @todo Add logic that identifies API latency, and reschedule the next background sync randomly between 8-16 hours.
2921
+
2922
+ if ( $this->is_registered() ) {
2923
+ if ( $this->has_paid_plan() ) {
2924
+ // Initiate background plan sync.
2925
+ $this->_sync_license( true );
2926
+
2927
+ if ( $this->is_paying() ) {
2928
+ // Check for premium plugin updates.
2929
+ $this->_check_updates( true );
2930
+ }
2931
+ } else {
2932
+ // Sync install (only if something changed locally).
2933
+ $this->sync_install();
2934
+ }
2935
+ }
2936
+
2937
+ $this->do_action( 'after_sync_cron' );
2938
+ }
2939
+
2940
+ /**
2941
+ * Check if sync was executed in the last $period of seconds.
2942
+ *
2943
+ * @author Vova Feldman (@svovaf)
2944
+ * @since 1.1.7.3
2945
+ *
2946
+ * @param int $period In seconds
2947
+ *
2948
+ * @return bool
2949
+ */
2950
+ private function is_sync_executed( $period = WP_FS__TIME_24_HOURS_IN_SEC ) {
2951
+ if ( ! isset( $this->_storage->sync_timestamp ) ) {
2952
+ return false;
2953
+ }
2954
+
2955
+ return ( $this->_storage->sync_timestamp > ( WP_FS__SCRIPT_START_TIME - $period ) );
2956
+ }
2957
+
2958
+ /**
2959
+ * @author Vova Feldman (@svovaf)
2960
+ * @since 1.1.7.3
2961
+ *
2962
+ * @return bool
2963
+ */
2964
+ private function is_sync_cron_on() {
2965
+ /**
2966
+ * @var object $sync_cron_data
2967
+ */
2968
+ $sync_cron_data = $this->_storage->get( 'sync_cron', null );
2969
+
2970
+ return ( ! is_null( $sync_cron_data ) && true === $sync_cron_data->on );
2971
+ }
2972
+
2973
+ /**
2974
+ * @author Vova Feldman (@svovaf)
2975
+ * @since 1.1.7.3
2976
+ *
2977
+ * @param int $start_at Defaults to now.
2978
+ * @param bool $randomize_start If true, schedule first job randomly during the next 12 hours. Otherwise,
2979
+ * schedule job to start right away.
2980
+ */
2981
+ private function schedule_sync_cron( $start_at = WP_FS__SCRIPT_START_TIME, $randomize_start = true ) {
2982
+ $this->_logger->entrance();
2983
+
2984
+ if ( $randomize_start ) {
2985
+ // Schedule first sync with a random 12 hour time range from now.
2986
+ $start_at += rand( 0, ( WP_FS__TIME_24_HOURS_IN_SEC / 2 ) );
2987
+ }
2988
+
2989
+ // Schedule daily WP cron.
2990
+ wp_schedule_event(
2991
+ $start_at,
2992
+ 'daily',
2993
+ $this->get_action_tag( 'data_sync' )
2994
+ );
2995
+
2996
+ $this->_storage->store( 'sync_cron', (object) array(
2997
+ 'version' => $this->get_plugin_version(),
2998
+ 'sdk_version' => $this->version,
2999
+ 'timestamp' => WP_FS__SCRIPT_START_TIME,
3000
+ 'on' => true,
3001
+ ) );
3002
  }
3003
 
3004
  /**
3005
+ * Add the actual sync function to the cron job hook.
3006
  *
3007
  * @author Vova Feldman (@svovaf)
3008
+ * @since 1.1.7.3
 
 
3009
  */
3010
+ private function hook_callback_to_sync_cron() {
3011
+ $this->add_action( 'data_sync', array( &$this, '_sync_cron' ) );
3012
  }
3013
 
3014
  /**
3015
  * @author Vova Feldman (@svovaf)
3016
+ * @since 1.1.7.3
 
 
3017
  */
3018
+ private function clear_sync_cron() {
3019
+ $this->_logger->entrance();
 
3020
 
3021
+ if ( ! $this->is_sync_cron_on() ) {
3022
+ return;
3023
+ }
3024
 
3025
+ $this->_storage->remove( 'sync_cron' );
3026
+
3027
+ wp_clear_scheduled_hook( $this->get_action_tag( 'data_sync' ) );
3028
+ }
3029
 
3030
  /**
3031
+ * Unix timestamp for next sync cron execution or false if not scheduled.
3032
  *
3033
  * @author Vova Feldman (@svovaf)
3034
+ * @since 1.1.7.3
3035
  *
3036
+ * @return int|false
3037
  */
3038
+ function next_sync_cron() {
3039
+ $this->_logger->entrance();
3040
 
3041
+ if ( ! $this->is_sync_cron_on() ) {
3042
+ return false;
3043
+ }
3044
+
3045
+ return wp_next_scheduled( $this->get_action_tag( 'data_sync' ) );
3046
  }
3047
 
3048
  /**
3049
+ * Unix timestamp for previous sync cron execution or false if never executed.
3050
  *
3051
  * @author Vova Feldman (@svovaf)
3052
+ * @since 1.1.7.3
3053
  *
3054
+ * @return int|false
3055
  */
3056
+ function last_sync_cron() {
3057
+ $this->_logger->entrance();
3058
+
3059
+ return $this->_storage->get( 'sync_timestamp' );
3060
  }
3061
 
3062
+ #endregion Daily Sync Cron ------------------------------------------------------------------
3063
+
3064
+ #region Async Install Sync ------------------------------------------------------------------
3065
 
3066
  /**
 
 
3067
  * @author Vova Feldman (@svovaf)
3068
+ * @since 1.1.7.3
3069
  *
3070
  * @return bool
3071
  */
3072
+ private function is_install_sync_scheduled() {
3073
+ /**
3074
+ * @var object $cron_data
3075
+ */
3076
+ $cron_data = $this->_storage->get( 'install_sync_cron', null );
3077
+
3078
+ return ( ! is_null( $cron_data ) && true === $cron_data->on );
3079
  }
3080
 
3081
  /**
3082
+ * Instead of running blocking install sync event, execute non blocking scheduled wp-cron.
3083
  *
3084
  * @author Vova Feldman (@svovaf)
3085
+ * @since 1.1.7.3
 
 
3086
  */
3087
+ private function schedule_install_sync() {
3088
+ $this->_logger->entrance();
 
 
 
 
 
 
3089
 
3090
+ $this->clear_install_sync_cron();
 
 
 
 
 
 
3091
 
3092
+ // Schedule immediate install sync.
3093
+ wp_schedule_single_event(
3094
+ WP_FS__SCRIPT_START_TIME,
3095
+ $this->get_action_tag( 'install_sync' )
3096
+ );
3097
+
3098
+ $this->_storage->store( 'install_sync_cron', (object) array(
3099
+ 'version' => $this->get_plugin_version(),
3100
+ 'sdk_version' => $this->version,
3101
+ 'timestamp' => WP_FS__SCRIPT_START_TIME,
3102
+ 'on' => true,
3103
+ ) );
3104
  }
3105
 
3106
  /**
3107
+ * Unix timestamp for previous install sync cron execution or false if never executed.
3108
+ *
3109
+ * @todo There's some very strange bug that $this->_storage->install_sync_timestamp value is not being
3110
+ * updated. But for sure the sync event is working.
3111
  *
3112
  * @author Vova Feldman (@svovaf)
3113
+ * @since 1.1.7.3
3114
  *
3115
+ * @return int|false
3116
  */
3117
+ function last_install_sync() {
3118
+ $this->_logger->entrance();
 
3119
 
3120
+ return $this->_storage->get( 'install_sync_timestamp' );
 
 
 
 
 
 
 
 
3121
  }
3122
 
3123
  /**
3124
+ * Unix timestamp for next install sync cron execution or false if not scheduled.
3125
  *
3126
  * @author Vova Feldman (@svovaf)
3127
+ * @since 1.1.7.3
3128
  *
3129
+ * @return int|false
3130
  */
3131
+ function next_install_sync() {
3132
  $this->_logger->entrance();
3133
 
3134
+ if ( ! $this->is_install_sync_scheduled() ) {
 
3135
  return false;
3136
  }
3137
 
3138
+ return wp_next_scheduled( $this->get_action_tag( 'install_sync' ) );
3139
+ }
 
 
3140
 
3141
+ /**
3142
+ * Add the actual install sync function to the cron job hook.
3143
+ *
3144
+ * @author Vova Feldman (@svovaf)
3145
+ * @since 1.1.7.3
3146
+ */
3147
+ private function hook_callback_to_install_sync() {
3148
+ $this->add_action( 'install_sync', array( &$this, '_run_sync_install' ) );
3149
+ }
3150
 
3151
+ /**
3152
+ * @author Vova Feldman (@svovaf)
3153
+ * @since 1.1.7.3
3154
+ */
3155
+ private function clear_install_sync_cron() {
3156
+ $this->_logger->entrance();
3157
 
3158
+ if ( ! $this->is_install_sync_scheduled() ) {
3159
+ return;
 
 
3160
  }
3161
 
3162
+ $this->_storage->remove( 'install_sync_cron' );
 
 
 
 
 
 
 
 
 
 
 
 
3163
 
3164
+ wp_clear_scheduled_hook( $this->get_action_tag( 'install_sync' ) );
3165
+ }
 
 
 
 
 
3166
 
3167
+ /**
3168
+ * @author Vova Feldman (@svovaf)
3169
+ * @since 1.1.7.3
3170
+ */
3171
+ public function _run_sync_install() {
3172
+ $this->_logger->entrance();
3173
 
3174
+ // Update last install sync timestamp.
3175
+ $this->_storage->install_sync_timestamp = time();
3176
 
3177
+ $this->sync_install( array(), true );
3178
  }
3179
 
3180
+ #endregion Async Install Sync ------------------------------------------------------------------
3181
+
3182
  /**
3183
  * Show a notice that activation is currently pending.
3184
  *
3189
  */
3190
  function _add_pending_activation_notice( $email = false ) {
3191
  if ( ! is_string( $email ) ) {
3192
+ $current_user = self::_get_current_wp_user();
3193
  $email = $current_user->user_email;
3194
  }
3195
 
3252
  if ( ! $this->is_addon() && ! $this->is_registered() && ! $this->is_anonymous() ) {
3253
  if ( ! $this->is_pending_activation() ) {
3254
  if ( ! $this->_menu->is_activation_page() ) {
3255
+ if ( $this->is_plugin_new_install() || $this->is_only_premium() ) {
3256
  // Show notice for new plugin installations.
3257
  $this->_admin_notices->add(
3258
  sprintf(
3283
  'update-nag'
3284
  );
3285
  }
3286
+
3287
+ if ( $this->has_filter( 'optin_pointer_element' ) ) {
3288
+ // Don't show admin nag if plugin update.
3289
+ wp_enqueue_script( 'wp-pointer' );
3290
+ wp_enqueue_style( 'wp-pointer' );
3291
+
3292
+ $this->_enqueue_connect_essentials();
3293
+
3294
+ add_action( 'admin_print_footer_scripts', array(
3295
+ $this,
3296
+ '_add_connect_pointer_script'
3297
+ ) );
3298
+ }
3299
+
3300
  }
3301
  }
3302
  }
3320
 
3321
  fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
3322
  }
3323
+
3324
+ /**
3325
+ * Add connect / opt-in pointer.
3326
+ *
3327
+ * @author Vova Feldman (@svovaf)
3328
+ * @since 1.1.4
3329
+ */
3330
+ function _add_connect_pointer_script() {
3331
+ $vars = array( 'slug' => $this->_slug );
3332
+ $pointer_content = fs_get_template( 'connect.php', $vars );
3333
+ ?>
3334
+ <script type="text/javascript">// <![CDATA[
3335
+ jQuery(document).ready(function ($) {
3336
+ if ('undefined' !== typeof(jQuery().pointer)) {
3337
+
3338
+ var element = <?php echo $this->apply_filters('optin_pointer_element', '$("#non_existing_element");') ?>;
3339
+
3340
+ if (element.length > 0) {
3341
+ var optin = $(element).pointer($.extend(true, {}, {
3342
+ content : <?php echo json_encode($pointer_content) ?>,
3343
+ position : {
3344
+ edge : 'left',
3345
+ align: 'center'
3346
+ },
3347
+ buttons : function () {
3348
+ // Don't show pointer buttons.
3349
+ return '';
3350
+ },
3351
+ pointerWidth: 482
3352
+ }, <?php echo $this->apply_filters('optin_pointer_options_json', '{}') ?>));
3353
+
3354
+ <?php
3355
+ echo $this->apply_filters('optin_pointer_execute', "
3356
+
3357
+ optin.pointer('open');
3358
+
3359
+ // Tag the opt-in pointer with custom class.
3360
+ $('.wp-pointer #fs_connect')
3361
+ .parents('.wp-pointer.wp-pointer-top')
3362
+ .addClass('fs-opt-in-pointer');
3363
+
3364
+ ", 'element', 'optin') ?>
3365
+ }
3366
+ }
3367
+ });
3368
+ // ]]></script>
3369
+ <?php
3370
+ }
3371
+
3372
  /**
3373
  * Return current page's URL.
3374
  *
3497
  return;
3498
  }
3499
 
3500
+ $this->unregister_uninstall_hook();
3501
+
3502
  // Clear API cache on activation.
3503
  FS_Api::clear_cache();
3504
 
3505
  if ( $this->is_registered() ) {
3506
+ // Schedule re-activation event and sync.
3507
+ // $this->sync_install( array(), true );
3508
+ $this->schedule_install_sync();
3509
 
3510
  /**
3511
  * @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.
3540
  * the first time that the plugin installed on the site, or the plugin was installed
3541
  * before but didn't have Freemius integrated.
3542
  *
3543
+ * Since register_activation_hook() do NOT fires on updates since 3.1, and only fires
3544
  * on manual activation via the dashboard, is_plugin_activation() is TRUE
3545
  * only after immediate activation.
3546
  *
3550
  $this->_storage->is_plugin_new_install = empty( $this->_storage->plugin_last_version );
3551
  }
3552
 
3553
+ if ( ! $this->_anonymous_mode && $this->has_api_connectivity( WP_FS__DEV_MODE ) ) {
3554
  // Store hint that the plugin was just activated to enable auto-redirection to settings.
3555
  add_option( "fs_{$this->_slug}_activated", true );
3556
  }
3557
+
3558
+ /**
3559
+ * Activation hook is executed after the plugin's main file is loaded, therefore,
3560
+ * after the plugin was loaded. The logic is located at activate_plugin()
3561
+ * ./wp-admin/includes/plugin.php.
3562
+ *
3563
+ * @author Vova Feldman (@svovaf)
3564
+ * @since 1.1.9
3565
+ */
3566
+ $this->_storage->was_plugin_loaded = true;
3567
  }
3568
 
3569
  /**
3599
 
3600
  self::$_accounts->store();
3601
 
3602
+ /**
3603
+ * IMPORTANT:
3604
+ * Clear crons must be executed before clearing all storage.
3605
+ * Otherwise, the cron will not be cleared.
3606
+ */
3607
+ $this->clear_sync_cron();
3608
+ $this->clear_install_sync_cron();
3609
+
3610
  // Clear all storage data.
3611
  $this->_storage->clear_all( true, array(
3612
  'connectivity_test',
3637
  unset( $this->_storage->sticky_optin_added );
3638
  }
3639
 
 
 
 
 
 
3640
  if ( ! isset( $this->_storage->is_plugin_new_install ) ) {
3641
  // Remember that plugin was already installed.
3642
  $this->_storage->is_plugin_new_install = false;
3643
  }
3644
 
3645
+ // Hook to plugin uninstall.
3646
+ register_uninstall_hook( $this->_plugin_main_file_path, array( 'Freemius', '_uninstall_plugin_hook' ) );
3647
+
3648
+ $this->clear_module_main_file_cache();
3649
+ $this->clear_sync_cron();
3650
+ $this->clear_install_sync_cron();
3651
+
3652
  if ( $this->is_registered() ) {
3653
  // Send deactivation event.
3654
  $this->sync_install( array(
3655
  'is_active' => false,
3656
  ) );
3657
+ } else {
3658
+ if ( ! $this->has_api_connectivity() ) {
3659
+ // Reset connectivity test cache.
3660
+ unset( $this->_storage->connectivity_test );
3661
+ }
3662
  }
3663
 
3664
  // Clear API cache on deactivation.
3738
  private function skip_connection() {
3739
  $this->_logger->entrance();
3740
 
3741
+ $this->_admin_notices->remove_sticky( 'connect_account' );
3742
+
3743
+ $this->set_anonymous_mode();
3744
+
3745
+ // Send anonymous skip event.
3746
+ // No user identified info nor any tracking will be sent after the user skips the opt-in.
3747
+ $this->get_api_plugin_scope()->call( 'skip.json', 'put', array(
3748
+ 'uid' => $this->get_anonymous_id(),
3749
+ ) );
3750
+ }
3751
+
3752
+ /**
3753
+ * Plugin version update hook.
3754
+ *
3755
+ * @author Vova Feldman (@svovaf)
3756
+ * @since 1.0.4
3757
+ */
3758
+ private function update_plugin_version_event() {
3759
+ $this->_logger->entrance();
3760
+
3761
+ if ( ! $this->is_registered() ) {
3762
+ return;
3763
+ }
3764
+
3765
+ $this->schedule_install_sync();
3766
+ // $this->sync_install( array(), true );
3767
+ }
3768
+
3769
+ /**
3770
+ * Return a list of modified plugins since the last sync.
3771
+ *
3772
+ * Note:
3773
+ * There's no point to store a plugins counter since even if the number of
3774
+ * plugins didn't change, we still need to check if the versions are all the
3775
+ * same and the activity state is similar.
3776
+ *
3777
+ * @author Vova Feldman (@svovaf)
3778
+ * @since 1.1.8
3779
+ *
3780
+ * @return array|false
3781
+ */
3782
+ private function get_plugins_data_for_api() {
3783
+ // Alias.
3784
+ $option_name = 'all_plugins';
3785
+
3786
+ $all_cached_plugins = self::$_accounts->get_option( $option_name );
3787
+
3788
+ if ( ! is_object( $all_cached_plugins ) ) {
3789
+ $all_cached_plugins = (object) array(
3790
+ 'timestamp' => '',
3791
+ 'md5' => '',
3792
+ 'plugins' => array(),
3793
+ );
3794
+ }
3795
+
3796
+ $time = time();
3797
+
3798
+ if ( ! empty( $all_cached_plugins->timestamp ) &&
3799
+ ( $time - $all_cached_plugins->timestamp ) < WP_FS__TIME_5_MIN_IN_SEC
3800
+ ) {
3801
+ // Don't send plugin updates if last update was in the past 5 min.
3802
+ return false;
3803
+ }
3804
+
3805
+ // Write timestamp to lock the logic.
3806
+ $all_cached_plugins->timestamp = $time;
3807
+ self::$_accounts->set_option( $option_name, $all_cached_plugins, true );
3808
+
3809
+ // Reload options from DB.
3810
+ self::$_accounts->load( true );
3811
+ $all_cached_plugins = self::$_accounts->get_option( $option_name );
3812
+
3813
+ if ( $time != $all_cached_plugins->timestamp ) {
3814
+ // If timestamp is different, then another thread captured the lock.
3815
+ return false;
3816
+ }
3817
+
3818
+ // Check if there's a change in plugins.
3819
+ $all_plugins = self::get_all_plugins();
3820
+
3821
+ // Check if plugins changed.
3822
+ ksort( $all_plugins );
3823
+
3824
+ $plugins_signature = '';
3825
+ foreach ( $all_plugins as $basename => $data ) {
3826
+ $plugins_signature .= $data['slug'] . ',' .
3827
+ $data['Version'] . ',' .
3828
+ ( $data['is_active'] ? '1' : '0' ) . ';';
3829
+ }
3830
+
3831
+ // Check if plugins status changed (version or active/inactive).
3832
+ $plugins_changed = ( $all_cached_plugins->md5 !== md5( $plugins_signature ) );
3833
+
3834
+ $plugins_update_data = array();
3835
+
3836
+ if ( $plugins_changed ) {
3837
+ // Change in plugins, report changes.
3838
+
3839
+ // Update existing plugins info.
3840
+ foreach ( $all_cached_plugins->plugins as $basename => $data ) {
3841
+ if ( ! isset( $all_plugins[ $basename ] ) ) {
3842
+ // Plugin uninstalled.
3843
+ $uninstalled_plugin_data = $data;
3844
+ $uninstalled_plugin_data['is_active'] = false;
3845
+ $uninstalled_plugin_data['is_uninstalled'] = true;
3846
+ $plugins_update_data[] = $uninstalled_plugin_data;
3847
+
3848
+ unset( $all_plugins[ $basename ] );
3849
+ unset( $all_cached_plugins->plugins[ $basename ] );
3850
+ } else if ( $data['is_active'] !== $all_plugins[ $basename ]['is_active'] ||
3851
+ $data['version'] !== $all_plugins[ $basename ]['Version']
3852
+ ) {
3853
+ // Plugin activated or deactivated, or version changed.
3854
+ $all_cached_plugins->plugins[ $basename ]['is_active'] = $all_plugins[ $basename ]['is_active'];
3855
+ $all_cached_plugins->plugins[ $basename ]['version'] = $all_plugins[ $basename ]['Version'];
3856
+
3857
+ $plugins_update_data[] = $all_cached_plugins->plugins[ $basename ];
3858
+ }
3859
+ }
3860
+
3861
+ // Find new plugins that weren't yet seen before.
3862
+ foreach ( $all_plugins as $basename => $data ) {
3863
+ if ( ! isset( $all_cached_plugins->plugins[ $basename ] ) ) {
3864
+ // New plugin.
3865
+ $new_plugin = array(
3866
+ 'slug' => $data['slug'],
3867
+ 'version' => $data['Version'],
3868
+ 'title' => $data['Name'],
3869
+ 'is_active' => $data['is_active'],
3870
+ 'is_uninstalled' => false,
3871
+ );
3872
+
3873
+ $plugins_update_data[] = $new_plugin;
3874
+ $all_cached_plugins->plugins[ $basename ] = $new_plugin;
3875
+ }
3876
+ }
3877
+
3878
+ $all_cached_plugins->md5 = md5( $plugins_signature );
3879
+ $all_cached_plugins->timestamp = $time;
3880
+ self::$_accounts->set_option( $option_name, $all_cached_plugins, true );
3881
+ }
3882
+
3883
+ return $plugins_update_data;
3884
+ }
3885
+
3886
+ /**
3887
+ * Return a list of modified themes since the last sync.
3888
+ *
3889
+ * Note:
3890
+ * There's no point to store a themes counter since even if the number of
3891
+ * themes didn't change, we still need to check if the versions are all the
3892
+ * same and the activity state is similar.
3893
+ *
3894
+ * @author Vova Feldman (@svovaf)
3895
+ * @since 1.1.8
3896
+ *
3897
+ * @return array|false
3898
+ */
3899
+ private function get_themes_data_for_api() {
3900
+ // Alias.
3901
+ $option_name = 'all_themes';
3902
+
3903
+ $all_cached_themes = self::$_accounts->get_option( $option_name );
3904
+
3905
+ if ( ! is_object( $all_cached_themes ) ) {
3906
+ $all_cached_themes = (object) array(
3907
+ 'timestamp' => '',
3908
+ 'md5' => '',
3909
+ 'themes' => array(),
3910
+ );
3911
+ }
3912
+
3913
+ $time = time();
3914
+
3915
+ if ( ! empty( $all_cached_themes->timestamp ) &&
3916
+ ( $time - $all_cached_themes->timestamp ) < WP_FS__TIME_5_MIN_IN_SEC
3917
+ ) {
3918
+ // Don't send theme updates if last update was in the past 5 min.
3919
+ return false;
3920
+ }
3921
+
3922
+ // Write timestamp to lock the logic.
3923
+ $all_cached_themes->timestamp = $time;
3924
+ self::$_accounts->set_option( $option_name, $all_cached_themes, true );
3925
+
3926
+ // Reload options from DB.
3927
+ self::$_accounts->load( true );
3928
+ $all_cached_themes = self::$_accounts->get_option( $option_name );
3929
+
3930
+ if ( $time != $all_cached_themes->timestamp ) {
3931
+ // If timestamp is different, then another thread captured the lock.
3932
+ return false;
3933
+ }
3934
+
3935
+ // Get active theme.
3936
+ $active_theme = wp_get_theme();
3937
+ $active_theme_stylesheet = $active_theme->get_stylesheet();
3938
+
3939
+ // Check if there's a change in themes.
3940
+ $all_themes = wp_get_themes();
3941
+
3942
+ // Check if themes changed.
3943
+ ksort( $all_themes );
3944
+
3945
+ $themes_signature = '';
3946
+ foreach ( $all_themes as $slug => $data ) {
3947
+ $is_active = ( $slug === $active_theme_stylesheet );
3948
+ $themes_signature .= $slug . ',' .
3949
+ $data->version . ',' .
3950
+ ( $is_active ? '1' : '0' ) . ';';
3951
+ }
3952
 
3953
+ // Check if themes status changed (version or active/inactive).
3954
+ $themes_changed = ( $all_cached_themes->md5 !== md5( $themes_signature ) );
3955
 
3956
+ $themes_update_data = array();
 
 
 
 
 
3957
 
3958
+ if ( $themes_changed ) {
3959
+ // Change in themes, report changes.
 
 
 
 
 
 
3960
 
3961
+ // Update existing themes info.
3962
+ foreach ( $all_cached_themes->themes as $slug => $data ) {
3963
+ $is_active = ( $slug === $active_theme_stylesheet );
3964
+
3965
+ if ( ! isset( $all_themes[ $slug ] ) ) {
3966
+ // Plugin uninstalled.
3967
+ $uninstalled_theme_data = $data;
3968
+ $uninstalled_theme_data['is_active'] = false;
3969
+ $uninstalled_theme_data['is_uninstalled'] = true;
3970
+ $themes_update_data[] = $uninstalled_theme_data;
3971
+
3972
+ unset( $all_themes[ $slug ] );
3973
+ unset( $all_cached_themes->themes[ $slug ] );
3974
+ } else if ( $data['is_active'] !== $is_active ||
3975
+ $data['version'] !== $all_themes[ $slug ]->version
3976
+ ) {
3977
+ // Plugin activated or deactivated, or version changed.
3978
+
3979
+ $all_cached_themes->themes[ $slug ]['is_active'] = $is_active;
3980
+ $all_cached_themes->themes[ $slug ]['version'] = $all_themes[ $slug ]->version;
3981
+
3982
+ $themes_update_data[] = $all_cached_themes->themes[ $slug ];
3983
+ }
3984
+ }
3985
+
3986
+ // Find new themes that weren't yet seen before.
3987
+ foreach ( $all_themes as $slug => $data ) {
3988
+ if ( ! isset( $all_cached_themes->themes[ $slug ] ) ) {
3989
+ $is_active = ( $slug === $active_theme_stylesheet );
3990
+
3991
+ // New plugin.
3992
+ $new_plugin = array(
3993
+ 'slug' => $slug,
3994
+ 'version' => $data->version,
3995
+ 'title' => $data->name,
3996
+ 'is_active' => $is_active,
3997
+ 'is_uninstalled' => false,
3998
+ );
3999
+
4000
+ $themes_update_data[] = $new_plugin;
4001
+ $all_cached_themes->themes[ $slug ] = $new_plugin;
4002
+ }
4003
+ }
4004
 
4005
+ $all_cached_themes->md5 = md5( $themes_signature );
4006
+ $all_cached_themes->timestamp = time();
4007
+ self::$_accounts->set_option( $option_name, $all_cached_themes, true );
4008
  }
4009
 
4010
+ return $themes_update_data;
 
4011
  }
4012
 
4013
  /**
4016
  * @author Vova Feldman (@svovaf)
4017
  * @since 1.1.2
4018
  *
4019
+ * @param string[] string $override
4020
+ * @param bool $include_plugins Since 1.1.8 by default include plugin changes.
4021
+ * @param bool $include_themes Since 1.1.8 by default include plugin changes.
4022
  *
4023
  * @return array
4024
  */
4025
+ private function get_install_data_for_api(
4026
+ array $override,
4027
+ $include_plugins = true,
4028
+ $include_themes = true
4029
+ ) {
4030
+ /**
4031
+ * @since 1.1.8 Also send plugin updates.
4032
+ */
4033
+ if ( $include_plugins && ! isset( $override['plugins'] ) ) {
4034
+ $plugins = $this->get_plugins_data_for_api();
4035
+ if ( ! empty( $plugins ) ) {
4036
+ $override['plugins'] = $plugins;
4037
+ }
4038
+ }
4039
+ /**
4040
+ * @since 1.1.8 Also send themes updates.
4041
+ */
4042
+ if ( $include_themes && ! isset( $override['themes'] ) ) {
4043
+ $themes = $this->get_themes_data_for_api();
4044
+ if ( ! empty( $themes ) ) {
4045
+ $override['themes'] = $themes;
4046
+ }
4047
+ }
4048
+
4049
  return array_merge( array(
4050
  'version' => $this->get_plugin_version(),
4051
  'is_premium' => $this->is_premium(),
4095
  } else {
4096
  $special[ $p ] = $v;
4097
 
4098
+ if ( isset( $override[ $p ] ) ||
4099
+ 'plugins' === $p ||
4100
+ 'themes' === $p
4101
+ ) {
4102
  $special_override = true;
4103
  }
4104
  }
4107
  if ( $special_override || 0 < count( $params ) ) {
4108
  // Add special params only if has at least one
4109
  // standard param, or if explicitly requested to
4110
+ // override a special param or a param which is not exist
4111
  // in the install object.
4112
  $params = array_merge( $params, $special );
4113
  }
4114
  }
4115
 
4116
  if ( 0 < count( $params ) ) {
4117
+ // Update last install sync timestamp.
4118
+ $this->_storage->install_sync_timestamp = time();
4119
+
4120
+ $params['uid'] = $this->get_anonymous_id();
4121
+
4122
  // Send updated values to FS.
4123
+ $site = $this->get_api_site_scope()->call( '/', 'put', $params );
4124
+
4125
+ if ( ! $this->is_api_error( $site ) ) {
4126
+ // I successfully sent install update, clear scheduled sync if exist.
4127
+ $this->clear_install_sync_cron();
4128
+ }
4129
+
4130
+ return $site;
4131
  }
4132
 
4133
  return false;
4166
  $this->_store_site( true );
4167
  }
4168
 
4169
+ /**
4170
+ * Track install's custom event.
4171
+ *
4172
+ * IMPORTANT:
4173
+ * Custom event tracking is currently only supported for specific clients.
4174
+ * If you are not one of them, please don't use this method. If you will,
4175
+ * the API will simply ignore your request based on the plugin ID.
4176
+ *
4177
+ * Need custom tracking for your plugin or theme?
4178
+ * If you are interested in custom event tracking please contact yo@freemius.com
4179
+ * for further details.
4180
+ *
4181
+ * @author Vova Feldman (@svovaf)
4182
+ * @since 1.2.1
4183
+ *
4184
+ * @param string $name Event name.
4185
+ * @param array $properties Associative key/value array with primitive values only
4186
+ * @param bool $process_at A valid future date-time in the following format Y-m-d H:i:s.
4187
+ * @param bool $once If true, event will be tracked only once. IMPORTANT: Still trigger the API call.
4188
+ *
4189
+ * @return object|false Event data or FALSE on failure.
4190
+ *
4191
+ * @throws \Freemius_InvalidArgumentException
4192
+ */
4193
+ public function track_event( $name, $properties = array(), $process_at = false, $once = false ) {
4194
+ $this->_logger->entrance( http_build_query( array( 'name' => $name, 'once' => $once ) ) );
4195
+
4196
+ if ( ! $this->is_registered() ) {
4197
+ return false;
4198
+ }
4199
+
4200
+ $event = array( 'type' => $name );
4201
+
4202
+ if ( is_numeric( $process_at ) && $process_at > time() ) {
4203
+ $event['process_at'] = $process_at;
4204
+ }
4205
+
4206
+ if ( $once ) {
4207
+ $event['once'] = true;
4208
+ }
4209
+
4210
+ if ( ! empty( $properties ) ) {
4211
+ // Verify associative array values are primitive.
4212
+ foreach ( $properties as $k => $v ) {
4213
+ if ( ! is_scalar( $v ) ) {
4214
+ throw new Freemius_InvalidArgumentException( 'The $properties argument must be an associative key/value array with primitive values only.' );
4215
+ }
4216
+ }
4217
+
4218
+ $event['properties'] = $properties;
4219
+ }
4220
+
4221
+ $result = $this->get_api_site_scope()->call( 'events.json', 'post', $event );
4222
+
4223
+ return $this->is_api_error( $result ) ?
4224
+ false :
4225
+ $result;
4226
+ }
4227
+
4228
+ /**
4229
+ * Track install's custom event only once, but it still triggers the API call.
4230
+ *
4231
+ * IMPORTANT:
4232
+ * Custom event tracking is currently only supported for specific clients.
4233
+ * If you are not one of them, please don't use this method. If you will,
4234
+ * the API will simply ignore your request based on the plugin ID.
4235
+ *
4236
+ * Need custom tracking for your plugin or theme?
4237
+ * If you are interested in custom event tracking please contact yo@freemius.com
4238
+ * for further details.
4239
+ *
4240
+ * @author Vova Feldman (@svovaf)
4241
+ * @since 1.2.1
4242
+ *
4243
+ * @param string $name Event name.
4244
+ * @param array $properties Associative key/value array with primitive values only
4245
+ * @param bool $process_at A valid future date-time in the following format Y-m-d H:i:s.
4246
+ *
4247
+ * @return object|false Event data or FALSE on failure.
4248
+ *
4249
+ * @throws \Freemius_InvalidArgumentException
4250
+ *
4251
+ * @user Freemius::track_event()
4252
+ */
4253
+ public function track_event_once( $name, $properties = array(), $process_at = false ) {
4254
+ return $this->track_event( $name, $properties, $process_at, true );
4255
+ }
4256
+
4257
  /**
4258
  * Plugin uninstall hook.
4259
  *
4269
  return;
4270
  }
4271
 
4272
+ $params = array();
4273
+ $uninstall_reason = null;
4274
  if ( isset( $this->_storage->uninstall_reason ) ) {
4275
+ $uninstall_reason = $this->_storage->uninstall_reason;
4276
+ $params['reason_id'] = $uninstall_reason->id;
4277
+ $params['reason_info'] = $uninstall_reason->info;
4278
  }
4279
 
4280
+ if ( ! $this->is_registered() && isset( $uninstall_reason ) ) {
4281
  // Send anonymous uninstall event only if user submitted a feedback.
4282
+ if ( isset( $uninstall_reason->is_anonymous ) && ! $uninstall_reason->is_anonymous ) {
4283
+ $this->opt_in( false, false, false, false, true );
4284
+ } else {
4285
+ $params['uid'] = $this->get_anonymous_id();
4286
+ $this->get_api_plugin_scope()->call( 'uninstall.json', 'put', $params );
4287
+ }
4288
  } else {
4289
  // Send uninstall event.
4290
  $this->send_install_update( array_merge( $params, array(
4383
  if ( ! isset( $this->_plugin_data ) ) {
4384
  self::require_plugin_essentials();
4385
 
4386
+ /**
4387
+ * @author Vova Feldman (@svovaf)
4388
+ * @since 1.2.0 When using get_plugin_data() do NOT translate plugin data.
4389
+ *
4390
+ * @link https://github.com/Freemius/wordpress-sdk/issues/77
4391
+ */
4392
+ $this->_plugin_data = get_plugin_data(
4393
+ $this->_plugin_main_file_path,
4394
+ false,
4395
+ false
4396
+ );
4397
  }
4398
 
4399
  return $this->_plugin_data;
4495
 
4496
  $this->_logger->departure( 'Version = ' . $plugin_data['Version'] );
4497
 
4498
+ return $this->apply_filters( 'plugin_version', $plugin_data['Version'] );
4499
  }
4500
 
4501
  /**
4713
  }
4714
 
4715
  /**
4716
+ * Get plugin add-ons.
4717
+ *
4718
  * @author Vova Feldman (@svovaf)
4719
  * @since 1.0.6
4720
  *
4721
+ * @since 1.1.7.3 If not yet loaded, fetch data from the API.
4722
+ *
4723
  * @return FS_Plugin[]|false
4724
  */
4725
  function get_addons() {
4726
  $this->_logger->entrance();
4727
 
4728
+ if ( ! $this->_has_addons ) {
 
 
 
 
 
 
4729
  return false;
4730
  }
4731
 
4732
+ $addons = $this->_sync_addons();
4733
+
4734
+ return ( ! is_array( $addons ) || empty( $addons ) ) ?
4735
+ false :
4736
+ $addons;
4737
  }
4738
 
4739
  /**
4816
 
4817
  if ( is_array( $addons ) ) {
4818
  foreach ( $addons as $addon ) {
4819
+ if ( $slug === $addon->slug ) {
4820
  return $addon;
4821
  }
4822
  }
4886
  return false;
4887
  }
4888
 
4889
+ return $this->_site->is_trial();
4890
+ }
4891
+
4892
+ /**
4893
+ * Check if currently in a trial with payment method (credit card or paypal).
4894
+ *
4895
+ * @author Vova Feldman (@svovaf)
4896
+ * @since 1.1.7
4897
+ *
4898
+ * @return bool
4899
+ */
4900
+ function is_paid_trial() {
4901
+ $this->_logger->entrance();
4902
+
4903
+ if ( ! $this->is_trial() ) {
4904
+ return false;
4905
+ }
4906
+
4907
+ return $this->has_active_valid_license() && ( $this->_site->trial_plan_id == $this->_license->plan_id );
4908
  }
4909
 
4910
  /**
4943
  }
4944
 
4945
  /**
4946
+ * Check if the user has an activate, non-expired license on current plugin's install.
4947
  *
4948
  * @since 1.0.9
4949
  *
4956
  return false;
4957
  }
4958
 
4959
+ if ( ! $this->has_paid_plan() ) {
4960
+ return false;
4961
+ }
4962
+
4963
  return (
4964
  ! $this->is_trial() &&
4965
  'free' !== $this->_site->plan->name &&
4966
+ $this->has_active_valid_license()
4967
  );
4968
  }
4969
 
4978
  return true;
4979
  }
4980
 
4981
+ if ( ! $this->has_paid_plan() ) {
4982
+ return true;
4983
+ }
4984
+
4985
  return (
4986
  'free' === $this->_site->plan->name ||
4987
  ! $this->has_features_enabled_license()
5002
  return ( false !== $premium_license );
5003
  }
5004
 
5005
+ /**
5006
+ * Check if user has any licenses associated with the plugin (including expired or blocking).
5007
+ *
5008
+ * @author Vova Feldman (@svovaf)
5009
+ * @since 1.1.7.3
5010
+ *
5011
+ * @return bool
5012
+ */
5013
+ private function has_any_license() {
5014
+ return is_array( $this->_licenses ) && ( 0 < count( $this->_licenses ) );
5015
+ }
5016
+
5017
  /**
5018
  * @author Vova Feldman (@svovaf)
5019
  * @since 1.0.5
5023
  function _get_available_premium_license() {
5024
  $this->_logger->entrance();
5025
 
5026
+ if ( ! $this->has_paid_plan() ) {
5027
+ return false;
5028
+ }
5029
+
5030
  if ( is_array( $this->_licenses ) ) {
5031
  foreach ( $this->_licenses as $license ) {
5032
  if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
5082
  return false;
5083
  }
5084
 
5085
+ /**
5086
+ * @author Vova Feldman (@svovaf)
5087
+ * @since 1.1.8.1
5088
+ *
5089
+ * @param string $name
5090
+ *
5091
+ * @return FS_Plugin_Plan|false
5092
+ */
5093
+ private function get_plan_by_name( $name ) {
5094
+ $this->_logger->entrance();
5095
+
5096
+ if ( ! is_array( $this->_plans ) || 0 === count( $this->_plans ) ) {
5097
+ $this->_sync_plans();
5098
+ }
5099
+
5100
+ foreach ( $this->_plans as $plan ) {
5101
+ if ( $name == $plan->name ) {
5102
+ return $plan;
5103
+ }
5104
+ }
5105
+
5106
+ return false;
5107
+ }
5108
+
5109
  /**
5110
  * Sync local plugin plans with remote server.
5111
  *
5112
  * @author Vova Feldman (@svovaf)
5113
  * @since 1.0.6
5114
  *
5115
+ * @param number|bool $site_license_id
5116
+ *
5117
  * @return FS_Plugin_License[]|object
5118
  */
5119
+ function _sync_licenses( $site_license_id = false ) {
5120
+ $licenses = $this->_fetch_licenses( false, $site_license_id );
5121
+ if ( ! $this->is_api_error( $licenses ) ) {
5122
  $this->_licenses = $licenses;
5123
  $this->_store_licenses();
5124
  }
5146
  return false;
5147
  }
5148
 
5149
+ if ( ! $this->has_any_license() ) {
5150
  $this->_sync_licenses();
5151
  }
5152
 
5348
  * @return bool
5349
  */
5350
  function has_paid_plan() {
5351
+ return $this->_has_paid_plans ||
5352
+ FS_Plan_Manager::instance()->has_paid_plan( $this->_plans );
5353
  }
5354
 
5355
  /**
5379
  * @return bool
5380
  */
5381
  function has_free_plan() {
5382
+ return ! $this->is_premium() ||
5383
+ ! $this->is_only_premium() ||
5384
+ FS_Plan_Manager::instance()->has_free_plan( $this->_plans );
5385
+ }
5386
+
5387
+ /**
5388
+ * Displays a license activation dialog box when the user clicks on the "Activate License"
5389
+ * or "Change License" link on the plugins
5390
+ * page.
5391
+ *
5392
+ * @author Leo Fajardo (@leorw)
5393
+ * @since 1.1.9
5394
+ */
5395
+ function _add_license_activation_dialog_box() {
5396
+ $vars = array(
5397
+ 'slug' => $this->_slug,
5398
+ );
5399
+
5400
+ fs_require_template( 'forms/license-activation.php', $vars );
5401
+ fs_require_template( 'forms/resend-key.php', $vars );
5402
+ }
5403
+
5404
+ /**
5405
+ * Prepare page to include all required UI and logic for the license activation dialog.
5406
+ *
5407
+ * @author Vova Feldman (@svovaf)
5408
+ * @since 1.2.0
5409
+ */
5410
+ function _require_license_activation_dialog() {
5411
+ if ( $this->is_ajax() ) {
5412
+ if ( $this->is_ajax_action( 'activate_license' ) ) {
5413
+ // Add license activation AJAX callback.
5414
+ $this->add_ajax_action( 'activate_license', array( &$this, '_activate_license_ajax_action' ) );
5415
+ }
5416
+
5417
+ if ( $this->is_ajax_action( 'resend_license_key' ) ) {
5418
+ // Add resend license AJAX callback.
5419
+ $this->add_ajax_action( 'resend_license_key', array(
5420
+ &$this,
5421
+ '_resend_license_key_ajax_action'
5422
+ ) );
5423
+ }
5424
+ } else {
5425
+ // Inject license activation dialog UI and client side code.
5426
+ add_action( 'admin_footer', array( &$this, '_add_license_activation_dialog_box' ) );
5427
+ }
5428
+ }
5429
+
5430
+ /**
5431
+ * @author Leo Fajardo (@leorw)
5432
+ * @since 1.1.9
5433
+ */
5434
+ function _activate_license_ajax_action() {
5435
+ $license_key = trim( fs_request_get( 'license_key' ) );
5436
+
5437
+ if ( empty( $license_key ) ) {
5438
+ exit;
5439
+ }
5440
+
5441
+ $slug = $_POST['slug'];
5442
+ $fs = ( ( $slug === $this->_slug ) ? $this : self::instance( $slug ) );
5443
+ $error = false;
5444
+
5445
+ if ( $this->is_registered() ) {
5446
+ $api = $fs->get_api_site_scope();
5447
+ $install = $api->call( '/', 'put',
5448
+ array(
5449
+ 'license_key' => $license_key
5450
+ )
5451
+ );
5452
+
5453
+ if ( isset( $install->error ) ) {
5454
+ $error = $install->error->message;
5455
+ }
5456
+ } else {
5457
+ $install = $this->opt_in( false, false, false, $license_key );
5458
+
5459
+ if ( isset( $install->error ) ) {
5460
+ $error = $install->error;
5461
+ }
5462
+ }
5463
+
5464
+ $result = array(
5465
+ 'success' => ( false === $error )
5466
+ );
5467
+
5468
+ if ( false !== $error ) {
5469
+ $result['error'] = $error;
5470
+ }
5471
+
5472
+ echo json_encode( $result );
5473
+
5474
+ exit;
5475
+ }
5476
+
5477
+ /**
5478
+ * @author Leo Fajardo (@leorw)
5479
+ * @since 1.2.0
5480
+ */
5481
+ function _resend_license_key_ajax_action() {
5482
+ if ( ! isset( $_POST['email'] ) ) {
5483
+ exit;
5484
+ }
5485
+
5486
+ $email_address = trim( $_POST['email'] );
5487
+ if ( empty( $email_address ) ) {
5488
+ exit;
5489
+ }
5490
+
5491
+ $error = false;
5492
+
5493
+ $api = $this->get_api_plugin_scope();
5494
+ $result = $api->call( '/licenses/resend.json', 'post',
5495
+ array(
5496
+ 'email' => $email_address,
5497
+ 'is_localhost' => WP_FS__IS_LOCALHOST
5498
+ )
5499
+ );
5500
+
5501
+ if ( is_object( $result ) && isset( $result->error ) ) {
5502
+ $error = $result->error;
5503
+
5504
+ if ( in_array( $error->code, array( 'invalid_email', 'no_user' ) ) ) {
5505
+ $error = __fs( 'email-not-found' );
5506
+ } else if ( 'no_license' === $error->code ) {
5507
+ $error = __fs( 'no-active-licenses' );
5508
+ } else {
5509
+ $error = $error->message;
5510
+ }
5511
+ }
5512
+
5513
+ $licenses = array(
5514
+ 'success' => ( false === $error )
5515
+ );
5516
+
5517
+ if ( false !== $error ) {
5518
+ $licenses['error'] = sprintf( '%s... %s', __fs( 'oops', $this->_slug ), strtolower( $error ) );
5519
+ }
5520
+
5521
+ echo json_encode( $licenses );
5522
+
5523
+ exit;
5524
  }
5525
 
5526
  #region URL Generators
5531
  * @author Vova Feldman (@svovaf)
5532
  * @since 1.0.2
5533
  *
5534
+ * @uses pricing_url()
5535
  *
5536
  * @param string $period Billing cycle
5537
+ * @param bool $is_trial
5538
  *
5539
  * @return string
5540
  */
5541
+ function get_upgrade_url( $period = WP_FS__PERIOD_ANNUALLY, $is_trial = false ) {
5542
+ return $this->pricing_url( $period, $is_trial );
5543
  }
5544
 
5545
  /**
5546
  * @author Vova Feldman (@svovaf)
5547
  * @since 1.0.9
5548
  *
5549
+ * @uses get_upgrade_url()
5550
  *
5551
  * @return string
5552
  */
5553
  function get_trial_url() {
5554
+ return $this->get_upgrade_url( WP_FS__PERIOD_ANNUALLY, true );
5555
  }
5556
 
5557
  /**
5560
  * @author Vova Feldman (@svovaf)
5561
  * @since 1.0.4
5562
  *
5563
+ * @param string $billing_cycle Billing cycle
5564
+ *
5565
+ * @param bool $is_trial
5566
  *
5567
  * @return string
5568
  */
5569
+ function pricing_url( $billing_cycle = WP_FS__PERIOD_ANNUALLY, $is_trial = false ) {
5570
  $this->_logger->entrance();
5571
 
5572
+ $params = array(
5573
+ 'billing_cycle' => $billing_cycle
5574
+ );
5575
+
5576
+ if ( $is_trial ) {
5577
+ $params['trial'] = 'true';
5578
+ }
5579
+
5580
+ return $this->_get_admin_page_url( 'pricing', $params );
5581
  }
5582
 
5583
  /**
5584
  * Checkout page URL.
5585
  *
5586
+ * @author Vova Feldman (@svovaf)
5587
+ * @since 1.0.6
5588
  *
5589
+ * @param string $billing_cycle Billing cycle
5590
+ * @param bool $is_trial
5591
+ * @param array $extra (optional) Extra parameters, override other query params.
 
5592
  *
5593
  * @return string
5594
  */
5595
  function checkout_url(
5596
+ $billing_cycle = WP_FS__PERIOD_ANNUALLY,
5597
+ $is_trial = false,
5598
+ $extra = array()
 
5599
  ) {
5600
  $this->_logger->entrance();
5601
 
5602
  $params = array(
5603
  'checkout' => 'true',
5604
+ 'billing_cycle' => $billing_cycle,
5605
  );
5606
 
5607
+ if ( $is_trial ) {
5608
+ $params['trial'] = 'true';
 
 
 
 
 
 
5609
  }
5610
 
5611
+ /**
5612
+ * Params in extra override other params.
5613
+ */
5614
+ $params = array_merge( $params, $extra );
5615
+
5616
  return $this->_get_admin_page_url( 'pricing', $params );
5617
  }
5618
 
5619
+ /**
5620
+ * Add-on checkout URL.
5621
+ *
5622
+ * @author Vova Feldman (@svovaf)
5623
+ * @since 1.1.7
5624
+ *
5625
+ * @param number $addon_id
5626
+ * @param number $pricing_id
5627
+ * @param string $billing_cycle
5628
+ * @param bool $is_trial
5629
+ *
5630
+ * @return string
5631
+ */
5632
+ function addon_checkout_url(
5633
+ $addon_id,
5634
+ $pricing_id,
5635
+ $billing_cycle = WP_FS__PERIOD_ANNUALLY,
5636
+ $is_trial = false
5637
+ ) {
5638
+ return $this->checkout_url( $billing_cycle, $is_trial, array(
5639
+ 'plugin_id' => $addon_id,
5640
+ 'pricing_id' => $pricing_id,
5641
+ ) );
5642
+ }
5643
+
5644
  #endregion
5645
 
5646
  #endregion ------------------------------------------------------------------
5651
  * @author Vova Feldman (@svovaf)
5652
  * @since 1.0.5
5653
  *
5654
+ * @since 1.1.7.3 Base logic only on the parameter provided by the developer in the init function.
5655
+ *
5656
  * @return bool
5657
  */
5658
+ function has_addons() {
5659
  $this->_logger->entrance();
5660
 
5661
+ return $this->_has_addons;
5662
  }
5663
 
5664
  /**
5665
  * Check if plugin can work in anonymous mode.
5666
  *
5667
+ * @author Vova Feldman (@svovaf)
5668
+ * @since 1.0.9
5669
  *
5670
  * @return bool
5671
+ *
5672
+ * @deprecated Please use is_enable_anonymous() instead
5673
  */
5674
  function enable_anonymous() {
5675
  return $this->_enable_anonymous;
5676
  }
5677
 
5678
+ /**
5679
+ * Check if plugin can work in anonymous mode.
5680
+ *
5681
+ * @author Vova Feldman (@svovaf)
5682
+ * @since 1.1.9
5683
+ *
5684
+ * @return bool
5685
+ */
5686
+ function is_enable_anonymous() {
5687
+ return $this->_enable_anonymous;
5688
+ }
5689
+
5690
+ /**
5691
+ * Check if plugin is premium only (no free plans).
5692
+ *
5693
+ * @author Vova Feldman (@svovaf)
5694
+ * @since 1.1.9
5695
+ *
5696
+ * @return bool
5697
+ */
5698
+ function is_only_premium() {
5699
+ return $this->_is_premium_only;
5700
+ }
5701
+
5702
  /**
5703
  * Check if feature supported with current site's plan.
5704
  *
5737
  return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
5738
  }
5739
 
5740
+ /**
5741
+ * Check if it's an AJAX call targeted for the current module.
5742
+ *
5743
+ * @author Vova Feldman (@svovaf)
5744
+ * @since 1.2.0
5745
+ *
5746
+ * @param array|string $actions Collection of AJAX actions.
5747
+ *
5748
+ * @return bool
5749
+ */
5750
+ function is_ajax_action( $actions ) {
5751
+ // Verify it's an ajax call.
5752
+ if ( ! $this->is_ajax() ) {
5753
+ return false;
5754
+ }
5755
+
5756
+ // Verify the call is relevant for the plugin.
5757
+ if ( $this->_slug !== fs_request_get( 'slug' ) ) {
5758
+ return false;
5759
+ }
5760
+
5761
+ // Verify it's one of the specified actions.
5762
+ if ( is_string( $actions ) ) {
5763
+ $actions = explode( ',', $actions );
5764
+ }
5765
+
5766
+ if ( is_array( $actions ) && 0 < count( $actions ) ) {
5767
+ $ajax_action = fs_request_get( 'action' );
5768
+
5769
+ foreach ( $actions as $action ) {
5770
+ if ( $ajax_action === $this->get_action_tag( $action ) ) {
5771
+ return true;
5772
+ }
5773
+ }
5774
+ }
5775
+
5776
+ return false;
5777
+ }
5778
+
5779
+ /**
5780
+ * @author Vova Feldman (@svovaf)
5781
+ * @since 1.1.7
5782
+ *
5783
+ * @return bool
5784
+ */
5785
+ function is_cron() {
5786
+ return ( defined( 'DOING_CRON' ) && DOING_CRON );
5787
+ }
5788
+
5789
+ /**
5790
+ * Check if a real user is visiting the admin dashboard.
5791
+ *
5792
+ * @author Vova Feldman (@svovaf)
5793
+ * @since 1.1.7
5794
+ *
5795
+ * @return bool
5796
+ */
5797
+ function is_user_in_admin() {
5798
+ return is_admin() && ! $this->is_ajax() && ! $this->is_cron();
5799
+ }
5800
+
5801
  /**
5802
  * Check if running in HTTPS and if site's plan matching the specified plan.
5803
  *
5822
  * @return string
5823
  */
5824
  function _get_admin_page_url( $page = '', $params = array() ) {
5825
+ if ( 0 < count( $params ) ) {
5826
+ foreach ( $params as $k => $v ) {
5827
+ $params[ $k ] = urlencode( $v );
5828
+ }
5829
+ }
5830
+
5831
  if ( ! $this->_menu->is_top_level() ) {
5832
  $parent_slug = $this->_menu->get_parent_slug();
5833
  $menu_file = ( false !== strpos( $parent_slug, '.php' ) ) ?
5858
  }
5859
  }
5860
 
5861
+ /**
5862
+ * Plugin's account page + sync license URL.
5863
+ *
5864
+ * @author Vova Feldman (@svovaf)
5865
+ * @since 1.1.9.1
5866
+ *
5867
+ * @param bool|number $plugin_id
5868
+ * @param bool $add_action_nonce
5869
+ *
5870
+ * @return string
5871
+ */
5872
+ function _get_sync_license_url( $plugin_id = false, $add_action_nonce = true ) {
5873
+ $params = array();
5874
+
5875
+ if ( is_numeric( $plugin_id ) ) {
5876
+ $params['plugin_id'] = $plugin_id;
5877
+ }
5878
+
5879
+ return $this->get_account_url(
5880
+ $this->_slug . '_sync_license',
5881
+ $params,
5882
+ $add_action_nonce
5883
+ );
5884
+ }
5885
 
5886
  /**
5887
  * Plugin's account URL.
5908
  $this->_get_admin_page_url( 'account', $params );
5909
  }
5910
 
5911
+ /**
5912
+ * @author Vova Feldman (@svovaf)
5913
+ * @since 1.2.0
5914
+ *
5915
+ * @param string $tab
5916
+ * @param bool $action
5917
+ * @param array $params
5918
+ * @param bool $add_action_nonce
5919
+ *
5920
+ * @return string
5921
+ *
5922
+ * @uses get_account_url()
5923
+ */
5924
+ function get_account_tab_url( $tab, $action = false, $params = array(), $add_action_nonce = true ) {
5925
+ $params['tab'] = $tab;
5926
+
5927
+ return $this->get_account_url( $action, $params, $add_action_nonce );
5928
+ }
5929
+
5930
  /**
5931
  * Plugin's account URL.
5932
  *
6221
  $this->_plans = $plans;
6222
  }
6223
 
6224
+ $this->send_install_update();
6225
 
6226
  $this->_store_account();
6227
 
6228
  }
6229
 
6230
+ /**
6231
+ * @author Vova Feldman (@svovaf)
6232
+ * @since 1.1.7.4
6233
+ *
6234
+ * @param array $override_with
6235
+ *
6236
+ * @return array
6237
+ */
6238
+ function get_opt_in_params( $override_with = array() ) {
6239
+ $this->_logger->entrance();
6240
+
6241
+ $current_user = self::_get_current_wp_user();
6242
+
6243
+ $params = array(
6244
+ 'user_firstname' => $current_user->user_firstname,
6245
+ 'user_lastname' => $current_user->user_lastname,
6246
+ 'user_nickname' => $current_user->user_nicename,
6247
+ 'user_email' => $current_user->user_email,
6248
+ 'user_ip' => WP_FS__REMOTE_ADDR,
6249
+ 'plugin_slug' => $this->_slug,
6250
+ 'plugin_id' => $this->get_id(),
6251
+ 'plugin_public_key' => $this->get_public_key(),
6252
+ 'plugin_version' => $this->get_plugin_version(),
6253
+ 'return_url' => wp_nonce_url( $this->_get_admin_page_url(
6254
+ '',
6255
+ array( 'fs_action' => $this->_slug . '_activate_new' )
6256
+ ), $this->_slug . '_activate_new' ),
6257
+ 'account_url' => wp_nonce_url( $this->_get_admin_page_url(
6258
+ 'account',
6259
+ array( 'fs_action' => 'sync_user' )
6260
+ ), 'sync_user' ),
6261
+ 'site_uid' => $this->get_anonymous_id(),
6262
+ 'site_url' => get_site_url(),
6263
+ 'site_name' => get_bloginfo( 'name' ),
6264
+ 'platform_version' => get_bloginfo( 'version' ),
6265
+ 'php_version' => phpversion(),
6266
+ 'language' => get_bloginfo( 'language' ),
6267
+ 'charset' => get_bloginfo( 'charset' ),
6268
+ );
6269
+
6270
+ if ( WP_FS__SKIP_EMAIL_ACTIVATION && $this->has_secret_key() ) {
6271
+ // Even though rand() is known for its security issues,
6272
+ // the timestamp adds another layer of protection.
6273
+ // It would be very hard for an attacker to get the secret key form here.
6274
+ // Plus, this should never run in production since the secret should never
6275
+ // be included in the production version.
6276
+ $params['ts'] = WP_FS__SCRIPT_START_TIME;
6277
+ $params['salt'] = md5( uniqid( rand() ) );
6278
+ $params['secure'] = md5(
6279
+ $params['ts'] .
6280
+ $params['salt'] .
6281
+ $this->get_secret_key()
6282
+ );
6283
+ }
6284
+
6285
+ return array_merge( $params, $override_with );
6286
+ }
6287
+
6288
+ /**
6289
+ * @author Vova Feldman (@svovaf)
6290
+ * @since 1.1.7.4
6291
+ *
6292
+ * @param string|bool $email
6293
+ * @param string|bool $first
6294
+ * @param string|bool $last
6295
+ * @param string|bool $license_key
6296
+ * @param bool $is_uninstall If "true", this means that the module is currently being uninstalled.
6297
+ * In this case, the user and site info will be sent to the server but no
6298
+ * data will be saved to the WP installation's database.
6299
+ *
6300
+ * @return bool Is successful opt-in (or set to pending).
6301
+ *
6302
+ * @use WP_Error
6303
+ */
6304
+ function opt_in(
6305
+ $email = false,
6306
+ $first = false,
6307
+ $last = false,
6308
+ $license_key = false,
6309
+ $is_uninstall = false
6310
+ ) {
6311
+ $this->_logger->entrance();
6312
+
6313
+ if ( false === $email ) {
6314
+ $current_user = self::_get_current_wp_user();
6315
+ $email = $current_user->user_email;
6316
+ }
6317
+
6318
+ /**
6319
+ * @since 1.2.1 If activating with license key, ignore the context-user
6320
+ * since the user will be automatically loaded from the license.
6321
+ */
6322
+ if (empty($license_key)) {
6323
+ if ( ! $is_uninstall ) {
6324
+ $fs_user = Freemius::_get_user_by_email( $email );
6325
+ if ( is_object( $fs_user ) && ! $this->is_pending_activation() ) {
6326
+ return $this->install_with_current_user( false );
6327
+ }
6328
+ }
6329
+ }
6330
+
6331
+ $user_info = array();
6332
+ if ( ! empty( $email ) ) {
6333
+ $user_info['user_email'] = $email;
6334
+ }
6335
+ if ( ! empty( $first ) ) {
6336
+ $user_info['user_firstname'] = $first;
6337
+ }
6338
+ if ( ! empty( $last ) ) {
6339
+ $user_info['user_lastname'] = $last;
6340
+ }
6341
+
6342
+ $params = $this->get_opt_in_params( $user_info );
6343
+
6344
+ if ( is_string( $license_key ) ) {
6345
+ $params['license_secret_key'] = $license_key;
6346
+ }
6347
+
6348
+ if ( $is_uninstall ) {
6349
+ $params['uninstall_params'] = array(
6350
+ 'reason_id' => $this->_storage->uninstall_reason->id,
6351
+ 'reason_info' => $this->_storage->uninstall_reason->info
6352
+ );
6353
+ }
6354
+
6355
+ $params['format'] = 'json';
6356
+
6357
+ $url = WP_FS__ADDRESS . '/action/service/user/install/';
6358
+ if ( isset( $_COOKIE['XDEBUG_SESSION'] ) ) {
6359
+ $url = add_query_arg( 'XDEBUG_SESSION', 'PHPSTORM', $url );
6360
+ }
6361
+
6362
+ $response = wp_remote_post( $url, array(
6363
+ 'method' => 'POST',
6364
+ 'body' => $params,
6365
+ 'timeout' => 15,
6366
+ ) );
6367
+
6368
+ if ( $response instanceof WP_Error ) {
6369
+ if ( 'https://' === substr( $url, 0, 8 ) &&
6370
+ isset( $response->errors ) &&
6371
+ isset( $response->errors['http_request_failed'] ) &&
6372
+ false !== strpos( $response->errors['http_request_failed'][0], 'sslv3 alert handshake' )
6373
+ ) {
6374
+ // Failed due to old version of cURL or Open SSL (SSLv3 is not supported by CloudFlare).
6375
+ $url = 'http://' . substr( $url, 8 );
6376
+
6377
+ $response = wp_remote_post( $url, array(
6378
+ 'method' => 'POST',
6379
+ 'body' => $params,
6380
+ 'timeout' => 15,
6381
+ ) );
6382
+ }
6383
+
6384
+ if ( $response instanceof WP_Error ) {
6385
+ return false;
6386
+ }
6387
+ }
6388
+
6389
+ if ( is_wp_error( $response ) ) {
6390
+ return false;
6391
+ }
6392
+
6393
+ // Module is being uninstalled, don't handle the returned data.
6394
+ if ( $is_uninstall ) {
6395
+ return true;
6396
+ }
6397
+
6398
+ $decoded = @json_decode( $response['body'] );
6399
+
6400
+ if ( empty( $decoded ) ) {
6401
+ return false;
6402
+ }
6403
+
6404
+ if ( isset( $decoded->error ) ) {
6405
+ return $decoded;
6406
+ } else if ( isset( $decoded->pending_activation ) && $decoded->pending_activation ) {
6407
+ // Pending activation, add message.
6408
+ $this->set_pending_confirmation( false, false );
6409
+
6410
+ return true;
6411
+ } else if ( isset( $decoded->install_secret_key ) ) {
6412
+ $this->install_with_new_user(
6413
+ $decoded->user_id,
6414
+ $decoded->user_public_key,
6415
+ $decoded->user_secret_key,
6416
+ $decoded->install_id,
6417
+ $decoded->install_public_key,
6418
+ $decoded->install_secret_key,
6419
+ false
6420
+ );
6421
+
6422
+ return true;
6423
+ }
6424
+
6425
+ return $decoded;
6426
+ }
6427
+
6428
  /**
6429
  * Set user and site identities.
6430
  *
6452
  $this->_enrich_site_trial_plan( true );
6453
  }
6454
 
6455
+ // If Freemius was OFF before, turn it on.
6456
+ $this->turn_on();
6457
+
6458
  $this->do_action( 'after_account_connection', $user, $site );
6459
 
6460
  if ( is_numeric( $site->license_id ) ) {
6461
  $this->_license = $this->_get_license_by_id( $site->license_id );
6462
  }
6463
 
6464
+ $this->_admin_notices->remove_sticky( 'connect_account' );
6465
+
6466
  if ( $this->is_pending_activation() ) {
6467
  // Remove pending activation sticky notice (if still exist).
6468
  $this->_admin_notices->remove_sticky( 'activation_pending' );
6483
  sprintf(
6484
  __fs( 'activation-with-plan-x-message', $this->_slug ),
6485
  $this->_site->plan->title
6486
+ ) . $this->get_complete_upgrade_instructions(),
 
 
 
6487
  'plan_upgraded',
6488
  __fs( 'yee-haw', $this->_slug ) . '!'
6489
  );
6499
  if ( is_numeric( $plugin_id ) ) {
6500
  if ( $plugin_id != $this->_plugin->id ) {
6501
  // Add-on was installed - sync license right after install.
6502
+ if ( $redirect && fs_redirect( $this->_get_sync_license_url( $plugin_id ) )
 
 
 
 
 
 
6503
  ) {
6504
  exit();
6505
  }
6506
 
6507
  }
6508
  } else {
6509
+ /**
6510
+ * @author Vova Feldman (@svovaf)
6511
+ * @since 1.1.9 If site installed with a valid license, sync license.
6512
+ */
6513
+ if ( $this->is_paying() ) {
6514
+ $this->_sync_plugin_license( true );
6515
+ }
6516
+
6517
  // Reload the page with the keys.
6518
  if ( $redirect && fs_redirect( $this->get_after_activation_url( 'after_connect_url' ) ) ) {
6519
  exit();
6537
  if ( fs_request_is_action( $this->_slug . '_activate_new' ) ) {
6538
  // check_admin_referer( $this->_slug . '_activate_new' );
6539
 
 
 
6540
  if ( fs_request_has( 'user_secret_key' ) ) {
6541
+ $this->install_with_new_user(
6542
+ fs_request_get( 'user_id' ),
6543
+ fs_request_get( 'user_public_key' ),
6544
+ fs_request_get( 'user_secret_key' ),
6545
+ fs_request_get( 'install_id' ),
6546
+ fs_request_get( 'install_public_key' ),
6547
+ fs_request_get( 'install_secret_key' )
6548
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
6549
  } else if ( fs_request_has( 'pending_activation' ) ) {
6550
+ $this->set_pending_confirmation( fs_request_get( 'user_email' ), true );
 
 
 
 
 
 
 
 
6551
  }
6552
  }
6553
  }
6554
 
6555
+ /**
6556
+ * Install plugin with new user.
6557
+ *
6558
+ * @author Vova Feldman (@svovaf)
6559
+ * @since 1.1.7.4
6560
+ *
6561
+ * @param number $user_id
6562
+ * @param string $user_public_key
6563
+ * @param string $user_secret_key
6564
+ * @param number $install_id
6565
+ * @param string $install_public_key
6566
+ * @param string $install_secret_key
6567
+ * @param bool $redirect
6568
+ */
6569
+ private function install_with_new_user(
6570
+ $user_id,
6571
+ $user_public_key,
6572
+ $user_secret_key,
6573
+ $install_id,
6574
+ $install_public_key,
6575
+ $install_secret_key,
6576
+ $redirect = true
6577
+ ) {
6578
+ $user = new FS_User();
6579
+ $user->id = $user_id;
6580
+ $user->public_key = $user_public_key;
6581
+ $user->secret_key = $user_secret_key;
6582
+
6583
+ $this->_user = $user;
6584
+ $user_result = $this->get_api_user_scope()->get();
6585
+ $user = new FS_User( $user_result );
6586
+ $this->_user = $user;
6587
+
6588
+ $site = new FS_Site();
6589
+ $site->id = $install_id;
6590
+ $site->public_key = $install_public_key;
6591
+ $site->secret_key = $install_secret_key;
6592
+
6593
+ $this->_site = $site;
6594
+ $site_result = $this->get_api_site_scope()->get();
6595
+ $site = new FS_Site( $site_result );
6596
+ $this->_site = $site;
6597
+
6598
+ $this->setup_account( $this->_user, $this->_site, $redirect );
6599
+ }
6600
+
6601
+ /**
6602
+ * @author Vova Feldman (@svovaf)
6603
+ * @since 1.1.7.4
6604
+ *
6605
+ * @param bool $email
6606
+ * @param bool $redirect
6607
+ */
6608
+ private function set_pending_confirmation( $email = false, $redirect = true ) {
6609
+ // Install must be activated via email since
6610
+ // user with the same email already exist.
6611
+ $this->_storage->is_pending_activation = true;
6612
+ $this->_add_pending_activation_notice( $email );
6613
+
6614
+ // Reload the page with with pending activation message.
6615
+ if ( $redirect && fs_redirect( $this->get_after_activation_url( 'after_pending_connect_url' ) ) ) {
6616
+ exit();
6617
+ }
6618
+ }
6619
+
6620
  /**
6621
  * Install plugin with current logged WP user info.
6622
  *
6633
  if ( fs_request_is_action( $this->_slug . '_activate_existing' ) && fs_request_is_post() ) {
6634
  // check_admin_referer( 'activate_existing_' . $this->_plugin->public_key );
6635
 
6636
+ $this->install_with_current_user();
6637
+ }
6638
+ }
6639
+
6640
+
6641
+ /**
6642
+ * @author Vova Feldman (@svovaf)
6643
+ * @since 1.1.7.4
6644
+ *
6645
+ * @param bool $redirect
6646
+ *
6647
+ * @return object|string
6648
+ */
6649
+ private function install_with_current_user( $redirect = true ) {
6650
+ // Get current logged WP user.
6651
+ $current_user = self::_get_current_wp_user();
6652
+
6653
+ // Find the relevant FS user by the email.
6654
+ $user = self::_get_user_by_email( $current_user->user_email );
6655
+
6656
+ // We have to set the user before getting user scope API handler.
6657
+ $this->_user = $user;
6658
+
6659
+ $extra_install_params = array(
6660
+ 'uid' => $this->get_anonymous_id(),
6661
+ );
6662
 
6663
+ /**
6664
+ * @author Vova Feldman (@svovaf)
6665
+ * @since 1.1.9 Add license key if given.
6666
+ */
6667
+ $license_key = fs_request_get( 'license_secret_key' );
6668
 
6669
+ if ( ! empty( $license_key ) ) {
6670
+ $extra_install_params['license_key'] = $license_key;
6671
+ }
6672
 
6673
+ // Install the plugin.
6674
+ $install = $this->get_api_user_scope()->call(
6675
+ "/plugins/{$this->get_id()}/installs.json",
6676
+ 'post',
6677
+ $this->get_install_data_for_api( $extra_install_params, false, false )
6678
+ );
6679
 
6680
+ if ( $this->is_api_error($install) ) {
6681
+ $this->_admin_notices->add(
6682
+ sprintf( __fs( 'could-not-activate-x', $this->_slug ), $this->get_plugin_name() ) . ' ' .
6683
+ __fs( 'contact-us-with-error-message', $this->_slug ) . ' ' . '<b>' . $install->error->message . '</b>',
6684
+ __fs( 'oops', $this->_slug ) . '...',
6685
+ 'error'
 
6686
  );
6687
 
6688
+ if ( $redirect && fs_redirect( $this->get_activation_url( array('error' => $install->error->message) ) )
6689
+ ) {
6690
+ exit();
 
 
 
 
 
 
6691
  }
6692
 
6693
+ return $install;
6694
+ }
6695
+
6696
+ $site = new FS_Site( $install );
6697
+ $this->_site = $site;
6698
  // $this->_enrich_site_plan( false );
6699
 
6700
  // $this->_set_account( $user, $site );
6701
  // $this->_sync_plans();
6702
 
6703
+ $this->setup_account( $this->_user, $this->_site, $redirect );
6704
+
6705
+ return $install;
6706
  }
6707
 
6708
  /**
6725
  'post',
6726
  $this->get_install_data_for_api( array(
6727
  'uid' => $this->get_anonymous_id(),
6728
+ ), false, false )
6729
  );
6730
 
6731
  if ( isset( $addon_install->error ) ) {
6782
  * @since 1.0.9
6783
  */
6784
  function _prepare_admin_menu() {
6785
+ // if ( ! $this->is_on() ) {
6786
+ // return;
6787
+ // }
6788
 
6789
+ if ( ! $this->has_api_connectivity() && ! $this->is_enable_anonymous() ) {
6790
  $this->_menu->remove_menu_item();
6791
  } else {
6792
+ $this->do_action( 'before_admin_menu_init' );
6793
+
6794
  $this->add_menu_action();
6795
+ $this->add_submenu_items();
6796
  }
6797
  }
6798
 
6834
  foreach ( $this->_menu_items as $priority => $items ) {
6835
  foreach ( $items as $item ) {
6836
  if ( isset( $item['url'] ) ) {
6837
+ if ( $page === strtolower( $item['menu_slug'] ) ) {
6838
  $this->_logger->log( 'Redirecting to ' . $item['url'] );
6839
 
6840
  fs_redirect( $item['url'] );
6924
  }
6925
  }
6926
 
6927
+ /**
6928
+ * @author Leo Fajardo (leorw)
6929
+ * @since 1.2.1
6930
+ *
6931
+ * return string
6932
+ */
6933
+ function get_top_level_menu_capability() {
6934
+ global $menu;
6935
+
6936
+ $top_level_menu_slug = $this->get_top_level_menu_slug();
6937
+
6938
+ foreach ( $menu as $menu_info ) {
6939
+ /**
6940
+ * The second element in the menu info array is the capability/role that has access to the menu and the
6941
+ * third element is the menu slug.
6942
+ */
6943
+ if ( $menu_info[2] === $top_level_menu_slug ) {
6944
+ return $menu_info[1];
6945
+ }
6946
+ }
6947
+
6948
+ return 'read';
6949
+ }
6950
+
6951
  /**
6952
  * @author Vova Feldman (@svovaf)
6953
  * @since 1.0.0
6969
  private function add_submenu_items() {
6970
  $this->_logger->entrance();
6971
 
 
 
6972
  if ( ! $this->is_addon() ) {
6973
+ if ( ! $this->is_activation_mode() ) {
6974
  if ( $this->is_registered() ) {
6975
  // Add user account page.
6976
  $this->add_submenu_item(
6997
  $this->_menu->is_submenu_item_visible( 'contact' )
6998
  );
6999
 
7000
+ if ( $this->has_addons() ) {
7001
  $this->add_submenu_item(
7002
  __fs( 'add-ons', $this->_slug ),
7003
  array( &$this, '_addons_page_render' ),
7056
  '<span class="fs-submenu-item">%s</span>' :
7057
  '<span class="fs-submenu-item fs-sub">%s</span>';
7058
 
7059
+ $top_level_menu_capability = $this->get_top_level_menu_capability();
7060
+
7061
  ksort( $this->_menu_items );
7062
 
7063
  foreach ( $this->_menu_items as $priority => $items ) {
7064
  foreach ( $items as $item ) {
7065
+ $capability = ( ! empty( $item['capability'] ) ? $item['capability'] : $top_level_menu_capability );
7066
+
7067
  if ( ! isset( $item['url'] ) ) {
7068
  $hook = add_submenu_page(
7069
  $item['show_submenu'] ?
7071
  null,
7072
  $item['page_title'],
7073
  sprintf( $item_template, $item['menu_title'] ),
7074
+ $capability,
7075
  $item['menu_slug'],
7076
  $item['render_function']
7077
  );
7084
  $this->get_top_level_menu_slug(),
7085
  $item['page_title'],
7086
  sprintf( $item_template, $item['menu_title'] ),
7087
+ $capability,
7088
  $item['menu_slug'],
7089
  array( $this, '' )
7090
  );
7103
  private function order_sub_submenu_items() {
7104
  global $submenu;
7105
 
7106
+ $menu_slug = $this->_menu->get_top_level_menu_slug();
7107
+
7108
+ /**
7109
+ * Before "admin_menu" fires, WordPress will loop over the default submenus and remove pages for which the user
7110
+ * does not have permissions. So in case a plugin does not have top-level menu but does have submenus under any
7111
+ * of the default menus, only users that have the right role can access its sub-submenus (Account, Contact Us,
7112
+ * Support Forum, etc.) since $submenu[ $menu_slug ] will be empty if the user doesn't have permission.
7113
+ *
7114
+ * In case a plugin does not have submenus under any of the default menus but does have submenus under the menu
7115
+ * of another plugin, only users that have the right role can access its sub-submenus since we will use the
7116
+ * capability needed to access the parent menu as the capability for the submenus that we will add.
7117
+ */
7118
+ if ( empty( $submenu[ $menu_slug ] ) ) {
7119
+ return;
7120
+ }
7121
+
7122
+ $top_level_menu = &$submenu[ $menu_slug ];
7123
 
7124
  $all_submenu_items_after = array();
7125
 
7160
  *
7161
  * function _fs_show_support_menu( $is_visible, $menu_id ) {
7162
  * if ( 'support' === $menu_id ) {
7163
+ * return _fs->is_registered();
7164
+ * }
7165
+ * return $is_visible;
7166
+ * }
7167
+ * _fs()->add_filter('is_submenu_visible', '_fs_show_support_menu', 10, 2);
7168
  *
7169
  */
7170
  function _add_default_submenu_items() {
7172
  return;
7173
  }
7174
 
7175
+ if ( ! $this->is_activation_mode() ) {
7176
  if ( $this->_menu->is_submenu_item_visible( 'support' ) ) {
7177
  $this->add_submenu_link_item(
7178
  $this->apply_filters( 'support_forum_submenu', __fs( 'support-forum', $this->_slug ) ),
7179
  $this->apply_filters( 'support_forum_url', 'https://wordpress.org/support/plugin/' . $this->_slug ),
7180
  'wp-support-forum',
7181
+ null,
7182
  50
7183
  );
7184
  }
7299
 
7300
  /* Actions / Hooks / Filters
7301
  ------------------------------------------------------------------------------------------------------------------*/
7302
+ /**
7303
+ * @author Vova Feldman (@svovaf)
7304
+ * @since 1.1.7
7305
+ *
7306
+ * @param string $tag
7307
+ *
7308
+ * @return string
7309
+ */
7310
+ public function get_action_tag( $tag ) {
7311
+ return "fs_{$tag}_{$this->_slug}";
7312
+ }
7313
+
7314
+ /**
7315
+ * @author Vova Feldman (@svovaf)
7316
+ * @since 1.2.1
7317
+ *
7318
+ * @param string $tag
7319
+ *
7320
+ * @return string
7321
+ */
7322
+ private function get_ajax_action_tag( $tag ) {
7323
+ return 'wp_ajax_' . $this->get_action_tag( $tag );
7324
+ }
7325
+
7326
  /**
7327
  * Do action, specific for the current context plugin.
7328
  *
7341
  $args = func_get_args();
7342
 
7343
  call_user_func_array( 'do_action', array_merge(
7344
+ array( $this->get_action_tag( $tag ) ),
7345
  array_slice( $args, 1 ) )
7346
  );
7347
  }
7362
  function add_action( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
7363
  $this->_logger->entrance( $tag );
7364
 
7365
+ add_action( $this->get_action_tag( $tag ), $function_to_add, $priority, $accepted_args );
7366
+ }
7367
+
7368
+ /**
7369
+ * Add AJAX action, specific for the current context plugin.
7370
+ *
7371
+ * @author Vova Feldman (@svovaf)
7372
+ * @since 1.2.1
7373
+ *
7374
+ * @param string $tag
7375
+ * @param callable $function_to_add
7376
+ * @param int $priority
7377
+ * @param int $accepted_args
7378
+ *
7379
+ * @uses add_action()
7380
+ */
7381
+ function add_ajax_action( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
7382
+ $this->_logger->entrance( $tag );
7383
+
7384
+ add_action( $this->get_ajax_action_tag( $tag ), $function_to_add, $priority, $accepted_args );
7385
  }
7386
 
7387
  /**
7401
  $this->_logger->entrance( $tag );
7402
 
7403
  $args = func_get_args();
7404
+ array_unshift( $args, $this->_slug );
7405
 
7406
+ return call_user_func_array( 'fs_apply_filter', $args );
7407
  }
7408
 
7409
  /**
7422
  function add_filter( $tag, $function_to_add, $priority = WP_FS__DEFAULT_PRIORITY, $accepted_args = 1 ) {
7423
  $this->_logger->entrance( $tag );
7424
 
7425
+ add_filter( $this->get_action_tag( $tag ), $function_to_add, $priority, $accepted_args );
7426
  }
7427
 
7428
  /**
7441
  function has_filter( $tag, $function_to_check = false ) {
7442
  $this->_logger->entrance( $tag );
7443
 
7444
+ return has_filter( $this->get_action_tag( $tag ), $function_to_check );
7445
  }
7446
 
7447
  /**
7712
  }
7713
  }
7714
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7715
  /**
7716
  * @param bool $store
7717
  *
7835
  * @uses FS_Api
7836
  *
7837
  * @param number|bool $plugin_id
7838
+ * @param number|bool $site_license_id
7839
  *
7840
  * @return FS_Plugin_License[]|object
7841
  */
7842
+ private function _fetch_licenses( $plugin_id = false, $site_license_id = false ) {
7843
  $this->_logger->entrance();
7844
 
7845
  $api = $this->get_api_user_scope();
7850
 
7851
  $result = $api->get( "/plugins/{$plugin_id}/licenses.json", true );
7852
 
7853
+ $is_site_license_synced = false;
7854
+
7855
  if ( ! isset( $result->error ) ) {
7856
  for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {
7857
  $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );
7858
+
7859
+ if ( ( ! $is_site_license_synced ) && is_numeric( $site_license_id ) ) {
7860
+ $is_site_license_synced = ( $site_license_id == $result->licenses[ $i ]->id );
7861
+ }
7862
  }
7863
 
7864
  $result = $result->licenses;
7865
  }
7866
 
7867
+ if ( ! $is_site_license_synced ) {
7868
+ $api = $this->get_api_site_scope();
7869
+
7870
+ if ( is_numeric( $site_license_id ) ) {
7871
+ // Try to retrieve a foreign license that is linked to the install.
7872
+ $api_result = $api->call( '/licenses.json' );
7873
+
7874
+ if ( ! isset( $api_result->error ) ) {
7875
+ $licenses = $api_result->licenses;
7876
+
7877
+ if ( ! empty( $licenses ) ) {
7878
+ $result[] = new FS_Plugin_License( $licenses[0] );
7879
+ }
7880
+ }
7881
+ } else if ( is_object( $this->_license ) ) {
7882
+ // Fetch foreign license by ID and license key.
7883
+ $license = $api->get( "/licenses/{$this->_license->id}.json?license_key=" .
7884
+ urlencode( $this->_license->secret_key ) );
7885
+
7886
+ if ( ! isset( $license->error ) ) {
7887
+ $result[] = new FS_Plugin_License( $license );
7888
+ }
7889
+ }
7890
+ }
7891
+
7892
+ return $result;
7893
+ }
7894
+
7895
+ /**
7896
+ * @author Vova Feldman (@svovaf)
7897
+ * @since 1.2.0
7898
+ * @uses FS_Api
7899
+ *
7900
+ * @param number|bool $plugin_id
7901
+ *
7902
+ * @return FS_Payment[]|object
7903
+ */
7904
+ function _fetch_payments( $plugin_id = false ) {
7905
+ $this->_logger->entrance();
7906
+
7907
+ $api = $this->get_api_user_scope();
7908
+
7909
+ if ( ! is_numeric( $plugin_id ) ) {
7910
+ $plugin_id = $this->_plugin->id;
7911
+ }
7912
+
7913
+ $result = $api->get( "/plugins/{$plugin_id}/payments.json", true );
7914
+
7915
+ if ( ! isset( $result->error ) ) {
7916
+ for ( $i = 0, $len = count( $result->payments ); $i < $len; $i ++ ) {
7917
+ $result->payments[ $i ] = new FS_Payment( $result->payments[ $i ] );
7918
+ }
7919
+ $result = $result->payments;
7920
+ }
7921
+
7922
  return $result;
7923
  }
7924
 
7964
  * @since 1.0.4
7965
  *
7966
  * @param bool|number $plugin_id
7967
+ * @param bool $flush Since 1.1.7.3
7968
  *
7969
  * @return object|false New plugin tag info if exist.
7970
  */
7971
+ private function _fetch_newer_version( $plugin_id = false, $flush = true ) {
7972
+ $latest_tag = $this->_fetch_latest_version( $plugin_id, $flush );
7973
 
7974
  if ( ! is_object( $latest_tag ) ) {
7975
  return false;
7992
  * @since 1.0.5
7993
  *
7994
  * @param bool|number $plugin_id
7995
+ * @param bool $flush Since 1.1.7.3
7996
  *
7997
  * @return bool|FS_Plugin_Tag
7998
  */
7999
+ function get_update( $plugin_id = false, $flush = true ) {
8000
  $this->_logger->entrance();
8001
 
8002
  if ( ! is_numeric( $plugin_id ) ) {
8003
  $plugin_id = $this->_plugin->id;
8004
  }
8005
 
8006
+ $this->_check_updates( true, $plugin_id, $flush );
8007
  $updates = $this->get_all_updates();
8008
 
8009
  return isset( $updates[ $plugin_id ] ) && is_object( $updates[ $plugin_id ] ) ? $updates[ $plugin_id ] : false;
8012
  /**
8013
  * Check if site assigned with active license.
8014
  *
8015
+ * @author Vova Feldman (@svovaf)
8016
+ * @since 1.0.6
8017
+ *
8018
+ * @deprecated Please use has_active_valid_license() instead because license can be cancelled.
8019
  */
8020
  function has_active_license() {
8021
  return (
8025
  );
8026
  }
8027
 
8028
+ /**
8029
+ * Check if site assigned with active & valid (not expired) license.
8030
+ *
8031
+ * @author Vova Feldman (@svovaf)
8032
+ * @since 1.2.1
8033
+ */
8034
+ function has_active_valid_license() {
8035
+ return (
8036
+ is_object( $this->_license ) &&
8037
+ is_numeric( $this->_license->id ) &&
8038
+ $this->_license->is_active() &&
8039
+ $this->_license->is_valid()
8040
+ );
8041
+ }
8042
+
8043
  /**
8044
  * Check if site assigned with license with enabled features.
8045
  *
8056
  );
8057
  }
8058
 
8059
+ /**
8060
+ * Check if user is a trial or have feature enabled license.
8061
+ *
8062
+ * @author Vova Feldman (@svovaf)
8063
+ * @since 1.1.7
8064
+ *
8065
+ * @return bool
8066
+ */
8067
+ function can_use_premium_code() {
8068
+ return $this->is_trial() || $this->has_features_enabled_license();
8069
+ }
8070
+
8071
  /**
8072
  * Sync site's plan.
8073
  *
8186
  private function _sync_plugin_license( $background = false ) {
8187
  $this->_logger->entrance();
8188
 
8189
+ /**
8190
+ * Sync site info.
8191
+ *
8192
+ * @todo This line will execute install sync on a daily basis, even if running the free version (for opted-in users). The reason we want to keep it that way is for cases when the user was a paying customer, then there was a failure in subscription payment, and then after some time the payment was successful. This could be heavily optimized. For example, we can skip the $flush if the current install was never associated with a paid version.
8193
+ */
8194
  $site = $this->send_install_update( array(), true );
8195
 
8196
  $plan_change = 'none';
8231
  );
8232
  }
8233
  }
 
 
 
8234
 
8235
+ // No reason to continue with license sync while there are API issues.
8236
+ return;
8237
+ }
8238
+
8239
+ // Remove sticky API connectivity message.
8240
+ self::$_global_admin_notices->remove_sticky( 'api_blocked' );
8241
 
8242
+ $site = new FS_Site( $site );
 
8243
 
8244
+ // Sync plans.
8245
+ $this->_sync_plans();
8246
+
8247
+ if ( ! $this->has_paid_plan() ) {
8248
+ $this->_site = $site;
8249
+ $this->_enrich_site_plan( true );
8250
+ $this->_store_site();
8251
+ } else {
8252
+ /**
8253
+ * Sync licenses. Pass the site's license ID so that the foreign licenses will be fetched if the license
8254
+ * associated with that ID is not included in the user's licenses collection.
8255
+ */
8256
+ $this->_sync_licenses( $site->license_id );
8257
 
8258
  // Check if plan / license changed.
8259
  if ( ! FS_Entity::equals( $site->plan, $this->_site->plan ) ||
8263
  // Check if license changed.
8264
  $site->license_id != $this->_site->license_id
8265
  ) {
8266
+ if ( $site->is_trial() && ( ! $this->_site->is_trial() || $site->trial_ends != $this->_site->trial_ends ) ) {
8267
  // New trial started.
8268
  $this->_site = $site;
8269
  $plan_change = 'trial_started';
8271
  // Store trial plan information.
8272
  $this->_enrich_site_trial_plan( true );
8273
 
8274
+ // For trial with subscription use-case.
8275
+ $new_license = is_null( $site->license_id ) ? null : $this->_get_license_by_id( $site->license_id );
8276
+
8277
+ if ( is_object( $new_license ) && $new_license->is_valid() ) {
8278
+ $this->_site = $site;
8279
+ $this->_update_site_license( $new_license );
8280
+ $this->_store_licenses();
8281
+ $this->_enrich_site_plan( true );
8282
+
8283
+ $this->_sync_site_subscription( $this->_license );
8284
+ }
8285
  } else if ( $this->_site->is_trial() && ! $site->is_trial() && ! is_numeric( $site->license_id ) ) {
8286
  // Was in trial, but now trial expired and no license ID.
8287
  // New trial started.
8295
  $is_free = $this->is_free_plan();
8296
 
8297
  // Make sure license exist and not expired.
8298
+ $new_license = is_null( $site->license_id ) ?
8299
+ null :
8300
+ $this->_get_license_by_id( $site->license_id );
8301
+
8302
+ if ( $is_free && is_null( $new_license ) && $this->has_any_license() && $this->_license->is_cancelled ) {
8303
+ // License cancelled.
8304
+ $this->_site = $site;
8305
+ $this->_update_site_license( $new_license );
8306
+ $this->_store_licenses();
8307
+ $this->_enrich_site_plan( true );
8308
 
8309
+ $plan_change = 'cancelled';
8310
+ } else if ( $is_free && ( ( ! is_object( $new_license ) || $new_license->is_expired() ) ) ) {
8311
  // The license is expired, so ignore upgrade method.
8312
  } else {
8313
  // License changed.
8342
  }
8343
  }
8344
 
8345
+ if ( $this->has_paid_plan() ) {
8346
+ switch ( $plan_change ) {
8347
+ case 'none':
8348
+ if ( ! $background && is_admin() ) {
8349
+ $plan = $this->is_trial() ?
8350
+ $this->_storage->trial_plan :
8351
+ $this->_site->plan;
8352
+
8353
+ $this->_admin_notices->add(
8354
  sprintf(
8355
+ __fs( 'plan-did-not-change-message', $this->_slug ),
8356
+ '<i><b>' . $plan->title . ( $this->is_trial() ? ' ' . __fs( 'trial', $this->_slug ) : '' ) . '</b></i>'
8357
+ ) . ' ' . sprintf(
8358
  '<a href="%s">%s</a>',
8359
  $this->contact_url(
8360
  'bug',
8361
  sprintf( __fs( 'plan-did-not-change-email-message', $this->_slug ),
8362
+ strtoupper( $plan->name )
8363
  )
8364
  ),
8365
  __fs( 'contact-us-here', $this->_slug )
8366
+ ),
8367
+ __fs( 'hmm', $this->_slug ) . '...'
8368
+ );
8369
+ }
8370
+ break;
8371
+ case 'upgraded':
8372
+ $this->_admin_notices->add_sticky(
8373
+ sprintf(
8374
+ __fs( 'plan-upgraded-message', $this->_slug ),
8375
+ '<i>' . $this->get_plugin_name() . '</i>'
8376
+ ) . $this->get_complete_upgrade_instructions(),
8377
+ 'plan_upgraded',
8378
+ __fs( 'yee-haw', $this->_slug ) . '!'
8379
+ );
8380
+
8381
+ $this->_admin_notices->remove_sticky( array(
8382
+ 'trial_started',
8383
+ 'trial_promotion',
8384
+ 'trial_expired',
8385
+ 'activation_complete',
8386
+ ) );
8387
+ break;
8388
+ case 'changed':
8389
+ $this->_admin_notices->add_sticky(
8390
+ sprintf(
8391
+ __fs( 'plan-changed-to-x-message', $this->_slug ),
8392
+ $this->_site->plan->title
8393
+ ),
8394
+ 'plan_changed'
8395
+ );
8396
+
8397
+ $this->_admin_notices->remove_sticky( array(
8398
+ 'trial_started',
8399
+ 'trial_promotion',
8400
+ 'trial_expired',
8401
+ 'activation_complete',
8402
+ ) );
8403
+ break;
8404
+ case 'downgraded':
8405
+ $this->_admin_notices->add_sticky(
8406
+ sprintf( __fs( 'license-expired-blocking-message', $this->_slug ) ),
8407
+ 'license_expired',
8408
+ __fs( 'hmm', $this->_slug ) . '...'
8409
+ );
8410
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
8411
+ break;
8412
+ case 'cancelled':
8413
+ $this->_admin_notices->add(
8414
+ __fs( 'license-cancelled', $this->_slug ) . ' ' .
8415
+ sprintf(
8416
+ '<a href="%s">%s</a>',
8417
+ $this->contact_url( 'bug' ),
8418
+ __fs( 'contact-us-here', $this->_slug )
8419
  ),
8420
  __fs( 'hmm', $this->_slug ) . '...',
8421
  'error'
8422
  );
8423
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
8424
+ break;
8425
+ case 'expired':
8426
+ $this->_admin_notices->add_sticky(
8427
+ sprintf( __fs( 'license-expired-non-blocking-message', $this->_slug ), $this->_site->plan->title ),
8428
+ 'license_expired',
8429
+ __fs( 'hmm', $this->_slug ) . '...'
8430
+ );
8431
+ $this->_admin_notices->remove_sticky( 'plan_upgraded' );
8432
+ break;
8433
+ case 'trial_started':
8434
+ $this->_admin_notices->add_sticky(
8435
+ sprintf(
8436
+ __fs( 'trial-started-message', $this->_slug ),
8437
+ '<i>' . $this->get_plugin_name() . '</i>'
8438
+ ) . $this->get_complete_upgrade_instructions( $this->_storage->trial_plan->title ),
8439
+ 'trial_started',
8440
+ __fs( 'yee-haw', $this->_slug ) . '!'
8441
+ );
8442
+
8443
+ $this->_admin_notices->remove_sticky( array(
8444
+ 'trial_promotion',
8445
+ ) );
8446
+ break;
8447
+ case 'trial_expired':
8448
+ $this->_admin_notices->add_sticky(
8449
+ __fs( 'trial-expired-message', $this->_slug ),
8450
+ 'trial_expired',
8451
+ __fs( 'hmm', $this->_slug ) . '...'
8452
+ );
8453
+ $this->_admin_notices->remove_sticky( array(
8454
+ 'trial_started',
8455
+ 'trial_promotion',
8456
+ 'plan_upgraded',
8457
+ ) );
8458
+ break;
8459
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8460
  }
8461
 
8462
  if ( 'none' !== $plan_change ) {
8473
  protected function _activate_license( $background = false ) {
8474
  $this->_logger->entrance();
8475
 
8476
+ $license_id = fs_request_get( 'license_id' );
8477
+
8478
+ if ( FS_Plugin_License::is_valid_id( $license_id ) && $license_id == $this->_site->license_id ) {
8479
+ // License is already activated.
8480
+ return;
8481
+ }
8482
+
8483
+ $premium_license = FS_Plugin_License::is_valid_id( $license_id ) ?
8484
+ $this->_get_license_by_id( $license_id ) :
8485
+ $this->_get_available_premium_license();
8486
 
8487
  if ( ! is_object( $premium_license ) ) {
8488
  return;
8489
  }
8490
 
8491
+ /**
8492
+ * If the premium license is already associated with the install, just
8493
+ * update the license reference (activation is not required).
8494
+ *
8495
+ * @since 1.1.9
8496
+ */
8497
+ if ( $premium_license->id == $this->_site->license_id ) {
8498
+ // License is already activated.
8499
+ $this->_update_site_license( $premium_license );
8500
+ $this->_enrich_site_plan( false );
8501
+ $this->_store_account();
8502
+
8503
+ return;
8504
+ }
8505
+
8506
+ if ( $this->_site->user_id != $premium_license->user_id ) {
8507
+ $api_request_params = array( 'license_key' => $premium_license->secret_key );
8508
+ } else {
8509
+ $api_request_params = array();
8510
+ }
8511
+
8512
  $api = $this->get_api_site_scope();
8513
+ $license = $api->call( "/licenses/{$premium_license->id}.json", 'put', $api_request_params );
8514
 
8515
+ if ( $this->is_api_error( $license ) ) {
8516
  if ( ! $background ) {
8517
+ $this->_admin_notices->add( sprintf(
8518
+ '%s %s',
8519
+ __fs( 'license-activation-failed-message', $this->_slug ),
8520
+ ( is_object( $license ) && isset( $license->error ) ?
8521
+ $license->error->message :
8522
+ sprintf( '%s<br><code>%s</code>',
8523
+ __fs( 'server-error-message', $this->_slug ),
8524
+ var_export( $license, true )
8525
+ )
8526
+ )
8527
+ ),
8528
  __fs( 'hmm', $this->_slug ) . '...',
8529
  'error'
8530
  );
8536
  $premium_license = new FS_Plugin_License( $license );
8537
 
8538
  // Updated site plan.
8539
+ $site = $this->get_api_site_scope()->get( '/', true );
8540
+ if ( ! $this->is_api_error( $site ) ) {
8541
+ $this->_site = new FS_Site( $site );
8542
+ }
8543
  $this->_update_site_license( $premium_license );
8544
  $this->_enrich_site_plan( false );
8545
 
8548
  if ( ! $background ) {
8549
  $this->_admin_notices->add_sticky(
8550
  __fs( 'license-activated-message', $this->_slug ) .
8551
+ $this->get_complete_upgrade_instructions(),
 
 
 
8552
  'license_activated',
8553
  __fs( 'yee-haw', $this->_slug ) . '!'
8554
  );
8676
  }
8677
  }
8678
 
8679
+ /**
8680
+ * @author Vova Feldman (@svovaf)
8681
+ * @since 1.1.8.1
8682
+ *
8683
+ * @param bool|string $plan_name
8684
+ *
8685
+ * @return bool If trial was successfully started.
8686
+ */
8687
+ function start_trial( $plan_name = false ) {
8688
+ $this->_logger->entrance();
8689
+
8690
+ if ( $this->is_trial() ) {
8691
+ // Already in trial mode.
8692
+ $this->_admin_notices->add(
8693
+ __fs( 'in-trial-mode', $this->_slug ),
8694
+ __fs( 'oops', $this->_slug ) . '...',
8695
+ 'error'
8696
+ );
8697
+
8698
+ return false;
8699
+ }
8700
+
8701
+ if ( $this->_site->is_trial_utilized() ) {
8702
+ // Trial was already utilized.
8703
+ $this->_admin_notices->add(
8704
+ __fs( 'trial-utilized', $this->_slug ),
8705
+ __fs( 'oops', $this->_slug ) . '...',
8706
+ 'error'
8707
+ );
8708
+
8709
+ return false;
8710
+ }
8711
+
8712
+ if ( false !== $plan_name ) {
8713
+ $plan = $this->get_plan_by_name( $plan_name );
8714
+
8715
+ if ( false === $plan ) {
8716
+ // Plan doesn't exist.
8717
+ $this->_admin_notices->add(
8718
+ sprintf( __fs( 'trial-plan-x-not-exist', $this->_slug ), $plan_name ),
8719
+ __fs( 'oops', $this->_slug ) . '...',
8720
+ 'error'
8721
+ );
8722
+
8723
+ return false;
8724
+ }
8725
+
8726
+ if ( ! $plan->has_trial() ) {
8727
+ // Plan doesn't exist.
8728
+ $this->_admin_notices->add(
8729
+ sprintf( __fs( 'plan-x-no-trial', $this->_slug ), $plan_name ),
8730
+ __fs( 'oops', $this->_slug ) . '...',
8731
+ 'error'
8732
+ );
8733
+
8734
+ return false;
8735
+ }
8736
+ } else {
8737
+ if ( ! $this->has_trial_plan() ) {
8738
+ // None of the plans have a trial.
8739
+ $this->_admin_notices->add(
8740
+ __fs( 'no-trials', $this->_slug ),
8741
+ __fs( 'oops', $this->_slug ) . '...',
8742
+ 'error'
8743
+ );
8744
+
8745
+ return false;
8746
+ }
8747
+
8748
+ $plans_with_trial = FS_Plan_Manager::instance()->get_trial_plans( $this->_plans );
8749
+
8750
+ $plan = $plans_with_trial[0];
8751
+ }
8752
+
8753
+ $api = $this->get_api_site_scope();
8754
+ $plan = $api->call( "plans/{$plan->id}/trials.json", 'post' );
8755
+
8756
+ if ( $this->is_api_error( $plan ) ) {
8757
+ // Some API error while trying to start the trial.
8758
+ $this->_admin_notices->add(
8759
+ __fs( 'unexpected-api-error', $this->_slug ) . ' ' . var_export( $plan, true ),
8760
+ __fs( 'oops', $this->_slug ) . '...',
8761
+ 'error'
8762
+ );
8763
+
8764
+ return false;
8765
+ }
8766
+
8767
+ // Sync license.
8768
+ $this->_sync_license();
8769
+
8770
+ return $this->is_trial();
8771
+ }
8772
+
8773
  /**
8774
  * Cancel site trial.
8775
  *
8796
 
8797
  $trial_cancelled = false;
8798
 
8799
+ if ( ! $this->is_api_error( $site ) ) {
8800
  $prev_trial_ends = $this->_site->trial_ends;
8801
 
8802
+ if ( $this->is_paid_trial() ) {
8803
+ $this->_license->expiration = $site->trial_ends;
8804
+ $this->_license->is_cancelled = true;
8805
+ $this->_update_site_license( $this->_license );
8806
+ $this->_store_licenses();
8807
+
8808
+ // Clear subscription reference.
8809
+ $this->_sync_site_subscription( null );
8810
+ }
8811
+
8812
+ // Update site info.
8813
+ $this->_site = new FS_Site( $site );
8814
+ $this->_enrich_site_plan();
8815
 
8816
  $trial_cancelled = ( $prev_trial_ends != $site->trial_ends );
8817
  } else {
8820
  }
8821
 
8822
  if ( $trial_cancelled ) {
8823
+ // Remove previous sticky messages about upgrade or trial (if exist).
 
 
 
 
 
 
8824
  $this->_admin_notices->remove_sticky( array(
8825
  'trial_started',
8826
  'trial_promotion',
8832
 
8833
  // Clear trial plan information.
8834
  unset( $this->_storage->trial_plan );
8835
+
8836
+ if ( ! $this->is_addon() ||
8837
+ ! $this->deactivate_premium_only_addon_without_license( true )
8838
+ ) {
8839
+ $this->_admin_notices->add(
8840
+ sprintf( __fs( 'trial-cancel-message', $this->_slug ), $this->_storage->trial_plan->title )
8841
+ );
8842
+ }
8843
  } else {
8844
  $this->_admin_notices->add(
8845
  __fs( 'trial-cancel-failure-message', $this->_slug ),
8870
  * @return bool
8871
  */
8872
  private function _can_download_premium() {
8873
+ return $this->has_active_valid_license() ||
8874
  ( $this->is_trial() && ! $this->get_trial_plan()->is_free() );
8875
  }
8876
 
8907
  * @since 1.0.4
8908
  *
8909
  * @param bool|number $addon_id
8910
+ * @param bool $flush Since 1.1.7.3
8911
  *
8912
  * @return object|false Plugin latest tag info.
8913
  */
8914
+ function _fetch_latest_version( $addon_id = false, $flush = true ) {
8915
+ $this->_logger->entrance();
8916
+
8917
+ /**
8918
+ * @since 1.1.7.3 Check for plugin updates from Freemius only if opted-in.
8919
+ * @since 1.1.7.4 Also check updates for add-ons.
8920
+ */
8921
+ if ( ! $this->is_registered() &&
8922
+ ! $this->_is_addon_id( $addon_id )
8923
+ ) {
8924
+ return false;
8925
+ }
8926
+
8927
+ $tag = $this->get_api_site_or_plugin_scope()->get(
8928
  $this->_get_latest_version_endpoint( $addon_id, 'json' ),
8929
+ $flush
8930
  );
8931
+
8932
  $latest_version = ( is_object( $tag ) && isset( $tag->version ) ) ? $tag->version : 'couldn\'t get';
8933
+
8934
  $this->_logger->departure( 'Latest version ' . $latest_version );
8935
 
8936
  return ( is_object( $tag ) && isset( $tag->version ) ) ? $tag : false;
8938
 
8939
  #region Download Plugin ------------------------------------------------------------------
8940
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8941
  /**
8942
  * Download latest plugin version, based on plan.
8943
  *
8977
  );
8978
  }
8979
 
8980
+ /**
8981
+ * Get payment invoice URL.
8982
+ *
8983
+ * @author Vova Feldman (@svovaf)
8984
+ * @since 1.2.0
8985
+ *
8986
+ * @param bool|number $payment_id
8987
+ *
8988
+ * @return string
8989
+ */
8990
+ function _get_invoice_api_url( $payment_id = false ) {
8991
+ $this->_logger->entrance();
8992
+
8993
+ return $this->get_api_user_scope()->get_signed_url(
8994
+ "/payments/{$payment_id}/invoice.pdf"
8995
+ );
8996
+ }
8997
+
8998
  /**
8999
  * Get latest plugin download link.
9000
  *
9046
  * @param bool $background Hints the method if it's a background updates check. If false, it means that
9047
  * was initiated by the admin.
9048
  * @param bool|number $plugin_id
9049
+ * @param bool $flush Since 1.1.7.3
9050
  */
9051
+ private function _check_updates( $background = false, $plugin_id = false, $flush = true ) {
9052
  $this->_logger->entrance();
9053
 
9054
  // Check if there's a newer version for download.
9055
+ $new_version = $this->_fetch_newer_version( $plugin_id, $flush );
9056
 
9057
  $update = null;
9058
  if ( is_object( $new_version ) ) {
9086
  * @author Vova Feldman (@svovaf)
9087
  * @since 1.0.4
9088
  *
9089
+ * @param bool $flush Since 1.1.7.3 add 24 hour cache by default.
9090
  *
9091
+ * @return FS_Plugin[]
9092
+ *
9093
+ * @uses FS_Api
9094
  */
9095
+ private function _sync_addons( $flush = false ) {
9096
  $this->_logger->entrance();
9097
 
9098
+ $api = $this->get_api_site_or_plugin_scope();
9099
 
9100
+ /**
9101
+ * @since 1.2.1
9102
+ *
9103
+ * If there's a cached version of the add-ons and not asking
9104
+ * for a flush, just use the currently stored add-ons.
9105
+ */
9106
+ if ( ! $flush && $api->is_cached( '/addons.json?enriched=true' ) ) {
9107
+ $addons = self::get_all_addons();
9108
+
9109
+ return $addons[ $this->_plugin->id ];
9110
  }
9111
 
9112
+ $result = $api->get( '/addons.json?enriched=true', $flush );
9113
+
9114
  $addons = array();
9115
+ if ( ! $this->is_api_error( $result ) ) {
9116
+ for ( $i = 0, $len = count( $result->plugins ); $i < $len; $i ++ ) {
9117
+ $addons[ $i ] = new FS_Plugin( $result->plugins[ $i ] );
9118
+ }
9119
+
9120
+ $this->_store_addons( $addons, true );
9121
  }
9122
 
9123
+ return $addons;
9124
  }
9125
 
9126
  /**
9303
  * @author Vova Feldman (@svovaf)
9304
  * @since 1.1.2
9305
  *
9306
+ * @param array $params
9307
+ *
9308
  * @return string
9309
  */
9310
+ private function get_activation_url( $params = array() ) {
9311
+ return $this->apply_filters( 'connect_url', $this->_get_admin_page_url( '', $params ) );
9312
  }
9313
 
9314
  /**
9315
+ * Get the URL of the page that should be loaded after the user connect or skip in the opt-in screen.
9316
+ *
9317
  * @author Vova Feldman (@svovaf)
9318
  * @since 1.1.3
9319
  *
9495
  #region Actions that might be called from external links (e.g. email)
9496
 
9497
  case 'cancel_trial':
9498
+ if ( $plugin_id == $this->get_id() ) {
9499
+ $this->_cancel_trial();
9500
+ } else {
9501
+ if ( $this->is_addon_activated( $plugin_id ) ) {
9502
+ $fs_addon = self::get_instance_by_id( $plugin_id );
9503
+ $fs_addon->_cancel_trial();
9504
+ }
9505
+ }
9506
 
9507
  return;
9508
 
9569
 
9570
  fs_enqueue_local_style( 'fs_account', '/admin/account.css' );
9571
 
9572
+ if ( $this->has_addons() ) {
9573
  wp_enqueue_script( 'plugin-install' );
9574
  add_thickbox();
9575
 
9582
  add_filter( 'admin_body_class', 'fs_addons_body_class' );
9583
  }
9584
 
9585
+ if ( $this->has_paid_plan() &&
9586
+ ! $this->has_any_license() &&
9587
+ ! $this->is_sync_executed()
9588
+ ) {
9589
+ /**
9590
+ * If no licenses found and no sync job was executed during the last 24 hours,
9591
+ * just execute the sync job right away (blocking execution).
9592
+ *
9593
+ * @since 1.1.7.3
9594
+ */
9595
+ $this->run_manual_sync();
9596
+ }
9597
+
9598
  $this->_handle_account_edits();
9599
 
9600
  $this->do_action( 'account_page_load_before_departure' );
9610
  $this->_logger->entrance();
9611
 
9612
  $vars = array( 'slug' => $this->_slug );
9613
+ if ( 'billing' === fs_request_get( 'tab' ) ) {
9614
+ fs_require_once_template( 'billing.php', $vars );
9615
+ } else {
9616
+ fs_require_once_template( 'account.php', $vars );
9617
+ }
9618
  }
9619
 
9620
  /**
9953
  private $_action_links_hooked = false;
9954
  private $_action_links = array();
9955
 
 
 
 
 
 
 
 
 
 
 
 
 
9956
  /**
9957
  * Hook to plugin action links filter.
9958
  *
10023
  __fs( 'upgrade', $this->_slug ),
10024
  $this->get_upgrade_url(),
10025
  false,
10026
+ 7,
10027
  'upgrade'
10028
  );
10029
  }
10030
 
10031
+ if ( $this->has_addons() ) {
10032
  $this->add_plugin_action_link(
10033
  __fs( 'add-ons', $this->_slug ),
10034
  $this->_get_admin_page_url( 'addons' ),
10035
  false,
10036
+ 9,
10037
  'addons'
10038
  );
10039
  }
10041
  }
10042
 
10043
  /**
10044
+ * Adds "Activate License" or "Change License" link to the main Plugins page link actions collection.
10045
+ *
10046
+ * @author Leo Fajardo (@leorw)
10047
+ * @since 1.1.9
10048
+ */
10049
+ function _add_license_action_link() {
10050
+ $this->_logger->entrance();
10051
+
10052
+ if ( $this->is_free_plan() && $this->is_addon() ) {
10053
+ return;
10054
+ }
10055
+
10056
+ $link_text = __fs(
10057
+ $this->is_free_plan() ? 'activate-license' : 'change-license',
10058
+ $this->_slug
10059
+ );
10060
+
10061
+ $this->add_plugin_action_link(
10062
+ $link_text,
10063
+ '#',
10064
+ false,
10065
+ 11,
10066
+ ( 'activate-license ' . $this->_slug )
10067
+ );
10068
+ }
10069
+
10070
+ /**
10071
+ * Get the URL of the page that should be loaded right after the plugin activation.
10072
  *
10073
  * @author Vova Feldman (@svovaf)
10074
+ * @since 1.1.7.4
10075
+ *
10076
+ * @return string
10077
  */
10078
+ function get_after_plugin_activation_redirect_url() {
10079
  $url = false;
10080
  $plugin_fs = false;
10081
 
10103
  }
10104
  }
10105
 
10106
+ return $url;
10107
+ }
10108
+
10109
+ /**
10110
+ * Forward page to activation page.
10111
+ *
10112
+ * @author Vova Feldman (@svovaf)
10113
+ * @since 1.0.3
10114
+ */
10115
+ function _redirect_on_activation_hook() {
10116
+ $url = $this->get_after_plugin_activation_redirect_url();
10117
+
10118
  if ( is_string( $url ) ) {
10119
  fs_redirect( $url );
10120
  exit();
10135
  function _modify_plugin_action_links_hook( $links, $file ) {
10136
  $this->_logger->entrance();
10137
 
10138
+ $passed_deactivate = false;
10139
+ $deactivate_link = '';
10140
+ $before_deactivate = array();
10141
+ $after_deactivate = array();
10142
+ foreach ( $links as $key => $link ) {
10143
+ if ( 'deactivate' === $key ) {
10144
+ $deactivate_link = $link;
10145
+ $passed_deactivate = true;
10146
+ continue;
10147
+ }
10148
+
10149
+ if ( ! $passed_deactivate ) {
10150
+ $before_deactivate[ $key ] = $link;
10151
+ } else {
10152
+ $after_deactivate[ $key ] = $link;
10153
+ }
10154
+ }
10155
+
10156
  ksort( $this->_action_links );
10157
 
10158
  foreach ( $this->_action_links as $new_links ) {
10159
  foreach ( $new_links as $link ) {
10160
+ $before_deactivate[ $link['key'] ] = '<a href="' . $link['href'] . '"' . ( $link['external'] ? ' target="_blank"' : '' ) . '>' . $link['label'] . '</a>';
10161
  }
10162
  }
10163
 
10164
+ if ( ! empty( $deactivate_link ) ) {
10165
+ if ( ! $this->is_paying_or_trial() || $this->is_premium() ) {
10166
+ /*
10167
+ * This HTML element is used to identify the correct plugin when attaching an event to its Deactivate link.
10168
+ *
10169
+ * If user is paying or in trial and have the free version installed,
10170
+ * assume that the deactivation is for the upgrade process, so this is not needed.
10171
+ */
10172
+ $deactivate_link .= '<i class="fs-slug" data-slug="' . $this->_slug . '"></i>';
10173
  }
10174
+
10175
+ // Append deactivation link.
10176
+ $before_deactivate['deactivate'] = $deactivate_link;
10177
  }
10178
 
10179
+ return array_merge( $before_deactivate, $after_deactivate );
10180
  }
10181
 
10182
  /**
10208
  $this->_admin_notices->add_sticky( $message, $id, $title, $type );
10209
  }
10210
 
10211
+ /**
10212
+ * Helper function that returns the final steps for the upgrade completion.
10213
+ *
10214
+ * If the module is already running the premium code, returns an empty string.
10215
+ *
10216
+ * @author Vova Feldman (@svovaf)
10217
+ * @since 1.2.1
10218
+ *
10219
+ * @param string $plan_title
10220
+ *
10221
+ * @return string
10222
+ */
10223
+ private function get_complete_upgrade_instructions( $plan_title = '' ) {
10224
+ if ( $this->is_premium() ) {
10225
+ return '';
10226
+ }
10227
+
10228
+ if ( empty( $plan_title ) ) {
10229
+ $plan_title = $this->_site->plan->title;
10230
+ }
10231
+
10232
+ return sprintf(
10233
+ ' %s: <ol><li>%s.</li><li>%s.</li><li>%s (<a href="%s" target="_blank">%s</a>).</li></ol>',
10234
+ __fs( 'follow-steps-to-complete-upgrade', $this->_slug ),
10235
+ $this->_get_latest_download_link( sprintf(
10236
+ __fs( 'download-latest-x-version', $this->_slug ),
10237
+ $plan_title
10238
+ ) ),
10239
+ __fs( 'deactivate-free-version', $this->_slug ),
10240
+ __fs( 'upload-and-activate', $this->_slug ),
10241
+ '//bit.ly/upload-wp-plugin',
10242
+ __fs( 'howto-upload-activate', $this->_slug )
10243
+ );
10244
+ }
10245
+
10246
  /* Plugin Auto-Updates (@since 1.0.4)
10247
  ------------------------------------------------------------------------------------------------------------------*/
10248
  /**
freemius/includes/class-fs-api.php CHANGED
@@ -154,7 +154,7 @@
154
  * @return array|mixed|string|void
155
  */
156
  private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
157
- $this->_logger->entrance();
158
 
159
  if ( self::is_temporary_down() ) {
160
  $result = $this->get_temporary_unavailable_error();
@@ -221,7 +221,7 @@
221
  * @return stdClass|mixed
222
  */
223
  function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
224
- $this->_logger->entrance();
225
 
226
  $cache_key = $this->get_cache_key( $path );
227
 
@@ -258,11 +258,38 @@
258
  return $cached_result;
259
  }
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  private function get_cache_key( $path, $method = 'GET', $params = array() ) {
262
  $canonized = $this->_api->CanonizePath( $path );
263
  // $exploded = explode('/', $canonized);
264
  // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
265
- return $method . ':' . $canonized . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
266
  }
267
 
268
  /**
@@ -336,7 +363,7 @@
336
  return (object) array(
337
  'error' => array(
338
  'type' => 'TemporaryUnavailable',
339
- 'message' => 'API is temporary unavailable.',
340
  'code' => 'temporary_unavailable',
341
  'http' => 503
342
  )
@@ -346,15 +373,15 @@
346
  /**
347
  * Ping API for connectivity test, and return result object.
348
  *
349
- * @author Vova Feldman (@svovaf)
350
- * @since 1.0.9
351
  *
352
  * @param null|string $unique_anonymous_id
353
- * @param bool $is_update False if new plugin installation.
354
  *
355
  * @return object
356
  */
357
- function ping( $unique_anonymous_id = null, $is_update = false ) {
358
  $this->_logger->entrance();
359
 
360
  if ( self::is_temporary_down() ) {
@@ -363,9 +390,9 @@
363
 
364
  $pong = is_null( $unique_anonymous_id ) ?
365
  Freemius_Api::Ping() :
366
- $this->_call( 'ping.json?' . http_build_query( array(
367
- 'uid' => $unique_anonymous_id,
368
- 'is_update' => $is_update,
369
  ) ) );
370
 
371
  if ( $this->is_valid_ping( $pong ) ) {
@@ -380,9 +407,9 @@
380
 
381
  $pong = is_null( $unique_anonymous_id ) ?
382
  Freemius_Api::Ping() :
383
- $this->_call( 'ping.json?' . http_build_query( array(
384
- 'uid' => $unique_anonymous_id,
385
- 'is_update' => $is_update,
386
  ) ) );
387
 
388
  if ( ! $this->is_valid_ping( $pong ) ) {
@@ -404,7 +431,7 @@
404
  *
405
  * @return bool
406
  */
407
- private static function should_try_with_http($result) {
408
  if ( ! Freemius_Api::IsHttps() ) {
409
  return false;
410
  }
@@ -415,6 +442,7 @@
415
  ! in_array( $result->error->code, array(
416
  'curl_missing',
417
  'cloudflare_ddos_protection',
 
418
  'squid_cache_block',
419
  'too_many_requests',
420
  ) ) );
@@ -449,6 +477,6 @@
449
  self::_init();
450
 
451
  self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
452
- self::$_cache->clear();
453
  }
454
  }
154
  * @return array|mixed|string|void
155
  */
156
  private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
157
+ $this->_logger->entrance( $method . ':' . $path );
158
 
159
  if ( self::is_temporary_down() ) {
160
  $result = $this->get_temporary_unavailable_error();
221
  * @return stdClass|mixed
222
  */
223
  function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
224
+ $this->_logger->entrance( $path );
225
 
226
  $cache_key = $this->get_cache_key( $path );
227
 
258
  return $cached_result;
259
  }
260
 
261
+ /**
262
+ * Check if there's a cached version of the API request.
263
+ *
264
+ * @author Vova Feldman (@svovaf)
265
+ * @since 1.2.1
266
+ *
267
+ * @param string $path
268
+ * @param string $method
269
+ * @param array $params
270
+ *
271
+ * @return bool
272
+ */
273
+ function is_cached( $path, $method = 'GET', $params = array() )
274
+ {
275
+ $cache_key = $this->get_cache_key( $path, $method, $params );
276
+
277
+ return self::$_cache->has_valid( $cache_key );
278
+ }
279
+
280
+ /**
281
+ * @param string $path
282
+ * @param string $method
283
+ * @param array $params
284
+ *
285
+ * @return string
286
+ * @throws \Freemius_Exception
287
+ */
288
  private function get_cache_key( $path, $method = 'GET', $params = array() ) {
289
  $canonized = $this->_api->CanonizePath( $path );
290
  // $exploded = explode('/', $canonized);
291
  // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
292
+ return strtolower($method . ':' . $canonized) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
293
  }
294
 
295
  /**
363
  return (object) array(
364
  'error' => array(
365
  'type' => 'TemporaryUnavailable',
366
+ 'message' => 'API is temporary unavailable, please retry in ' . ( self::$_cache->get_record_expiration( 'ping_test' ) - WP_FS__SCRIPT_START_TIME ) . ' sec.',
367
  'code' => 'temporary_unavailable',
368
  'http' => 503
369
  )
373
  /**
374
  * Ping API for connectivity test, and return result object.
375
  *
376
+ * @author Vova Feldman (@svovaf)
377
+ * @since 1.0.9
378
  *
379
  * @param null|string $unique_anonymous_id
380
+ * @param array $params
381
  *
382
  * @return object
383
  */
384
+ function ping( $unique_anonymous_id = null, $params = array() ) {
385
  $this->_logger->entrance();
386
 
387
  if ( self::is_temporary_down() ) {
390
 
391
  $pong = is_null( $unique_anonymous_id ) ?
392
  Freemius_Api::Ping() :
393
+ $this->_call( 'ping.json?' . http_build_query( array_merge(
394
+ array( 'uid' => $unique_anonymous_id ),
395
+ $params
396
  ) ) );
397
 
398
  if ( $this->is_valid_ping( $pong ) ) {
407
 
408
  $pong = is_null( $unique_anonymous_id ) ?
409
  Freemius_Api::Ping() :
410
+ $this->_call( 'ping.json?' . http_build_query( array_merge(
411
+ array( 'uid' => $unique_anonymous_id ),
412
+ $params
413
  ) ) );
414
 
415
  if ( ! $this->is_valid_ping( $pong ) ) {
431
  *
432
  * @return bool
433
  */
434
+ private static function should_try_with_http( $result ) {
435
  if ( ! Freemius_Api::IsHttps() ) {
436
  return false;
437
  }
442
  ! in_array( $result->error->code, array(
443
  'curl_missing',
444
  'cloudflare_ddos_protection',
445
+ 'maintenance_mode',
446
  'squid_cache_block',
447
  'too_many_requests',
448
  ) ) );
477
  self::_init();
478
 
479
  self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
480
+ self::$_cache->clear( true );
481
  }
482
  }
freemius/includes/class-fs-logger.php CHANGED
@@ -77,7 +77,7 @@
77
  }
78
 
79
  function echo_on() {
80
- $this->_on;
81
 
82
  $this->_echo = true;
83
  }
@@ -86,6 +86,13 @@
86
  return $this->_echo;
87
  }
88
 
 
 
 
 
 
 
 
89
 
90
  private function _log( &$message, $type = 'log', $wrapper ) {
91
  if ( ! $this->is_on() ) {
@@ -103,7 +110,7 @@
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
  ) );
@@ -111,7 +118,7 @@
111
  self::$LOG[] = $log;
112
 
113
  if ( $this->is_echo_on() ) {
114
- echo self::_format_html( $log ) . "\n";
115
  }
116
  }
117
 
@@ -143,11 +150,11 @@
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
 
@@ -158,11 +165,15 @@
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
  }
77
  }
78
 
79
  function echo_on() {
80
+ $this->on();
81
 
82
  $this->_echo = true;
83
  }
86
  return $this->_echo;
87
  }
88
 
89
+ function get_id() {
90
+ return $this->_id;
91
+ }
92
+
93
+ function get_file() {
94
+ return $this->_file_start;
95
+ }
96
 
97
  private function _log( &$message, $type = 'log', $wrapper ) {
98
  if ( ! $this->is_on() ) {
110
  $log = array_merge( $caller, array(
111
  'cnt' => self::$CNT ++,
112
  'logger' => $this,
113
+ 'timestamp' => microtime(true),
114
  'type' => $type,
115
  'msg' => $message,
116
  ) );
118
  self::$LOG[] = $log;
119
 
120
  if ( $this->is_echo_on() ) {
121
+ echo self::format_html( $log ) . "\n";
122
  }
123
  }
124
 
150
  $this->_log( $msg, 'log', $wrapper );
151
  }
152
 
153
+ private static function format( $log, $show_type = true ) {
154
  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'] . ']';
155
  }
156
 
157
+ private static function format_html( $log ) {
158
  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>';
159
  }
160
 
165
  <?php
166
  foreach (self::$LOG as $log)
167
  {
168
+ echo 'console.' . $log['type'] . '(' . json_encode(self::format($log, false)) . ')' . "\n";
169
  }
170
  ?>
171
  </script>
172
  <!-- END: Freemius PHP Console Log -->
173
  <?php
174
  }
175
+
176
+ static function get_log() {
177
+ return self::$LOG;
178
+ }
179
  }
freemius/includes/class-fs-plugin-updater.php CHANGED
@@ -27,6 +27,11 @@
27
  * @since 1.0.4
28
  */
29
  private $_logger;
 
 
 
 
 
30
 
31
  function __construct( Freemius $freemius ) {
32
  $this->_fs = $freemius;
@@ -52,7 +57,7 @@
52
  'pre_set_site_transient_update_plugins_filter'
53
  ) );
54
 
55
- if ( ! $this->_fs->has_active_license() ) {
56
  /**
57
  * If user has the premium plugin's code but do NOT have an active license,
58
  * encourage him to upgrade by showing that there's a new release, but instead
@@ -95,6 +100,9 @@
95
  *
96
  * @author Vova Feldman (@svovaf)
97
  * @since 1.1.6
 
 
 
98
  */
99
  function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
100
  $plugin_update_row = ob_get_clean();
@@ -103,7 +111,7 @@
103
  if ( ! isset( $current->response[ $file ] ) ) {
104
  echo $plugin_update_row;
105
 
106
- return false;
107
  }
108
 
109
  $r = $current->response[ $file ];
@@ -167,21 +175,36 @@
167
  return $transient_data;
168
  }
169
 
170
- // Get plugin's newest update.
171
- $new_version = $this->_fs->get_update();
172
-
173
- if ( is_object( $new_version ) ) {
174
- $this->_logger->log( 'Found newer plugin version ' . $new_version->version );
175
-
176
- $plugin_details = new stdClass();
177
- $plugin_details->slug = $this->_fs->get_slug();
178
- $plugin_details->new_version = $new_version->version;
179
- $plugin_details->url = WP_FS__ADDRESS;
180
- $plugin_details->package = $new_version->url;
181
- $plugin_details->plugin = $this->_fs->get_plugin_basename();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
 
183
  // Add plugin to transient data.
184
- $transient_data->response[ $this->_fs->get_plugin_basename() ] = $plugin_details;
185
  }
186
 
187
  return $transient_data;
@@ -194,11 +217,11 @@
194
  * @since 1.0.5
195
  *
196
  * @param string $action
197
- * @param array $args
198
  *
199
  * @return bool|mixed
200
  */
201
- private function _fetch_plugin_info_from_repository( $action, $args ) {
202
  $url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
203
  if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
204
  $url = set_url_scheme( $url, 'https' );
@@ -266,7 +289,7 @@
266
  $plugin_in_repo = false;
267
  if ( ! $is_addon ) {
268
  // Try to fetch info from .org repository.
269
- $data = $this->_fetch_plugin_info_from_repository( $action, $args );
270
 
271
  $plugin_in_repo = ( false !== $data );
272
  }
27
  * @since 1.0.4
28
  */
29
  private $_logger;
30
+ /**
31
+ * @var object
32
+ * @since 1.1.8.1
33
+ */
34
+ private $_update_details;
35
 
36
  function __construct( Freemius $freemius ) {
37
  $this->_fs = $freemius;
57
  'pre_set_site_transient_update_plugins_filter'
58
  ) );
59
 
60
+ if ( ! $this->_fs->has_active_valid_license() ) {
61
  /**
62
  * If user has the premium plugin's code but do NOT have an active license,
63
  * encourage him to upgrade by showing that there's a new release, but instead
100
  *
101
  * @author Vova Feldman (@svovaf)
102
  * @since 1.1.6
103
+ *
104
+ * @param string $file
105
+ * @param array $plugin_data
106
  */
107
  function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
108
  $plugin_update_row = ob_get_clean();
111
  if ( ! isset( $current->response[ $file ] ) ) {
112
  echo $plugin_update_row;
113
 
114
+ return;
115
  }
116
 
117
  $r = $current->response[ $file ];
175
  return $transient_data;
176
  }
177
 
178
+ if ( ! isset( $this->_update_details ) ) {
179
+ // Get plugin's newest update.
180
+ $new_version = $this->_fs->get_update( false, false );
181
+
182
+ $this->_update_details = false;
183
+
184
+ if ( is_object( $new_version ) ) {
185
+ $this->_logger->log( 'Found newer plugin version ' . $new_version->version );
186
+
187
+ $plugin_details = new stdClass();
188
+ $plugin_details->slug = $this->_fs->get_slug();
189
+ $plugin_details->new_version = $new_version->version;
190
+ $plugin_details->url = WP_FS__ADDRESS;
191
+ $plugin_details->package = $new_version->url;
192
+ $plugin_details->plugin = $this->_fs->get_plugin_basename();
193
+
194
+ /**
195
+ * Cache plugin details locally since set_site_transient( 'update_plugins' )
196
+ * called multiple times and the non wp.org plugins are filtered after the
197
+ * call to .org.
198
+ *
199
+ * @since 1.1.8.1
200
+ */
201
+ $this->_update_details = $plugin_details;
202
+ }
203
+ }
204
 
205
+ if ( is_object( $this->_update_details ) ) {
206
  // Add plugin to transient data.
207
+ $transient_data->response[ $this->_fs->get_plugin_basename() ] = $this->_update_details;
208
  }
209
 
210
  return $transient_data;
217
  * @since 1.0.5
218
  *
219
  * @param string $action
220
+ * @param object $args
221
  *
222
  * @return bool|mixed
223
  */
224
+ static function _fetch_plugin_info_from_repository( $action, $args ) {
225
  $url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
226
  if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
227
  $url = set_url_scheme( $url, 'https' );
289
  $plugin_in_repo = false;
290
  if ( ! $is_addon ) {
291
  // Try to fetch info from .org repository.
292
+ $data = self::_fetch_plugin_info_from_repository( $action, $args );
293
 
294
  $plugin_in_repo = ( false !== $data );
295
  }
freemius/includes/class-fs-security.php CHANGED
@@ -27,7 +27,11 @@
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;
@@ -36,6 +40,13 @@
36
  private function __construct() {
37
  }
38
 
 
 
 
 
 
 
 
39
  function get_secure_token( FS_Scope_Entity $entity, $timestamp, $action = '' ) {
40
  return md5(
41
  $timestamp .
@@ -46,6 +57,13 @@
46
  );
47
  }
48
 
 
 
 
 
 
 
 
49
  function get_context_params( FS_Scope_Entity $entity, $timestamp = false, $action = '' ) {
50
  if ( false === $timestamp ) {
51
  $timestamp = time();
27
  public static function instance() {
28
  if ( ! isset( self::$_instance ) ) {
29
  self::$_instance = new FS_Security();
30
+ self::$_logger = FS_Logger::get_logger(
31
+ WP_FS__SLUG,
32
+ WP_FS__DEBUG_SDK,
33
+ WP_FS__ECHO_DEBUG_SDK
34
+ );
35
  }
36
 
37
  return self::$_instance;
40
  private function __construct() {
41
  }
42
 
43
+ /**
44
+ * @param \FS_Scope_Entity $entity
45
+ * @param int $timestamp
46
+ * @param string $action
47
+ *
48
+ * @return string
49
+ */
50
  function get_secure_token( FS_Scope_Entity $entity, $timestamp, $action = '' ) {
51
  return md5(
52
  $timestamp .
57
  );
58
  }
59
 
60
+ /**
61
+ * @param \FS_Scope_Entity $entity
62
+ * @param int|bool $timestamp
63
+ * @param string $action
64
+ *
65
+ * @return array
66
+ */
67
  function get_context_params( FS_Scope_Entity $entity, $timestamp = false, $action = '' ) {
68
  if ( false === $timestamp ) {
69
  $timestamp = time();
freemius/includes/debug/class-fs-debug-bar-panel.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Extends Debug Bar plugin by adding a panel to show all Freemius API requests.
15
+ *
16
+ * @author Vova Feldman (@svovaf)
17
+ * @since 1.1.7.3
18
+ *
19
+ * Class Freemius_Debug_Bar_Panel
20
+ */
21
+ class Freemius_Debug_Bar_Panel extends Debug_Bar_Panel {
22
+ function init() {
23
+ $this->title( 'Freemius' );
24
+ }
25
+
26
+ static function requests_count() {
27
+ if ( class_exists( 'Freemius_Api' ) ) {
28
+ $logger = Freemius_Api::GetLogger();
29
+ } else {
30
+ $logger = array();
31
+ }
32
+
33
+ return number_format( count( $logger ) );
34
+ }
35
+
36
+ static function total_time() {
37
+ if ( class_exists( 'Freemius_Api' ) ) {
38
+ $logger = Freemius_Api::GetLogger();
39
+ } else {
40
+ $logger = array();
41
+ }
42
+
43
+ $total_time = .0;
44
+ foreach ( $logger as $l ) {
45
+ $total_time += $l['total'];
46
+ }
47
+
48
+ return number_format( 100 * $total_time, 2 ) . ' ' . __fs( 'ms' );
49
+ }
50
+
51
+ function render() {
52
+ ?>
53
+ <div id='debug-bar-php'>
54
+ <?php fs_require_template( '/debug/api-calls.php' ) ?>
55
+ <br>
56
+ <?php fs_require_template( '/debug/scheduled-crons.php' ) ?>
57
+ <br>
58
+ <?php fs_require_template( '/debug/plugins-themes-sync.php' ) ?>
59
+ <br>
60
+ <?php fs_require_template( '/debug/logger.php' ) ?>
61
+ </div>
62
+ <?php
63
+ }
64
+ }
freemius/includes/debug/debug-bar-start.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ if ( ! WP_FS__DEBUG_SDK ) {
14
+ return;
15
+ }
16
+
17
+ /**
18
+ * Initialize Freemius custom debug panels.
19
+ *
20
+ * @param array $panels Debug bar panels objects
21
+ *
22
+ * @return array Debug bar panels with your custom panels
23
+ */
24
+ function fs_custom_panels_init( $panels ) {
25
+ if ( class_exists( 'Debug_Bar_Panel' ) ) {
26
+ if ( FS_API__LOGGER_ON ) {
27
+ require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php';
28
+ $panels[] = new Freemius_Debug_Bar_Panel();
29
+ }
30
+ }
31
+
32
+ return $panels;
33
+ }
34
+
35
+ function fs_custom_status_init( $statuses ) {
36
+ if ( class_exists( 'Debug_Bar_Panel' ) ) {
37
+ if ( FS_API__LOGGER_ON ) {
38
+ require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php';
39
+ $statuses[] = array(
40
+ 'fs_api_requests',
41
+ __fs( 'Freemius API' ),
42
+ Freemius_Debug_Bar_Panel::requests_count() . ' ' . __fs( 'Requests' ) .
43
+ ' (' . Freemius_Debug_Bar_Panel::total_time() . ')'
44
+ );
45
+ }
46
+ }
47
+
48
+ return $statuses;
49
+ }
50
+
51
+ add_filter( 'debug_bar_panels', 'fs_custom_panels_init' );
52
+ add_filter( 'debug_bar_statuses', 'fs_custom_status_init' );
freemius/includes/entities/class-fs-entity.php CHANGED
@@ -39,7 +39,7 @@
39
  public $created;
40
 
41
  /**
42
- * @param bool|stdClass $entity
43
  */
44
  function __construct( $entity = false ) {
45
  if ( ! ( $entity instanceof stdClass ) ) {
39
  public $created;
40
 
41
  /**
42
+ * @param bool|object $entity
43
  */
44
  function __construct( $entity = false ) {
45
  if ( ! ( $entity instanceof stdClass ) ) {
freemius/includes/entities/class-fs-payment.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2016, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Payment 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 $install_id;
29
+ /**
30
+ * @var number
31
+ */
32
+ public $subscription_id;
33
+ /**
34
+ * @var number
35
+ */
36
+ public $plan_id;
37
+ /**
38
+ * @var number
39
+ */
40
+ public $license_id;
41
+ /**
42
+ * @var float
43
+ */
44
+ public $gross;
45
+ /**
46
+ * @var number
47
+ */
48
+ public $bound_payment_id;
49
+ /**
50
+ * @var string
51
+ */
52
+ public $external_id;
53
+ /**
54
+ * @var string
55
+ */
56
+ public $gateway;
57
+ /**
58
+ * @var string ISO 3166-1 alpha-2 - two-letter country code.
59
+ *
60
+ * @link http://www.wikiwand.com/en/ISO_3166-1_alpha-2
61
+ */
62
+ public $country_code;
63
+ /**
64
+ * @var string
65
+ */
66
+ public $vat_id;
67
+ /**
68
+ * @var float Actual Tax / VAT in $$$
69
+ */
70
+ public $vat;
71
+
72
+ #endregion Properties
73
+
74
+ /**
75
+ * @param object|bool $payment
76
+ */
77
+ function __construct( $payment = false ) {
78
+ parent::__construct( $payment );
79
+ }
80
+
81
+ static function get_type() {
82
+ return 'payment';
83
+ }
84
+
85
+ /**
86
+ * @author Vova Feldman (@svovaf)
87
+ * @since 1.0.0
88
+ *
89
+ * @return bool
90
+ */
91
+ function is_refund() {
92
+ return ( parent::is_valid_id( $this->bound_payment_id ) && 0 > $this->gross );
93
+ }
94
+ }
freemius/includes/entities/class-fs-plugin-license.php CHANGED
@@ -31,7 +31,7 @@
31
  */
32
  public $pricing_id;
33
  /**
34
- * @var int
35
  */
36
  public $quota;
37
  /**
@@ -46,6 +46,10 @@
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.
@@ -83,13 +87,29 @@
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
@@ -100,6 +120,18 @@
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
@@ -110,6 +142,16 @@
110
  return is_null( $this->expiration );
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
113
  /**
114
  * Check if license is fully utilized.
115
  *
@@ -125,10 +167,24 @@
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
  *
@@ -141,7 +197,7 @@
141
  * @return bool
142
  */
143
  function is_features_enabled() {
144
- return ( ! $this->is_block_features || ! $this->is_expired() );
145
  }
146
 
147
  /**
31
  */
32
  public $pricing_id;
33
  /**
34
+ * @var int|null
35
  */
36
  public $quota;
37
  /**
46
  * @var string
47
  */
48
  public $expiration;
49
+ /**
50
+ * @var string
51
+ */
52
+ public $secret_key;
53
  /**
54
  * @var bool $is_free_localhost Defaults to true. If true, allow unlimited localhost installs with the same
55
  * license.
87
  * @return int
88
  */
89
  function left() {
90
+ if ( ! $this->is_active() || $this->is_expired() ) {
91
  return 0;
92
  }
93
 
94
+ if ( $this->is_unlimited() ) {
95
+ return 999;
96
+ }
97
+
98
  return ( $this->quota - $this->activated - ( $this->is_free_localhost ? 0 : $this->activated_local ) );
99
  }
100
 
101
+ /**
102
+ * Check if single site license.
103
+ *
104
+ * @author Vova Feldman (@svovaf)
105
+ * @since 1.1.8.1
106
+ *
107
+ * @return bool
108
+ */
109
+ function is_single_site() {
110
+ return ( is_numeric( $this->quota ) && 1 == $this->quota );
111
+ }
112
+
113
  /**
114
  * @author Vova Feldman (@svovaf)
115
  * @since 1.0.5
120
  return ! $this->is_lifetime() && ( strtotime( $this->expiration ) < WP_FS__SCRIPT_START_TIME );
121
  }
122
 
123
+ /**
124
+ * Check if license is not expired.
125
+ *
126
+ * @author Vova Feldman (@svovaf)
127
+ * @since 1.2.1
128
+ *
129
+ * @return bool
130
+ */
131
+ function is_valid() {
132
+ return ! $this->is_expired();
133
+ }
134
+
135
  /**
136
  * @author Vova Feldman (@svovaf)
137
  * @since 1.0.6
142
  return is_null( $this->expiration );
143
  }
144
 
145
+ /**
146
+ * @author Vova Feldman (@svovaf)
147
+ * @since 1.2.0
148
+ *
149
+ * @return bool
150
+ */
151
+ function is_unlimited() {
152
+ return is_null( $this->quota );
153
+ }
154
+
155
  /**
156
  * Check if license is fully utilized.
157
  *
167
  $is_localhost = WP_FS__IS_LOCALHOST_FOR_SERVER;
168
  }
169
 
170
+ if ( $this->is_unlimited() ) {
171
+ return false;
172
+ }
173
+
174
  return ! ( $this->is_free_localhost && $is_localhost ) &&
175
  ( $this->quota <= $this->activated + ( $this->is_free_localhost ? 0 : $this->activated_local ) );
176
  }
177
 
178
+ /**
179
+ * @author Vova Feldman (@svovaf)
180
+ * @since 1.2.1
181
+ *
182
+ * @return bool
183
+ */
184
+ function is_active() {
185
+ return ( ! $this->is_cancelled );
186
+ }
187
+
188
  /**
189
  * Check if license's plan features are enabled.
190
  *
197
  * @return bool
198
  */
199
  function is_features_enabled() {
200
+ return $this->is_active() && ( ! $this->is_block_features || ! $this->is_expired() );
201
  }
202
 
203
  /**
freemius/includes/entities/class-fs-plugin-plan.php CHANGED
@@ -10,10 +10,23 @@
10
  exit;
11
  }
12
 
 
 
 
 
 
13
  class FS_Plugin_Plan extends FS_Entity {
14
 
15
  #region Properties
16
 
 
 
 
 
 
 
 
 
17
  /**
18
  * @var string
19
  */
@@ -21,7 +34,24 @@
21
  /**
22
  * @var string
23
  */
24
- public $name;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  /**
26
  * @var int Trial days.
27
  */
@@ -30,6 +60,34 @@
30
  * @var string If true, require payment for trial.
31
  */
32
  public $is_require_subscription;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  #endregion Properties
35
 
@@ -58,6 +116,22 @@
58
  return ( 'free' === $this->name );
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  /**
62
  * @author Vova Feldman (@svovaf)
63
  * @since 1.0.9
10
  exit;
11
  }
12
 
13
+ /**
14
+ * Class FS_Plugin_Plan
15
+ *
16
+ * @property FS_Pricing[] $pricing
17
+ */
18
  class FS_Plugin_Plan extends FS_Entity {
19
 
20
  #region Properties
21
 
22
+ /**
23
+ * @var number
24
+ */
25
+ public $plugin_id;
26
+ /**
27
+ * @var string
28
+ */
29
+ public $name;
30
  /**
31
  * @var string
32
  */
34
  /**
35
  * @var string
36
  */
37
+ public $description;
38
+ /**
39
+ * @var bool Defaults to true. If true, allow unlimited localhost installs with the same license.
40
+ */
41
+ public $is_free_localhost;
42
+ /**
43
+ * @var bool Defaults to true. If false, don't block features after license expiry - only block updates and
44
+ * support.
45
+ */
46
+ public $is_block_features;
47
+ /**
48
+ * @var int
49
+ */
50
+ public $license_type;
51
+ /**
52
+ * @var bool
53
+ */
54
+ public $is_https_support;
55
  /**
56
  * @var int Trial days.
57
  */
60
  * @var string If true, require payment for trial.
61
  */
62
  public $is_require_subscription;
63
+ /**
64
+ * @var string Knowledge Base URL.
65
+ */
66
+ public $support_kb;
67
+ /**
68
+ * @var string Support Forum URL.
69
+ */
70
+ public $support_forum;
71
+ /**
72
+ * @var string Support email address.
73
+ */
74
+ public $support_email;
75
+ /**
76
+ * @var string Support phone.
77
+ */
78
+ public $support_phone;
79
+ /**
80
+ * @var string Support skype username.
81
+ */
82
+ public $support_skype;
83
+ /**
84
+ * @var bool Is personal success manager supported with the plan.
85
+ */
86
+ public $is_success_manager;
87
+ /**
88
+ * @var bool Is featured plan.
89
+ */
90
+ public $is_featured;
91
 
92
  #endregion Properties
93
 
116
  return ( 'free' === $this->name );
117
  }
118
 
119
+ /**
120
+ * Checks if this plan supports "Technical Support".
121
+ *
122
+ * @author Leo Fajardo (leorw)
123
+ * @since 1.2.0
124
+ *
125
+ * @return bool
126
+ */
127
+ function has_technical_support() {
128
+ return ( ! empty( $this->support_email ) ||
129
+ ! empty( $this->support_skype ) ||
130
+ ! empty( $this->support_phone ) ||
131
+ ! empty( $this->is_success_manager )
132
+ );
133
+ }
134
+
135
  /**
136
  * @author Vova Feldman (@svovaf)
137
  * @since 1.0.9
freemius/includes/entities/class-fs-pricing.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius for EDD Add-On
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.0.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ class FS_Pricing extends FS_Entity {
14
+
15
+ #region Properties
16
+
17
+ /**
18
+ * @var number
19
+ */
20
+ public $plan_id;
21
+ /**
22
+ * @var int
23
+ */
24
+ public $licenses;
25
+ /**
26
+ * @var null|float
27
+ */
28
+ public $monthly_price;
29
+ /**
30
+ * @var null|float
31
+ */
32
+ public $annual_price;
33
+ /**
34
+ * @var null|float
35
+ */
36
+ public $lifetime_price;
37
+
38
+ #endregion Properties
39
+
40
+ /**
41
+ * @param object|bool $pricing
42
+ */
43
+ function __construct( $pricing = false ) {
44
+ parent::__construct( $pricing );
45
+ }
46
+
47
+ static function get_type() {
48
+ return 'pricing';
49
+ }
50
+
51
+ /**
52
+ * @author Vova Feldman (@svovaf)
53
+ * @since 1.1.8
54
+ *
55
+ * @return bool
56
+ */
57
+ function has_monthly() {
58
+ return ( is_numeric( $this->monthly_price ) && $this->monthly_price > 0 );
59
+ }
60
+
61
+ /**
62
+ * @author Vova Feldman (@svovaf)
63
+ * @since 1.1.8
64
+ *
65
+ * @return bool
66
+ */
67
+ function has_annual() {
68
+ return ( is_numeric( $this->annual_price ) && $this->annual_price > 0 );
69
+ }
70
+
71
+ /**
72
+ * @author Vova Feldman (@svovaf)
73
+ * @since 1.1.8
74
+ *
75
+ * @return bool
76
+ */
77
+ function has_lifetime() {
78
+ return ( is_numeric( $this->lifetime_price ) && $this->lifetime_price > 0 );
79
+ }
80
+
81
+ /**
82
+ * Check if unlimited licenses pricing.
83
+ *
84
+ * @author Vova Feldman (@svovaf)
85
+ * @since 1.1.8
86
+ *
87
+ * @return bool
88
+ */
89
+ function is_unlimited() {
90
+ return is_null( $this->licenses );
91
+ }
92
+
93
+
94
+ /**
95
+ * Check if pricing has more than one billing cycle.
96
+ *
97
+ * @author Vova Feldman (@svovaf)
98
+ * @since 1.1.8
99
+ *
100
+ * @return bool
101
+ */
102
+ function is_multi_cycle() {
103
+ $cycles = 0;
104
+ if ( $this->has_monthly() ) {
105
+ $cycles ++;
106
+ }
107
+ if ( $this->has_annual() ) {
108
+ $cycles ++;
109
+ }
110
+ if ( $this->has_lifetime() ) {
111
+ $cycles ++;
112
+ }
113
+
114
+ return $cycles > 1;
115
+ }
116
+
117
+ /**
118
+ * Get annual over monthly discount.
119
+ *
120
+ * @author Vova Feldman (@svovaf)
121
+ * @since 1.1.8
122
+ *
123
+ * @return int
124
+ */
125
+ function annual_discount_percentage() {
126
+ return floor( $this->annual_savings() / ( $this->monthly_price * 12 * ( $this->is_unlimited() ? 1 : $this->licenses ) ) * 100 );
127
+ }
128
+
129
+ /**
130
+ * Get annual over monthly savings.
131
+ *
132
+ * @author Vova Feldman (@svovaf)
133
+ * @since 1.1.8
134
+ *
135
+ * @return float
136
+ */
137
+ function annual_savings() {
138
+ return ( $this->monthly_price * 12 - $this->annual_price ) * ( $this->is_unlimited() ? 1 : $this->licenses );
139
+ }
140
+
141
+ }
freemius/includes/entities/class-fs-site.php CHANGED
@@ -15,6 +15,14 @@
15
  * @var string
16
  */
17
  public $slug;
 
 
 
 
 
 
 
 
18
  /**
19
  * @var number
20
  */
15
  * @var string
16
  */
17
  public $slug;
18
+ /**
19
+ * @var number
20
+ */
21
+ public $site_id;
22
+ /**
23
+ * @var number
24
+ */
25
+ public $plugin_id;
26
  /**
27
  * @var number
28
  */
freemius/includes/entities/class-fs-subscription.php CHANGED
@@ -114,4 +114,12 @@
114
  function is_first_payment_pending() {
115
  return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->next_payment ) - strtotime( $this->created ) );
116
  }
 
 
 
 
 
 
 
 
117
  }
114
  function is_first_payment_pending() {
115
  return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->next_payment ) - strtotime( $this->created ) );
116
  }
117
+
118
+ /**
119
+ * @author Vova Feldman (@svovaf)
120
+ * @since 1.1.7
121
+ */
122
+ function has_trial() {
123
+ return ! is_null( $this->trial_ends );
124
+ }
125
  }
freemius/includes/fs-core-functions.php CHANGED
@@ -14,7 +14,17 @@
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.
@@ -25,37 +35,39 @@
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
  /* Scripts and styles including.
@@ -103,7 +115,19 @@
103
  }
104
 
105
  function fs_request_get_bool( $key, $def = false ) {
106
- return ( isset( $_REQUEST[ $key ] ) && ( 1 == $_REQUEST[ $key ] || 'true' === strtolower( $_REQUEST[ $key ] ) ) ) ? true : $def;
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
 
109
  function fs_request_is_post() {
@@ -140,11 +164,99 @@
140
 
141
  /* Core UI.
142
  --------------------------------------------------------------------------------------------*/
143
- function fs_ui_action_button( $slug, $page, $action, $title, $params = array(), $is_primary = true ) {
144
- ?><a class="button<?php if ( $is_primary ) {
145
- echo ' button-primary';
146
- } ?>"
147
- 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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
 
150
  function fs_ui_action_link( $slug, $page, $action, $title, $params = array() ) {
@@ -180,120 +292,130 @@
180
  return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
181
  }
182
 
183
- /**
184
- * Check if string starts with.
185
- *
186
- * @author Vova Feldman (@svovaf)
187
- * @since 1.1.3
188
- *
189
- * @param string $haystack
190
- * @param string $needle
191
- *
192
- * @return bool
193
- */
194
- function fs_starts_with( $haystack, $needle ) {
195
- $length = strlen( $needle );
196
-
197
- return ( substr( $haystack, 0, $length ) === $needle );
 
 
198
  }
199
 
200
  #region Url Canonization ------------------------------------------------------------------
201
 
202
- /**
203
- * @author Vova Feldman (@svovaf)
204
- * @since 1.1.3
205
- *
206
- * @param string $url
207
- * @param bool $omit_host
208
- * @param array $ignore_params
209
- *
210
- * @return string
211
- */
212
- function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
213
- $parsed_url = parse_url( strtolower( $url ) );
 
214
 
215
  // if ( ! isset( $parsed_url['host'] ) ) {
216
  // return $url;
217
  // }
218
 
219
- $canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
220
 
221
- if ( isset( $parsed_url['query'] ) ) {
222
- parse_str( $parsed_url['query'], $queryString );
223
- $canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
224
- }
225
 
226
- return $canonical;
 
227
  }
228
 
229
- /**
230
- * @author Vova Feldman (@svovaf)
231
- * @since 1.1.3
232
- *
233
- * @param array $params
234
- * @param array $ignore_params
235
- * @param bool $params_prefix
236
- *
237
- * @return string
238
- */
239
- function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
240
- if ( ! is_array( $params ) || 0 === count( $params ) ) {
241
- return '';
242
- }
 
243
 
244
- // Urlencode both keys and values
245
- $keys = fs_urlencode_rfc3986( array_keys( $params ) );
246
- $values = fs_urlencode_rfc3986( array_values( $params ) );
247
- $params = array_combine( $keys, $values );
248
 
249
- // Parameters are sorted by name, using lexicographical byte value ordering.
250
- // Ref: Spec: 9.1.1 (1)
251
- uksort( $params, 'strcmp' );
252
 
253
- $pairs = array();
254
- foreach ( $params as $parameter => $value ) {
255
- $lower_param = strtolower( $parameter );
256
 
257
- // Skip ignore params.
258
- if ( in_array( $lower_param, $ignore_params ) || ( false !== $params_prefix && startsWith( $lower_param, $params_prefix ) ) ) {
259
- continue;
260
- }
 
 
261
 
262
- if ( is_array( $value ) ) {
263
- // If two or more parameters share the same name, they are sorted by their value
264
- // Ref: Spec: 9.1.1 (1)
265
- natsort( $value );
266
- foreach ( $value as $duplicate_value ) {
267
- $pairs[] = $lower_param . '=' . $duplicate_value;
 
 
 
268
  }
269
- } else {
270
- $pairs[] = $lower_param . '=' . $value;
271
  }
272
- }
273
 
274
- if ( 0 === count( $pairs ) ) {
275
- return '';
276
- }
277
 
278
- return implode( "&", $pairs );
 
279
  }
280
 
281
- /**
282
- * @author Vova Feldman (@svovaf)
283
- * @since 1.1.3
284
- *
285
- * @param string|string[] $input
286
- *
287
- * @return array|mixed|string
288
- */
289
- function fs_urlencode_rfc3986( $input ) {
290
- if ( is_array( $input ) ) {
291
- return array_map( 'fs_urlencode_rfc3986', $input );
292
- } else if ( is_scalar( $input ) ) {
293
- return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
294
- }
 
295
 
296
- return '';
 
297
  }
298
 
299
  #endregion Url Canonization ------------------------------------------------------------------
@@ -308,36 +430,34 @@
308
  fclose( $fp );
309
  }
310
 
311
- /* General Utilities
312
- --------------------------------------------------------------------------------------------*/
313
-
314
- /**
315
- * Sorts an array by the value of the priority key.
316
- *
317
- * @author Daniel Iser (@danieliser)
318
- * @since 1.1.7
319
- *
320
- * @param $a
321
- * @param $b
322
- *
323
- * @return int
324
- */
325
- function fs_sort_by_priority( $a, $b ) {
326
-
327
- // If b has a priority and a does not, b wins.
328
- if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
329
- return 1;
330
- }
331
- // If b has a priority and a does not, b wins.
332
- elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
333
- return -1;
334
- }
335
- // If neither has a priority or both priorities are equal its a tie.
336
- elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
337
- return 0;
338
- }
339
-
340
- // If both have priority return the winner.
341
- return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
342
- }
343
 
14
 
15
  $fs_core_logger = FS_Logger::get_logger( WP_FS__SLUG . '_core', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
16
 
17
+ if ( ! function_exists( 'fs_dummy' ) ) {
18
+ function fs_dummy() {
19
+ }
20
+ }
21
+
22
+ if ( ! function_exists( 'starts_with' ) ) {
23
+ function starts_with( $haystack, $needle ) {
24
+ $length = strlen( $needle );
25
+
26
+ return ( substr( $haystack, 0, $length ) === $needle );
27
+ }
28
  }
29
 
30
  /* Url.
35
 
36
  /* Templates / Views.
37
  --------------------------------------------------------------------------------------------*/
38
+ if ( ! function_exists( 'fs_get_template_path' ) ) {
39
+ function fs_get_template_path( $path ) {
40
+ return WP_FS__DIR_TEMPLATES . '/' . trim( $path, '/' );
41
+ }
42
 
43
+ function fs_include_template( $path, &$params = null ) {
44
+ $VARS = &$params;
45
+ include( fs_get_template_path( $path ) );
46
+ }
47
 
48
+ function fs_include_once_template( $path, &$params = null ) {
49
+ $VARS = &$params;
50
+ include_once( fs_get_template_path( $path ) );
51
+ }
52
 
53
+ function fs_require_template( $path, &$params = null ) {
54
+ $VARS = &$params;
55
+ require( fs_get_template_path( $path ) );
56
+ }
57
 
58
+ function fs_require_once_template( $path, &$params = null ) {
59
+ $VARS = &$params;
60
+ require_once( fs_get_template_path( $path ) );
61
+ }
62
 
63
+ function fs_get_template( $path, &$params = null ) {
64
+ ob_start();
65
 
66
+ $VARS = &$params;
67
+ require_once( fs_get_template_path( $path ) );
68
 
69
+ return ob_get_clean();
70
+ }
71
  }
72
 
73
  /* Scripts and styles including.
115
  }
116
 
117
  function fs_request_get_bool( $key, $def = false ) {
118
+ if ( ! isset( $_REQUEST[ $key ] ) ) {
119
+ return $def;
120
+ }
121
+
122
+ if ( 1 == $_REQUEST[ $key ] || 'true' === strtolower( $_REQUEST[ $key ] ) ) {
123
+ return true;
124
+ }
125
+
126
+ if ( 0 == $_REQUEST[ $key ] || 'false' === strtolower( $_REQUEST[ $key ] ) ) {
127
+ return false;
128
+ }
129
+
130
+ return $def;
131
  }
132
 
133
  function fs_request_is_post() {
164
 
165
  /* Core UI.
166
  --------------------------------------------------------------------------------------------*/
167
+ /**
168
+ * @param string $slug
169
+ * @param string $page
170
+ * @param string $action
171
+ * @param string $title
172
+ * @param array $params
173
+ * @param bool $is_primary
174
+ * @param string|bool $icon_class Optional class for an icon (since 1.1.7).
175
+ * @param string|bool $confirmation Optional confirmation message before submit (since 1.1.7).
176
+ * @param string $method Since 1.1.7
177
+ *
178
+ * @uses fs_ui_get_action_button()
179
+ */
180
+ function fs_ui_action_button(
181
+ $slug,
182
+ $page,
183
+ $action,
184
+ $title,
185
+ $params = array(),
186
+ $is_primary = true,
187
+ $icon_class = false,
188
+ $confirmation = false,
189
+ $method = 'GET'
190
+ ) {
191
+ echo fs_ui_get_action_button(
192
+ $slug,
193
+ $page,
194
+ $action,
195
+ $title,
196
+ $params,
197
+ $is_primary,
198
+ $icon_class,
199
+ $confirmation,
200
+ $method
201
+ );
202
+ }
203
+
204
+ /**
205
+ * @author Vova Feldman (@svovaf)
206
+ * @since 1.1.7
207
+ *
208
+ * @param string $slug
209
+ * @param string $page
210
+ * @param string $action
211
+ * @param string $title
212
+ * @param array $params
213
+ * @param bool $is_primary
214
+ * @param string|bool $icon_class Optional class for an icon.
215
+ * @param string|bool $confirmation Optional confirmation message before submit.
216
+ * @param string $method
217
+ *
218
+ * @return string
219
+ */
220
+ function fs_ui_get_action_button(
221
+ $slug,
222
+ $page,
223
+ $action,
224
+ $title,
225
+ $params = array(),
226
+ $is_primary = true,
227
+ $icon_class = false,
228
+ $confirmation = false,
229
+ $method = 'GET'
230
+ ) {
231
+ // Prepend icon (if set).
232
+ $title = ( is_string( $icon_class ) ? '<i class="' . $icon_class . '"></i> ' : '' ) . $title;
233
+
234
+ if ( is_string( $confirmation ) ) {
235
+ return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="if (confirm(\'%s\')) this.parentNode.submit(); return false;">%s</a></form>',
236
+ freemius( $slug )->_get_admin_page_url( $page, $params ),
237
+ $method,
238
+ $action,
239
+ wp_nonce_field( $action, '_wpnonce', true, false ),
240
+ 'button' . ( $is_primary ? ' button-primary' : '' ),
241
+ $confirmation,
242
+ $title
243
+ );
244
+ } else if ( 'GET' !== strtoupper( $method ) ) {
245
+ return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="this.parentNode.submit(); return false;">%s</a></form>',
246
+ freemius( $slug )->_get_admin_page_url( $page, $params ),
247
+ $method,
248
+ $action,
249
+ wp_nonce_field( $action, '_wpnonce', true, false ),
250
+ 'button' . ( $is_primary ? ' button-primary' : '' ),
251
+ $title
252
+ );
253
+ } else {
254
+ return sprintf( '<a href="%s" class="%s">%s</a></form>',
255
+ wp_nonce_url( freemius( $slug )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ),
256
+ 'button' . ( $is_primary ? ' button-primary' : '' ),
257
+ $title
258
+ );
259
+ }
260
  }
261
 
262
  function fs_ui_action_link( $slug, $page, $action, $title, $params = array() ) {
292
  return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
293
  }
294
 
295
+ if ( ! function_exists( 'fs_starts_with' ) ) {
296
+ /**
297
+ * Check if string starts with.
298
+ *
299
+ * @author Vova Feldman (@svovaf)
300
+ * @since 1.1.3
301
+ *
302
+ * @param string $haystack
303
+ * @param string $needle
304
+ *
305
+ * @return bool
306
+ */
307
+ function fs_starts_with( $haystack, $needle ) {
308
+ $length = strlen( $needle );
309
+
310
+ return ( substr( $haystack, 0, $length ) === $needle );
311
+ }
312
  }
313
 
314
  #region Url Canonization ------------------------------------------------------------------
315
 
316
+ if ( ! function_exists( 'fs_canonize_url' ) ) {
317
+ /**
318
+ * @author Vova Feldman (@svovaf)
319
+ * @since 1.1.3
320
+ *
321
+ * @param string $url
322
+ * @param bool $omit_host
323
+ * @param array $ignore_params
324
+ *
325
+ * @return string
326
+ */
327
+ function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
328
+ $parsed_url = parse_url( strtolower( $url ) );
329
 
330
  // if ( ! isset( $parsed_url['host'] ) ) {
331
  // return $url;
332
  // }
333
 
334
+ $canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
335
 
336
+ if ( isset( $parsed_url['query'] ) ) {
337
+ parse_str( $parsed_url['query'], $queryString );
338
+ $canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
339
+ }
340
 
341
+ return $canonical;
342
+ }
343
  }
344
 
345
+ if ( ! function_exists( 'fs_canonize_query_string' ) ) {
346
+ /**
347
+ * @author Vova Feldman (@svovaf)
348
+ * @since 1.1.3
349
+ *
350
+ * @param array $params
351
+ * @param array $ignore_params
352
+ * @param bool $params_prefix
353
+ *
354
+ * @return string
355
+ */
356
+ function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
357
+ if ( ! is_array( $params ) || 0 === count( $params ) ) {
358
+ return '';
359
+ }
360
 
361
+ // Url encode both keys and values
362
+ $keys = fs_urlencode_rfc3986( array_keys( $params ) );
363
+ $values = fs_urlencode_rfc3986( array_values( $params ) );
364
+ $params = array_combine( $keys, $values );
365
 
366
+ // Parameters are sorted by name, using lexicographical byte value ordering.
367
+ // Ref: Spec: 9.1.1 (1)
368
+ uksort( $params, 'strcmp' );
369
 
370
+ $pairs = array();
371
+ foreach ( $params as $parameter => $value ) {
372
+ $lower_param = strtolower( $parameter );
373
 
374
+ // Skip ignore params.
375
+ if ( in_array( $lower_param, $ignore_params ) ||
376
+ ( false !== $params_prefix && starts_with( $lower_param, $params_prefix ) )
377
+ ) {
378
+ continue;
379
+ }
380
 
381
+ if ( is_array( $value ) ) {
382
+ // If two or more parameters share the same name, they are sorted by their value
383
+ // Ref: Spec: 9.1.1 (1)
384
+ natsort( $value );
385
+ foreach ( $value as $duplicate_value ) {
386
+ $pairs[] = $lower_param . '=' . $duplicate_value;
387
+ }
388
+ } else {
389
+ $pairs[] = $lower_param . '=' . $value;
390
  }
 
 
391
  }
 
392
 
393
+ if ( 0 === count( $pairs ) ) {
394
+ return '';
395
+ }
396
 
397
+ return implode( "&", $pairs );
398
+ }
399
  }
400
 
401
+ if ( ! function_exists( 'fs_urlencode_rfc3986' ) ) {
402
+ /**
403
+ * @author Vova Feldman (@svovaf)
404
+ * @since 1.1.3
405
+ *
406
+ * @param string|string[] $input
407
+ *
408
+ * @return array|mixed|string
409
+ */
410
+ function fs_urlencode_rfc3986( $input ) {
411
+ if ( is_array( $input ) ) {
412
+ return array_map( 'fs_urlencode_rfc3986', $input );
413
+ } else if ( is_scalar( $input ) ) {
414
+ return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
415
+ }
416
 
417
+ return '';
418
+ }
419
  }
420
 
421
  #endregion Url Canonization ------------------------------------------------------------------
430
  fclose( $fp );
431
  }
432
 
433
+ /* General Utilities
434
+ --------------------------------------------------------------------------------------------*/
435
+
436
+ /**
437
+ * Sorts an array by the value of the priority key.
438
+ *
439
+ * @author Daniel Iser (@danieliser)
440
+ * @since 1.1.7
441
+ *
442
+ * @param $a
443
+ * @param $b
444
+ *
445
+ * @return int
446
+ */
447
+ function fs_sort_by_priority( $a, $b ) {
448
+
449
+ // If b has a priority and a does not, b wins.
450
+ if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
451
+ return 1;
452
+ } // If b has a priority and a does not, b wins.
453
+ elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
454
+ return - 1;
455
+ } // If neither has a priority or both priorities are equal its a tie.
456
+ elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
457
+ return 0;
458
+ }
459
+
460
+ // If both have priority return the winner.
461
+ return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
462
+ }
 
 
463
 
freemius/includes/fs-essential-functions.php CHANGED
@@ -72,49 +72,53 @@
72
  return true;
73
  }
74
 
75
- /**
76
- * Sanitizes a URL for use in a redirect.
77
- *
78
- * @since 2.3
79
- *
80
- * @param string $location
81
- *
82
- * @return string redirect-sanitized URL
83
- */
84
- function fs_sanitize_redirect( $location ) {
85
- $location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location );
86
- $location = fs_kses_no_null( $location );
87
-
88
- // remove %0d and %0a from location
89
- $strip = array( '%0d', '%0a' );
90
- $found = true;
91
- while ( $found ) {
92
- $found = false;
93
- foreach ( (array) $strip as $val ) {
94
- while ( strpos( $location, $val ) !== false ) {
95
- $found = true;
96
- $location = str_replace( $val, '', $location );
 
 
97
  }
98
  }
99
- }
100
 
101
- return $location;
 
102
  }
103
 
104
- /**
105
- * Removes any NULL characters in $string.
106
- *
107
- * @since 1.0.0
108
- *
109
- * @param string $string
110
- *
111
- * @return string
112
- */
113
- function fs_kses_no_null( $string ) {
114
- $string = preg_replace( '/\0+/', '', $string );
115
- $string = preg_replace( '/(\\\\0)+/', '', $string );
 
116
 
117
- return $string;
 
118
  }
119
  }
120
 
@@ -147,10 +151,15 @@
147
  require_once( ( defined( 'WP_FS__DIR_INCLUDES' ) ? WP_FS__DIR_INCLUDES : dirname( __FILE__ ) ) . '/i18n.php' );
148
  }
149
 
150
- if ( isset( $fs_text_overrides[ $slug ] ) &&
151
- isset( $fs_text_overrides[ $slug ][ $key ] )
152
- ) {
153
- return $fs_text_overrides[ $slug ][ $key ];
 
 
 
 
 
154
  }
155
 
156
  return isset( $fs_text[ $key ] ) ?
@@ -345,6 +354,9 @@
345
  function fs_fallback_to_newest_active_sdk() {
346
  global $fs_active_plugins;
347
 
 
 
 
348
  $newest_sdk_data = null;
349
  $newest_sdk_path = null;
350
 
72
  return true;
73
  }
74
 
75
+ if ( ! function_exists( 'fs_sanitize_redirect' ) ) {
76
+ /**
77
+ * Sanitizes a URL for use in a redirect.
78
+ *
79
+ * @since 2.3
80
+ *
81
+ * @param string $location
82
+ *
83
+ * @return string redirect-sanitized URL
84
+ */
85
+ function fs_sanitize_redirect( $location ) {
86
+ $location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location );
87
+ $location = fs_kses_no_null( $location );
88
+
89
+ // remove %0d and %0a from location
90
+ $strip = array( '%0d', '%0a' );
91
+ $found = true;
92
+ while ( $found ) {
93
+ $found = false;
94
+ foreach ( (array) $strip as $val ) {
95
+ while ( strpos( $location, $val ) !== false ) {
96
+ $found = true;
97
+ $location = str_replace( $val, '', $location );
98
+ }
99
  }
100
  }
 
101
 
102
+ return $location;
103
+ }
104
  }
105
 
106
+ if ( ! function_exists( 'fs_kses_no_null' ) ) {
107
+ /**
108
+ * Removes any NULL characters in $string.
109
+ *
110
+ * @since 1.0.0
111
+ *
112
+ * @param string $string
113
+ *
114
+ * @return string
115
+ */
116
+ function fs_kses_no_null( $string ) {
117
+ $string = preg_replace( '/\0+/', '', $string );
118
+ $string = preg_replace( '/(\\\\0)+/', '', $string );
119
 
120
+ return $string;
121
+ }
122
  }
123
  }
124
 
151
  require_once( ( defined( 'WP_FS__DIR_INCLUDES' ) ? WP_FS__DIR_INCLUDES : dirname( __FILE__ ) ) . '/i18n.php' );
152
  }
153
 
154
+ if ( isset( $fs_text_overrides[ $slug ] ) ) {
155
+ if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
156
+ return $fs_text_overrides[ $slug ][ $key ];
157
+ }
158
+
159
+ $lower_key = strtolower( $key );
160
+ if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
161
+ return $fs_text_overrides[ $slug ][ $lower_key ];
162
+ }
163
  }
164
 
165
  return isset( $fs_text[ $key ] ) ?
354
  function fs_fallback_to_newest_active_sdk() {
355
  global $fs_active_plugins;
356
 
357
+ /**
358
+ * @var object $newest_sdk_data
359
+ */
360
  $newest_sdk_data = null;
361
  $newest_sdk_path = null;
362
 
freemius/includes/fs-plugin-info-dialog.php ADDED
@@ -0,0 +1,930 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ * Class FS_Plugin_Info_Dialog
15
+ *
16
+ * @author Vova Feldman (@svovaf)
17
+ * @since 1.1.7
18
+ */
19
+ class FS_Plugin_Info_Dialog {
20
+ /**
21
+ * @since 1.1.7
22
+ *
23
+ * @var FS_Logger
24
+ */
25
+ private $_logger;
26
+
27
+ /**
28
+ * @since 1.1.7
29
+ *
30
+ * @var Freemius
31
+ */
32
+ private $_fs;
33
+
34
+ function __construct( Freemius $fs ) {
35
+ $this->_fs = $fs;
36
+
37
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
38
+
39
+ // Remove default plugin information action.
40
+ remove_all_actions( 'install_plugins_pre_plugin-information' );
41
+
42
+ // Override action with custom plugins function for add-ons.
43
+ add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
44
+
45
+ // Override request for plugin information for Add-ons.
46
+ add_filter(
47
+ 'fs_plugins_api',
48
+ array( &$this, '_get_addon_info_filter' ),
49
+ WP_FS__DEFAULT_PRIORITY, 3 );
50
+ }
51
+
52
+ /**
53
+ * Generate add-on plugin information.
54
+ *
55
+ * @author Vova Feldman (@svovaf)
56
+ * @since 1.0.6
57
+ *
58
+ * @param array $data
59
+ * @param string $action
60
+ * @param object|null $args
61
+ *
62
+ * @return array|null
63
+ */
64
+ function _get_addon_info_filter( $data, $action = '', $args = null ) {
65
+ $this->_logger->entrance();
66
+
67
+ $parent_plugin_id = fs_request_get( 'parent_plugin_id', false );
68
+
69
+ if ( $this->_fs->get_id() != $parent_plugin_id ||
70
+ ( 'plugin_information' !== $action ) ||
71
+ ! isset( $args->slug )
72
+ ) {
73
+ return $data;
74
+ }
75
+
76
+ // Find add-on by slug.
77
+ $selected_addon = $this->_fs->get_addon_by_slug($args->slug);
78
+
79
+ if ( false === $selected_addon ) {
80
+ return $data;
81
+ }
82
+
83
+ if ( ! isset( $selected_addon->info ) ) {
84
+ // Setup some default info.
85
+ $selected_addon->info = new stdClass();
86
+ $selected_addon->info->selling_point_0 = 'Selling Point 1';
87
+ $selected_addon->info->selling_point_1 = 'Selling Point 2';
88
+ $selected_addon->info->selling_point_2 = 'Selling Point 3';
89
+ $selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
90
+ }
91
+
92
+ fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
93
+
94
+ $data = $args;
95
+
96
+ $is_free = true;
97
+
98
+ // Load add-on pricing.
99
+ $has_pricing = false;
100
+ $has_features = false;
101
+ $plans = false;
102
+ $plans_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans.json" );
103
+ if ( ! isset( $plans_result->error ) ) {
104
+ $plans = $plans_result->plans;
105
+ if ( is_array( $plans ) ) {
106
+ for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
107
+ $plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
108
+ $plan = $plans[ $i ];
109
+
110
+ $pricing_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/pricing.json" );
111
+ if ( ! isset( $pricing_result->error ) ) {
112
+ // Update plan's pricing.
113
+ $plan->pricing = $pricing_result->pricing;
114
+
115
+ if ( is_array( $plan->pricing ) && ! empty( $plan->pricing ) ) {
116
+ $is_free = false;
117
+
118
+ foreach ( $plan->pricing as &$pricing ) {
119
+ $pricing = new FS_Pricing( $pricing );
120
+ }
121
+ }
122
+
123
+ $has_pricing = true;
124
+ }
125
+
126
+ $features_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/features.json" );
127
+ if ( ! isset( $features_result->error ) &&
128
+ is_array( $features_result->features ) &&
129
+ 0 < count( $features_result->features )
130
+ ) {
131
+ // Update plan's pricing.
132
+ $plan->features = $features_result->features;
133
+
134
+ $has_features = true;
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // Fetch latest version from Freemius.
141
+ $latest = $this->_fs->_fetch_latest_version( $selected_addon->id );
142
+
143
+ if ( ! $is_free ) {
144
+ // If paid add-on, then it's not on wordpress.org
145
+ $is_wordpress_org = false;
146
+ } else {
147
+ // If no versions found, then assume it's a .org plugin.
148
+ $is_wordpress_org = ( false === $latest );
149
+ }
150
+
151
+ if ( $is_wordpress_org ) {
152
+ $repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
153
+ 'plugin_information', (object) array(
154
+ 'slug' => $selected_addon->slug,
155
+ 'is_ssl' => is_ssl(),
156
+ 'fields' => array(
157
+ 'banners' => true,
158
+ 'reviews' => true,
159
+ 'downloaded' => false,
160
+ 'active_installs' => true
161
+ )
162
+ ) );
163
+
164
+ if ( ! empty( $repo_data ) ) {
165
+ $data = $repo_data;
166
+ $data->wp_org_missing = false;
167
+ } else {
168
+ // Couldn't find plugin on .org.
169
+ $is_wordpress_org = false;
170
+
171
+ // Plugin is missing, not on Freemius nor WP.org.
172
+ $data->wp_org_missing = true;
173
+ }
174
+ }
175
+
176
+ if ( ! $is_wordpress_org ) {
177
+ $data->checkout_link = $this->_fs->checkout_url();
178
+ $data->fs_missing = ( false === $latest );
179
+
180
+ if ( $is_free ) {
181
+ $data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
182
+ }
183
+ }
184
+
185
+ if ( ! $is_wordpress_org ) {
186
+ // Fetch as much as possible info from local files.
187
+ $plugin_local_data = $this->_fs->get_plugin_data();
188
+ $data->name = $selected_addon->title;
189
+ $data->author = $plugin_local_data['Author'];
190
+ $view_vars = array( 'plugin' => $selected_addon );
191
+ $data->sections = array(
192
+ 'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
193
+ );
194
+
195
+ if ( ! empty( $selected_addon->info->banner_url ) ) {
196
+ $data->banners = array(
197
+ 'low' => $selected_addon->info->banner_url,
198
+ );
199
+ }
200
+
201
+ if ( ! empty( $selected_addon->info->screenshots ) ) {
202
+ $view_vars = array(
203
+ 'screenshots' => $selected_addon->info->screenshots,
204
+ 'plugin' => $selected_addon,
205
+ );
206
+ $data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
207
+ }
208
+
209
+ if ( is_object( $latest ) ) {
210
+ $data->version = $latest->version;
211
+ $data->last_updated = ! is_null( $latest->updated ) ? $latest->updated : $latest->created;
212
+ $data->requires = $latest->requires_platform_version;
213
+ $data->tested = $latest->tested_up_to_version;
214
+ } else {
215
+ // Add dummy version.
216
+ $data->version = '1.0.0';
217
+
218
+ // Add message to developer to deploy the plugin through Freemius.
219
+ }
220
+ }
221
+
222
+ if ( $has_pricing ) {
223
+ // Add plans to data.
224
+ $data->plans = $plans;
225
+
226
+ if ( $has_features ) {
227
+ $view_vars = array(
228
+ 'plans' => $plans,
229
+ 'plugin' => $selected_addon,
230
+ );
231
+ $data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
232
+ }
233
+ }
234
+
235
+ $data->is_paid = ! $is_free;
236
+ $data->external = ! $is_wordpress_org;
237
+
238
+ return $data;
239
+ }
240
+
241
+ /**
242
+ * @author Vova Feldman (@svovaf)
243
+ * @since 1.1.7
244
+ *
245
+ * @param FS_Plugin_Plan $plan
246
+ *
247
+ * @return string
248
+ */
249
+ private function get_billing_cycle( FS_Plugin_Plan $plan ) {
250
+ $billing_cycle = null;
251
+
252
+ if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
253
+ $pricing = $plan->pricing[0];
254
+ if ( isset( $pricing->annual_price ) ) {
255
+ $billing_cycle = 'annual';
256
+ } else if ( isset( $pricing->monthly_price ) ) {
257
+ $billing_cycle = 'monthly';
258
+ } else if ( isset( $pricing->lifetime_price ) ) {
259
+ $billing_cycle = 'lifetime';
260
+ }
261
+ } else {
262
+ foreach ( $plan->pricing as $pricing ) {
263
+ if ( isset( $pricing->annual_price ) ) {
264
+ $billing_cycle = 'annual';
265
+ } else if ( isset( $pricing->monthly_price ) ) {
266
+ $billing_cycle = 'monthly';
267
+ } else if ( isset( $pricing->lifetime_price ) ) {
268
+ $billing_cycle = 'lifetime';
269
+ }
270
+
271
+ if ( ! is_null( $billing_cycle ) ) {
272
+ break;
273
+ }
274
+ }
275
+ }
276
+
277
+ return $billing_cycle;
278
+ }
279
+
280
+ /**
281
+ * @author Vova Feldman (@svovaf)
282
+ * @since 1.1.7
283
+ *
284
+ * @param FS_Plugin_Plan $plan
285
+ * @param FS_Pricing $pricing
286
+ *
287
+ * @return float|null|string
288
+ */
289
+ private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
290
+ $price_tag = '';
291
+ if ( isset( $pricing->annual_price ) ) {
292
+ $price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
293
+ } else if ( isset( $pricing->monthly_price ) ) {
294
+ $price_tag = $pricing->monthly_price . ' / mo';
295
+ } else if ( isset( $pricing->lifetime_price ) ) {
296
+ $price_tag = $pricing->lifetime_price;
297
+ }
298
+
299
+ return '$' . $price_tag;
300
+ }
301
+
302
+ /**
303
+ * @author Vova Feldman (@svovaf)
304
+ * @since 1.1.7
305
+ *
306
+ * @param object $api
307
+ * @param FS_Plugin_Plan|null $plan
308
+ *
309
+ * @return string
310
+ */
311
+ private function get_plugin_cta( $api, $plan = null ) {
312
+ if ( ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
313
+
314
+ if ( ! empty( $api->checkout_link ) && isset( $api->plans ) && 0 < is_array( $api->plans ) ) {
315
+ if ( is_null( $plan ) ) {
316
+ $plan = $api->plans[0];
317
+ }
318
+
319
+ return ' <a class="button button-primary right" href="' . $this->_fs->addon_checkout_url(
320
+ $plan->plugin_id,
321
+ $plan->pricing[0]->id,
322
+ $this->get_billing_cycle( $plan ),
323
+ $plan->has_trial()
324
+ ) . '" target="_parent">' .
325
+ ( ! $plan->has_trial() ?
326
+ __fs( 'purchase', $api->slug ) :
327
+ sprintf( __fs( 'start-free-x', $api->slug ), $this->get_trial_period( $plan ) )
328
+ ) .
329
+ '</a>';
330
+
331
+ // @todo Add Cart concept.
332
+ // echo ' <a class="button right" href="' . $status['url'] . '" target="_parent">' . __( 'Add to Cart' ) . '</a>';
333
+
334
+ } else if ( ! empty( $api->download_link ) ) {
335
+ $status = install_plugin_install_status( $api );
336
+
337
+ // Hosted on WordPress.org.
338
+ switch ( $status['status'] ) {
339
+ case 'install':
340
+ if ( $api->external &&
341
+ $this->_fs->is_org_repo_compliant() ||
342
+ ! $this->_fs->is_premium()
343
+ ) {
344
+ /**
345
+ * Add-on hosted on Freemius, not yet installed, and core
346
+ * plugin is wordpress.org compliant. Therefore, require a download
347
+ * since installing external plugins is not allowed by the wp.org guidelines.
348
+ */
349
+ return ' <a class="button button-primary right" href="' . esc_url( $api->download_link ) . '" target="_blank">' . __fs( 'download-latest', $api->slug ) . '</a>';
350
+ } else {
351
+ if ( $status['url'] ) {
352
+ return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>';
353
+ }
354
+ }
355
+ break;
356
+ case 'update_available':
357
+ if ( $status['url'] ) {
358
+ return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) . '</a>';
359
+ }
360
+ break;
361
+ case 'newer_installed':
362
+ return '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed' ), $status['version'] ) . '</a>';
363
+ break;
364
+ case 'latest_installed':
365
+ return '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>';
366
+ break;
367
+ }
368
+
369
+ }
370
+ }
371
+
372
+ return '';
373
+ }
374
+
375
+ /**
376
+ * @author Vova Feldman (@svovaf)
377
+ * @since 1.1.7
378
+ *
379
+ * @param FS_Plugin_Plan $plan
380
+ *
381
+ * @return string
382
+ */
383
+ private function get_trial_period( $plan ) {
384
+ $trial_period = (int) $plan->trial_period;
385
+
386
+ switch ( $trial_period ) {
387
+ case 30:
388
+ return 'month';
389
+ case 60:
390
+ return '2 months';
391
+ default:
392
+ return "{$plan->trial_period} days";
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Display plugin information in dialog box form.
398
+ *
399
+ * Based on core install_plugin_information() function.
400
+ *
401
+ * @author Vova Feldman (@svovaf)
402
+ * @since 1.0.6
403
+ */
404
+ function install_plugin_information() {
405
+ global $tab;
406
+
407
+ if ( empty( $_REQUEST['plugin'] ) ) {
408
+ return;
409
+ }
410
+
411
+ $args = array(
412
+ 'slug' => wp_unslash( $_REQUEST['plugin'] ),
413
+ 'is_ssl' => is_ssl(),
414
+ 'fields' => array(
415
+ 'banners' => true,
416
+ 'reviews' => true,
417
+ 'downloaded' => false,
418
+ 'active_installs' => true
419
+ )
420
+ );
421
+
422
+ if ( is_array( $args ) ) {
423
+ $args = (object) $args;
424
+ }
425
+
426
+ if ( ! isset( $args->per_page ) ) {
427
+ $args->per_page = 24;
428
+ }
429
+
430
+ if ( ! isset( $args->locale ) ) {
431
+ $args->locale = get_locale();
432
+ }
433
+
434
+ $api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
435
+
436
+ if ( is_wp_error( $api ) ) {
437
+ wp_die( $api );
438
+ }
439
+
440
+ $plugins_allowedtags = array(
441
+ 'a' => array(
442
+ 'href' => array(),
443
+ 'title' => array(),
444
+ 'target' => array(),
445
+ // Add image style for screenshots.
446
+ 'class' => array()
447
+ ),
448
+ 'style' => array(),
449
+ 'abbr' => array( 'title' => array() ),
450
+ 'acronym' => array( 'title' => array() ),
451
+ 'code' => array(),
452
+ 'pre' => array(),
453
+ 'em' => array(),
454
+ 'strong' => array(),
455
+ 'div' => array( 'class' => array() ),
456
+ 'span' => array( 'class' => array() ),
457
+ 'p' => array(),
458
+ 'ul' => array(),
459
+ 'ol' => array(),
460
+ 'li' => array( 'class' => array() ),
461
+ 'i' => array( 'class' => array() ),
462
+ 'h1' => array(),
463
+ 'h2' => array(),
464
+ 'h3' => array(),
465
+ 'h4' => array(),
466
+ 'h5' => array(),
467
+ 'h6' => array(),
468
+ 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
469
+ // 'table' => array(),
470
+ // 'td' => array(),
471
+ // 'tr' => array(),
472
+ // 'th' => array(),
473
+ // 'thead' => array(),
474
+ // 'tbody' => array(),
475
+ );
476
+
477
+ $plugins_section_titles = array(
478
+ 'description' => _x( 'Description', 'Plugin installer section title' ),
479
+ 'installation' => _x( 'Installation', 'Plugin installer section title' ),
480
+ 'faq' => _x( 'FAQ', 'Plugin installer section title' ),
481
+ 'screenshots' => _x( 'Screenshots', 'Plugin installer section title' ),
482
+ 'changelog' => _x( 'Changelog', 'Plugin installer section title' ),
483
+ 'reviews' => _x( 'Reviews', 'Plugin installer section title' ),
484
+ 'other_notes' => _x( 'Other Notes', 'Plugin installer section title' ),
485
+ );
486
+
487
+ // Sanitize HTML
488
+ // foreach ( (array) $api->sections as $section_name => $content ) {
489
+ // $api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
490
+ // }
491
+
492
+ foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
493
+ if ( isset( $api->$key ) ) {
494
+ $api->$key = wp_kses( $api->$key, $plugins_allowedtags );
495
+ }
496
+ }
497
+
498
+ // Add after $api->slug is ready.
499
+ $plugins_section_titles['features'] = __fs( 'features-and-pricing', $api->slug );
500
+
501
+ $_tab = esc_attr( $tab );
502
+
503
+ $section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
504
+ if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
505
+ $section_titles = array_keys( (array) $api->sections );
506
+ $section = array_shift( $section_titles );
507
+ }
508
+
509
+ iframe_header( __( 'Plugin Install' ) );
510
+
511
+ $_with_banner = '';
512
+
513
+ // var_dump($api->banners);
514
+ if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
515
+ $_with_banner = 'with-banner';
516
+ $low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
517
+ $high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
518
+ ?>
519
+ <style type="text/css">
520
+ #plugin-information-title.with-banner
521
+ {
522
+ background-image: url( <?php echo esc_url( $low ); ?> );
523
+ }
524
+
525
+ @media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
526
+ {
527
+ #plugin-information-title.with-banner
528
+ {
529
+ background-image: url( <?php echo esc_url( $high ); ?> );
530
+ }
531
+ }
532
+ </style>
533
+ <?php
534
+ }
535
+
536
+ echo '<div id="plugin-information-scrollable">';
537
+ echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
538
+ echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
539
+
540
+ foreach ( (array) $api->sections as $section_name => $content ) {
541
+ if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
542
+ continue;
543
+ }
544
+
545
+ if ( isset( $plugins_section_titles[ $section_name ] ) ) {
546
+ $title = $plugins_section_titles[ $section_name ];
547
+ } else {
548
+ $title = ucwords( str_replace( '_', ' ', $section_name ) );
549
+ }
550
+
551
+ $class = ( $section_name === $section ) ? ' class="current"' : '';
552
+ $href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
553
+ $href = esc_url( $href );
554
+ $san_section = esc_attr( $section_name );
555
+ echo "\t<a name='$san_section' href='$href' $class>$title</a>\n";
556
+ }
557
+
558
+ echo "</div>\n";
559
+
560
+ ?>
561
+ <div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
562
+ <div class="fyi">
563
+ <?php if ( $api->is_paid ) : ?>
564
+ <?php if ( isset( $api->plans ) ) : ?>
565
+ <div class="plugin-information-pricing">
566
+ <?php foreach ( $api->plans as $plan ) : ?>
567
+ <?php
568
+ /**
569
+ * @var FS_Plugin_Plan $plan
570
+ */
571
+ ?>
572
+ <?php $first_pricing = $plan->pricing[0] ?>
573
+ <?php $is_multi_cycle = $first_pricing->is_multi_cycle() ?>
574
+ <div class="fs-plan<?php if ( ! $is_multi_cycle ) {
575
+ echo ' fs-single-cycle';
576
+ } ?>" data-plan-id="<?php echo $plan->id ?>">
577
+ <h3 data-plan="<?php echo $plan->id ?>"><?php printf( __fs( 'x-plan', $api->slug ), $plan->title ) ?></h3>
578
+ <?php $has_annual = $first_pricing->has_annual() ?>
579
+ <?php $has_monthly = $first_pricing->has_monthly() ?>
580
+ <div class="nav-tab-wrapper">
581
+ <?php $billing_cycles = array( 'monthly', 'annual', 'lifetime' ) ?>
582
+ <?php $i = 0;
583
+ foreach ( $billing_cycles as $cycle ) : ?>
584
+ <?php $prop = "{$cycle}_price";
585
+ if ( isset( $first_pricing->{$prop} ) ) : ?>
586
+ <?php $is_featured = ( 'annual' === $cycle && $is_multi_cycle ) ?>
587
+ <?php
588
+ $prices = array();
589
+ foreach ( $plan->pricing as $pricing ) {
590
+ if ( isset( $pricing->{$prop} ) ) {
591
+ $prices[] = array(
592
+ 'id' => $pricing->id,
593
+ 'licenses' => $pricing->licenses,
594
+ 'price' => $pricing->{$prop}
595
+ );
596
+ }
597
+ }
598
+ ?>
599
+ <a class="nav-tab" data-billing-cycle="<?php echo $cycle ?>"
600
+ data-pricing="<?php esc_attr_e( json_encode( $prices ) ) ?>">
601
+ <?php if ( $is_featured ) : ?>
602
+ <label>&#9733; <?php _efs( 'best', $api->slug ) ?> &#9733;</label>
603
+ <?php endif ?>
604
+ <?php _efs( $cycle, $api->slug ) ?>
605
+ </a>
606
+ <?php endif ?>
607
+ <?php $i ++; endforeach ?>
608
+ <?php wp_enqueue_script( 'jquery' ) ?>
609
+ <script type="text/javascript">
610
+ (function ($, undef) {
611
+ var
612
+ _formatBillingFrequency = function (cycle) {
613
+ switch (cycle) {
614
+ case 'monthly':
615
+ return '<?php printf(__fs('billed-x', $api->slug), __fs('monthly', $api->slug)) ?>';
616
+ case 'annual':
617
+ return '<?php printf(__fs('billed-x', $api->slug), __fs('annually', $api->slug)) ?>';
618
+ case 'lifetime':
619
+ return '<?php printf(__fs('billed-x', $api->slug), __fs('once', $api->slug)) ?>';
620
+ }
621
+ },
622
+ _formatLicensesTitle = function (pricing) {
623
+ switch (pricing.licenses) {
624
+ case 1:
625
+ return '<?php _efs( 'license-single-site', $api->slug ) ?>';
626
+ case null:
627
+ return '<?php _efs( 'license-unlimited', $api->slug ) ?>';
628
+ default:
629
+ return '<?php _efs( 'license-x-sites', $api->slug ) ?>'.replace('%s', pricing.licenses);
630
+ }
631
+ },
632
+ _formatPrice = function (pricing, cycle, multipleLicenses) {
633
+ if (undef === multipleLicenses)
634
+ multipleLicenses = true;
635
+
636
+ var priceCycle;
637
+ switch (cycle) {
638
+ case 'monthly':
639
+ priceCycle = ' / <?php _efs('mo', $api->slug) ?>';
640
+ break;
641
+ case 'lifetime':
642
+ priceCycle = '';
643
+ break;
644
+ case 'annual':
645
+ default:
646
+ priceCycle = ' / <?php _efs('year', $api->slug) ?>';
647
+ break;
648
+ }
649
+
650
+ if (!multipleLicenses && 1 == pricing.licenses) {
651
+ return '$' + pricing.price + priceCycle;
652
+ }
653
+
654
+ return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
655
+ },
656
+ _checkoutUrl = function (plan, pricing, cycle) {
657
+ return '<?php echo esc_url_raw(remove_query_arg('billing_cycle', add_query_arg(array('plugin_id' => $plan->plugin_id), $api->checkout_link))) ?>' +
658
+ '&plan_id=' + plan +
659
+ '&pricing_id=' + pricing +
660
+ '&billing_cycle=' + cycle<?php if ($plan->has_trial()) { echo " + '&trial=true'"; }?>;
661
+ },
662
+ _updateCtaUrl = function (plan, pricing, cycle) {
663
+ $('.plugin-information-pricing .button, #plugin-information-footer .button').attr('href', _checkoutUrl(plan, pricing, cycle));
664
+ };
665
+
666
+ $(document).ready(function () {
667
+ var $plan = $('.plugin-information-pricing .fs-plan[data-plan-id=<?php echo $plan->id ?>]');
668
+ $plan.find('input[type=radio]').live('click', function () {
669
+ _updateCtaUrl(
670
+ $plan.attr('data-plan-id'),
671
+ $(this).val(),
672
+ $plan.find('.nav-tab-active').attr('data-billing-cycle')
673
+ );
674
+
675
+ $plan.find('.fs-trial-terms .fs-price').html(
676
+ $(this).parents('label').find('.fs-price').html()
677
+ );
678
+ });
679
+
680
+ $plan.find('.nav-tab').click(function () {
681
+ if ($(this).hasClass('nav-tab-active'))
682
+ return;
683
+
684
+ var $this = $(this),
685
+ billingCycle = $this.attr('data-billing-cycle'),
686
+ pricing = JSON.parse($this.attr('data-pricing')),
687
+ $pricesList = $this.parents('.fs-plan').find('.fs-pricing-body .fs-licenses'),
688
+ html = '';
689
+
690
+ // Un-select previously selected tab.
691
+ $plan.find('.nav-tab').removeClass('nav-tab-active');
692
+
693
+ // Select current tab.
694
+ $this.addClass('nav-tab-active');
695
+
696
+ // Render licenses prices.
697
+ if (1 == pricing.length) {
698
+ html = '<li><label><?php _efs( 'price', $api->slug ) ?>: ' + _formatPrice(pricing[0], billingCycle, false) + '</label></li>';
699
+ } else {
700
+ for (var i = 0; i < pricing.length; i++) {
701
+ html += '<li><label><input name="pricing-<?php echo $plan->id ?>" type="radio" value="' + pricing[i].id + '">' + _formatPrice(pricing[i], billingCycle) + '</label></li>';
702
+ }
703
+ }
704
+ $pricesList.html(html);
705
+
706
+ if (1 < pricing.length) {
707
+ // Select first license option.
708
+ $pricesList.find('li:first input').click();
709
+ }
710
+ else {
711
+ _updateCtaUrl(
712
+ $plan.attr('data-plan-id'),
713
+ pricing[0].id,
714
+ billingCycle
715
+ );
716
+ }
717
+
718
+ // Update billing frequency.
719
+ $plan.find('.fs-billing-frequency').html(_formatBillingFrequency(billingCycle));
720
+
721
+ if ('annual' === billingCycle) {
722
+ $plan.find('.fs-annual-discount').show();
723
+ } else {
724
+ $plan.find('.fs-annual-discount').hide();
725
+ }
726
+ });
727
+
728
+ <?php if ( $has_annual ) : ?>
729
+ // Select annual by default.
730
+ $plan.find('.nav-tab[data-billing-cycle=annual]').click();
731
+ <?php else : ?>
732
+ // Select first tab.
733
+ $plan.find('.nav-tab:first').click();
734
+ <?php endif ?>
735
+ });
736
+ }(jQuery));
737
+ </script>
738
+ </div>
739
+ <div class="fs-pricing-body">
740
+ <span class="fs-billing-frequency"></span>
741
+ <?php $annual_discount = ( $has_annual && $has_monthly ) ? $plan->pricing[0]->annual_discount_percentage() : 0 ?>
742
+ <?php if ( $annual_discount > 0 ) : ?>
743
+ <span
744
+ class="fs-annual-discount"><?php printf( __fs( 'save-x', $api->slug ), $annual_discount . '%' ) ?></span>
745
+ <?php endif ?>
746
+ <ul class="fs-licenses">
747
+ </ul>
748
+ <?php echo $this->get_plugin_cta( $api, $plan ) ?>
749
+ <div style="clear:both"></div>
750
+ <?php if ( $plan->has_trial() ) : ?>
751
+ <?php $trial_period = $this->get_trial_period( $plan ) ?>
752
+ <ul class="fs-trial-terms">
753
+ <li>
754
+ <i class="dashicons dashicons-yes"></i><?php printf( __fs( 'no-commitment-x', $api->slug ), $trial_period ) ?>
755
+ </li>
756
+ <li>
757
+ <i class="dashicons dashicons-yes"></i><?php printf( __fs( 'after-x-pay-as-little-y', $api->slug ), $trial_period, '<var class="fs-price">' . $this->get_price_tag( $plan, $plan->pricing[0] ) . '</var>' ) ?>
758
+ </li>
759
+ </ul>
760
+ <?php endif ?>
761
+ </div>
762
+ </div>
763
+ </div>
764
+ <?php endforeach ?>
765
+ <?php endif ?>
766
+ <?php endif ?>
767
+ <div>
768
+ <h3><?php _efs( 'details', $api->slug ) ?></h3>
769
+ <ul>
770
+ <?php if ( ! empty( $api->version ) ) { ?>
771
+ <li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li>
772
+ <?php
773
+ }
774
+ if ( ! empty( $api->author ) ) {
775
+ ?>
776
+ <li>
777
+ <strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
778
+ </li>
779
+ <?php
780
+ }
781
+ if ( ! empty( $api->last_updated ) ) {
782
+ ?>
783
+ <li><strong><?php _e( 'Last Updated:' ); ?></strong> <span
784
+ title="<?php echo $api->last_updated; ?>">
785
+ <?php printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?>
786
+ </span></li>
787
+ <?php
788
+ }
789
+ if ( ! empty( $api->requires ) ) {
790
+ ?>
791
+ <li>
792
+ <strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php printf( __( '%s or higher' ), $api->requires ); ?>
793
+ </li>
794
+ <?php
795
+ }
796
+ if ( ! empty( $api->tested ) ) {
797
+ ?>
798
+ <li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?>
799
+ </li>
800
+ <?php
801
+ }
802
+ if ( ! empty( $api->downloaded ) ) {
803
+ ?>
804
+ <li>
805
+ <strong><?php _e( 'Downloaded:' ); ?></strong> <?php printf( _n( '%s time', '%s times', $api->downloaded ), number_format_i18n( $api->downloaded ) ); ?>
806
+ </li>
807
+ <?php
808
+ }
809
+ if ( ! empty( $api->slug ) && empty( $api->external ) ) {
810
+ ?>
811
+ <li><a target="_blank"
812
+ href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php _e( 'WordPress.org Plugin Page &#187;' ); ?></a>
813
+ </li>
814
+ <?php
815
+ }
816
+ if ( ! empty( $api->homepage ) ) {
817
+ ?>
818
+ <li><a target="_blank"
819
+ href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage &#187;' ); ?></a>
820
+ </li>
821
+ <?php
822
+ }
823
+ if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) {
824
+ ?>
825
+ <li><a target="_blank"
826
+ href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
827
+ </li>
828
+ <?php } ?>
829
+ </ul>
830
+ </div>
831
+ <?php if ( ! empty( $api->rating ) ) { ?>
832
+ <h3><?php _e( 'Average Rating' ); ?></h3>
833
+ <?php wp_star_rating( array(
834
+ 'rating' => $api->rating,
835
+ 'type' => 'percent',
836
+ 'number' => $api->num_ratings
837
+ ) ); ?>
838
+ <small><?php printf( _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?></small>
839
+ <?php
840
+ }
841
+
842
+ if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
843
+ foreach ( $api->ratings as $key => $ratecount ) {
844
+ // Avoid div-by-zero.
845
+ $_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
846
+ ?>
847
+ <div class="counter-container">
848
+ <span class="counter-label"><a
849
+ href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
850
+ target="_blank"
851
+ 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>
852
+ <span class="counter-back">
853
+ <span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span>
854
+ </span>
855
+ <span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
856
+ </div>
857
+ <?php
858
+ }
859
+ }
860
+ if ( ! empty( $api->contributors ) ) {
861
+ ?>
862
+ <h3><?php _e( 'Contributors' ); ?></h3>
863
+ <ul class="contributors">
864
+ <?php
865
+ foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
866
+ if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
867
+ continue;
868
+ }
869
+ if ( empty( $contrib_username ) ) {
870
+ $contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
871
+ }
872
+ $contrib_username = sanitize_user( $contrib_username );
873
+ if ( empty( $contrib_profile ) ) {
874
+ echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</li>";
875
+ } else {
876
+ 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>";
877
+ }
878
+ }
879
+ ?>
880
+ </ul>
881
+ <?php if ( ! empty( $api->donate_link ) ) { ?>
882
+ <a target="_blank"
883
+ href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
884
+ <?php } ?>
885
+ <?php } ?>
886
+ </div>
887
+ <div id="section-holder" class="wrap">
888
+ <?php
889
+ if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
890
+ echo '<div class="notice notice-warning"><p>' . '<strong>' . __( 'Warning:' ) . '</strong> ' . __( 'This plugin has not been tested with your current version of WordPress.' ) . '</p></div>';
891
+ } else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
892
+ 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>';
893
+ }
894
+
895
+ foreach ( (array) $api->sections as $section_name => $content ) {
896
+ $content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
897
+ $content = links_add_target( $content, '_blank' );
898
+
899
+ $san_section = esc_attr( $section_name );
900
+
901
+ $display = ( $section_name === $section ) ? 'block' : 'none';
902
+
903
+ if ( 'description' === $section_name &&
904
+ ( ( ! $api->external && $api->wp_org_missing ) ||
905
+ ( $api->external && $api->fs_missing ) )
906
+ ) {
907
+ $missing_notice = array(
908
+ 'type' => 'error',
909
+ 'id' => md5( microtime() ),
910
+ 'message' => __fs( ( $api->is_paid ? 'paid-addon-not-deployed' : 'free-addon-not-deployed' ), $api->slug ),
911
+ );
912
+ fs_require_template( 'admin-notice.php', $missing_notice );
913
+ }
914
+ echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
915
+ echo $content;
916
+ echo "\t</div>\n";
917
+ }
918
+ echo "</div>\n";
919
+ echo "</div>\n";
920
+ echo "</div>\n"; // #plugin-information-scrollable
921
+ echo "<div id='$tab-footer'>\n";
922
+
923
+ echo $this->get_plugin_cta( $api );
924
+
925
+ echo "</div>\n";
926
+
927
+ iframe_footer();
928
+ exit;
929
+ }
930
+ }
freemius/includes/i18n.php CHANGED
@@ -1,299 +1,390 @@
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
-
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- exit;
11
- }
12
-
13
- /**
14
- * All strings can now be overridden.
15
- *
16
- * For example, if we want to override:
17
- * 'you-are-step-away' => 'You are just one step away - %s',
18
- *
19
- * We can use the filter:
20
- * fs_override_i18n( array(
21
- * 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
22
- * 'skip' => __( 'Not today', '{your-text_domain}' ),
23
- * ), '{plugin_slug}' );
24
- *
25
- * Or with the Freemius instance:
26
- *
27
- * my_freemius->override_i18n( array(
28
- * 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
29
- * 'skip' => __( 'Not today', '{your-text_domain}' ),
30
- * );
31
- */
32
- global $fs_text;
33
-
34
- $fs_text = array(
35
- 'account' => __( 'Account', 'freemius' ),
36
- 'addon' => __( 'Add On', 'freemius' ),
37
- 'contact-us' => __( 'Contact Us', 'freemius' ),
38
- 'change-ownership' => __( 'Change Ownership', 'freemius' ),
39
- 'support' => __( 'Support', 'freemius' ),
40
- 'support-forum' => __( 'Support Forum', 'freemius' ),
41
- 'add-ons' => __( 'Add Ons', 'freemius' ),
42
- 'upgrade' => _x( 'Upgrade', 'verb', 'freemius' ),
43
- 'awesome' => __( 'Awesome', 'freemius' ),
44
- 'pricing' => _x( 'Pricing', 'noun', 'freemius' ),
45
- 'price' => _x( 'Price', 'noun', 'freemius' ),
46
- 'unlimited-updates' => __( 'Unlimited Updates', 'freemius' ),
47
- 'downgrade' => _x( 'Downgrade', 'verb', 'freemius' ),
48
- 'free-trial' => __( 'Free Trial', 'freemius' ),
49
- 'details' => __( 'Details', 'freemius' ),
50
- 'account-details' => __( 'Account Details', 'freemius' ),
51
- 'delete' => _x( 'Delete', 'verb', 'freemius' ),
52
- 'delete-account' => __( 'Delete Account', 'freemius' ),
53
- 'dismiss' => _x( 'Dismiss', 'as close a window', 'freemius' ),
54
- 'plan' => _x( 'Plan', 'as product pricing plan', 'freemius' ),
55
- 'change-plan' => __( 'Change Plan', 'freemius' ),
56
- 'download-x-version' => _x( 'Download %s Version', 'as download professional version', 'freemius' ),
57
- 'download-x-version-now' => _x( 'Download %s version now', 'as download professional version now', 'freemius' ),
58
- 'download-latest' => _x( 'Download Latest', 'as download latest version', 'freemius' ),
59
- 'you-have-x-license' => _x( 'You have a %s license.', 'E.g. you have a professional license.', 'freemius' ),
60
- 'new' => __( 'New', 'freemius' ),
61
- 'free' => __( 'Free', 'freemius' ),
62
- 'trial' => _x( 'Trial', 'as trial plan', 'freemius' ),
63
- 'purchase' => _x( 'Purchase', 'verb', 'freemius' ),
64
- 'license-single-site' => __( 'Single Site License', 'freemius' ),
65
- 'license-unlimited' => __( 'Unlimited Licenses', 'freemius' ),
66
- 'license-x-sites' => __( 'Up to %s Sites', 'freemius' ),
67
- 'renew-license-now' => __( '%sRenew your license now%s to access version %s features and support.', 'freemius' ),
68
- 'x-plan' => _x( '%s Plan', 'e.g. Professional Plan', 'freemius' ),
69
- 'you-are-step-away' => __( 'You are just one step away - %s', 'freemius' ),
70
- 'activate-x-now' => _x( 'Complete "%s" Activation Now', '%s - plugin name. As complete "Jetpack" activation now', 'freemius' ),
71
- 'few-plugin-tweaks' => __( 'We made a few tweaks to the plugin, %s', 'freemius' ),
72
- 'optin-x-now' => __( 'Opt-in to make "%s" Better!', 'freemius' ),
73
- 'error' => __( 'Error', 'freemius' ),
74
- 'failed-finding-main-path' => __( 'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.', 'freemius' ),
75
- #region Account
76
-
77
- 'expiration' => _x( 'Expiration', 'as expiration date', 'freemius' ),
78
- 'not-verified' => __( 'not verified', 'freemius' ),
79
- 'verify-email' => __( 'Verify Email', 'freemius' ),
80
- 'expires-in' => _x( 'Expires in %s', 'e.g. expires in 2 months', 'freemius' ),
81
- 'renews-in' => _x( 'Auto renews in %s', 'e.g. auto renews in 2 months', 'freemius' ),
82
- 'no-expiration' => __( 'No expiration', 'freemius' ),
83
- 'expired' => __( 'Expired', 'freemius' ),
84
- 'in-x' => __( 'In %s', 'freemius' ),
85
- 'version' => _x( 'Version', 'as plugin version', 'freemius' ),
86
- 'name' => __( 'Name', 'freemius' ),
87
- 'email' => __( 'Email', 'freemius' ),
88
- 'verified' => __( 'Verified', 'freemius' ),
89
- 'plugin' => __( 'Plugin', 'freemius' ),
90
- 'plugins' => __( 'Plugins', 'freemius' ),
91
- 'path' => _x( 'Path', 'as file/folder path', 'freemius' ),
92
- 'title' => __( 'Title', 'freemius' ),
93
- 'slug' => _x( 'Slug', 'as WP plugin slug', 'freemius' ),
94
- 'id' => __( 'ID', 'freemius' ),
95
- 'users' => __( 'Users', 'freemius' ),
96
- 'plugin-installs' => __( 'Plugin Installs', 'freemius' ),
97
- 'sites' => _x( 'Sites', 'like websites', 'freemius' ),
98
- 'user-id' => __( 'User ID', 'freemius' ),
99
- 'site-id' => __( 'Site ID', 'freemius' ),
100
- 'public-key' => __( 'Public Key', 'freemius' ),
101
- 'secret-key' => __( 'Secret Key', 'freemius' ),
102
- 'no-secret' => _x( 'No Secret', 'as secret encryption key missing', 'freemius' ),
103
- 'no-id' => __( 'No ID', 'freemius' ),
104
- 'sync-license' => _x( 'Sync License', 'as synchronize license', 'freemius' ),
105
- 'sync' => _x( 'Sync', 'as synchronize', 'freemius' ),
106
- 'deactivate-license' => __( 'Deactivate License', 'freemius' ),
107
- 'activate' => __( 'Activate', 'freemius' ),
108
- 'deactivate' => __( 'Deactivate', 'freemius' ),
109
- 'active' => _x( 'Active', 'active mode', 'freemius' ),
110
- 'is-active' => _x( 'Is Active', 'is active mode?', 'freemius' ),
111
- 'install-now' => __( 'Install Now', 'freemius' ),
112
- 'install-update-now' => __( 'Install Update Now', 'freemius' ),
113
- 'more-information-about-x' => __( 'More information about %s', 'freemius' ),
114
- 'localhost' => __( 'Localhost', 'freemius' ),
115
- 'activate-x-plan' => _x( 'Activate %s Plan', 'as activate Professional plan', 'freemius' ),
116
- 'what-is-your-x' => __( 'What is your %s?', 'freemius' ),
117
- 'activate-this-addon' => __( 'Activate this add-on', 'freemius' ),
118
- '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' ),
119
- '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' ),
120
- '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' ),
121
- 'downgrade-x-confirm' => __( 'Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s.', 'freemius' ),
122
- 'after-downgrade-non-blocking' => __( 'You can still enjoy all %s features but you will not have access to plugin updates and support.', 'freemius' ),
123
- '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' ),
124
- 'proceed-confirmation' => __( 'Are you sure you want to proceed?', 'freemius' ),
125
- #endregion Account
126
-
127
- 'add-ons-for-x' => __( 'Add Ons for %s', 'freemius' ),
128
- #region Plugin Deactivation
129
- 'deactivation-share-reason' => __( 'If you have a moment, please let us know why you are deactivating', 'freemius' ),
130
- 'deactivation-modal-button-deactivate' => __( 'Deactivate', 'freemius' ),
131
- 'deactivation-modal-button-confirm' => __( 'Yes - Deactivate', 'freemius' ),
132
- 'deactivation-modal-button-submit' => __( 'Submit & Deactivate', 'freemius' ),
133
- 'deactivation-modal-button-cancel' => _x( 'Cancel', 'the text of the cancel button of the plugin deactivation dialog box.', 'freemius' ),
134
- 'reason-no-longer-needed' => __( 'I no longer need the plugin', 'freemius' ),
135
- 'reason-found-a-better-plugin' => __( 'I found a better plugin', 'freemius' ),
136
- 'reason-needed-for-a-short-period' => __( 'I only needed the plugin for a short period', 'freemius' ),
137
- 'reason-broke-my-site' => __( 'The plugin broke my site', 'freemius' ),
138
- 'reason-suddenly-stopped-working' => __( 'The plugin suddenly stopped working', 'freemius' ),
139
- 'reason-cant-pay-anymore' => __( "I can't pay for it anymore", 'freemius' ),
140
- 'reason-other' => _x( 'Other', 'the text of the "other" reason for deactivating the plugin that is shown in the modal box.', 'freemius' ),
141
- 'placeholder-plugin-name' => __( "What's the plugin's name?", 'freemius' ),
142
- 'placeholder-comfortable-price' => __( 'What price would you feel comfortable paying?', 'freemius' ),
143
- 'reason-couldnt-make-it-work' => __( "I couldn't understand how to make it work", 'freemius' ),
144
- 'reason-great-but-need-specific-feature' => __( "The plugin is great, but I need specific feature that you don't support", 'freemius' ),
145
- 'reason-not-working' => __( 'The plugin is not working', 'freemius' ),
146
- 'reason-not-what-i-was-looking-for' => __( "It's not what I was looking for", 'freemius' ),
147
- 'reason-didnt-work-as-expected' => __( "The plugin didn't work as expected", 'freemius' ),
148
- 'placeholder-feature' => __( 'What feature?', 'freemius' ),
149
- 'placeholder-share-what-didnt-work' => __( "Kindly share what didn't work so we can fix it for future users...", 'freemius' ),
150
- 'placeholder-what-youve-been-looking-for' => __( "What you've been looking for?", 'freemius' ),
151
- 'placeholder-what-did-you-expect' => __( "What did you expect?", 'freemius' ),
152
- 'reason-didnt-work' => __( "The plugin didn't work", 'freemius' ),
153
- 'reason-dont-like-to-share-my-information' => __( "I don't like to share my information with you", 'freemius' ),
154
- #endregion Plugin Deactivation
155
-
156
- #region Connect
157
- 'hey-x' => _x( 'Hey %s,', 'greeting', 'freemius' ),
158
- 'thanks-x' => _x( 'Thanks %s!', 'a greeting. E.g. Thanks John!', 'freemius' ),
159
- 'connect-message' => __( 'In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s', 'freemius' ),
160
- 'connect-message_on-update' => __( 'Please help us improve %2$s! If you opt-in, some data about your usage of %2$s will be sent to %5$s. If you skip this, that\'s okay! %2$s will still work just fine.', 'freemius' ),
161
- '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' ),
162
- 'what-permissions' => __( 'What permissions are being granted?', 'freemius' ),
163
- 'permissions-profile' => __( 'Your Profile Overview', 'freemius' ),
164
- 'permissions-profile_desc' => __( 'Name and email address', 'freemius' ),
165
- 'permissions-site' => __( 'Your Site Overview', 'freemius' ),
166
- 'permissions-site_desc' => __( 'Site address, WordPress version, PHP Version', 'freemius' ),
167
- 'permissions-events' => __( 'Plugin Events', 'freemius' ),
168
- 'permissions-events_desc' => __( 'Activation, deactivation and uninstall', 'freemius' ),
169
- 'permissions-newsletter' => __( 'Newsletter', 'freemius' ),
170
- 'permissions-newsletter_desc' => __( 'Updates, announcements, marketing, no spam', 'freemius' ),
171
- 'privacy-policy' => __( 'Privacy Policy', 'freemius' ),
172
- 'tos' => __( 'Terms of Service', 'freemius' ),
173
- 'activating' => _x( 'Activating', 'as activating plugin', 'freemius' ),
174
- 'sending-email' => _x( 'Sending email', 'as in the process of sending an email', 'freemius' ),
175
- 'opt-in-connect' => _x( 'Allow & Continue', 'button label', 'freemius' ),
176
- 'skip' => _x( 'Skip', 'verb', 'freemius' ),
177
- 'resend-activation-email' => __( 'Re-send activation email', 'freemius' ),
178
- #endregion Connect
179
-
180
- #region Screenshots
181
- 'screenshots' => __( 'Screenshots', 'freemius' ),
182
- 'view-full-size-x' => __( 'Click to view full-size screenshot %d', 'freemius' ),
183
- #endregion Screenshots
184
-
185
- #region Debug
186
- 'freemius-debug' => __( 'Freemius Debug', 'freemius' ),
187
- 'on' => _x( 'On', 'as turned on', 'freemius' ),
188
- 'off' => _x( 'Off', 'as turned off', 'freemius' ),
189
- 'freemius-state' => __( 'Freemius State', 'freemius' ),
190
- 'connected' => _x( 'Connected', 'as connection was successful', 'freemius' ),
191
- 'blocked' => _x( 'Blocked', 'as connection blocked', 'freemius' ),
192
- 'api' => _x( 'API', 'as application program interface', 'freemius' ),
193
- 'sdk' => _x( 'SDK', 'as software development kit versions', 'freemius' ),
194
- 'sdk-versions' => _x( 'SDK Versions', 'as software development kit versions', 'freemius' ),
195
- 'plugin-path' => _x( 'Plugin Path', 'as plugin folder path', 'freemius' ),
196
- 'sdk-path' => _x( 'SDK Path', 'as sdk path', 'freemius' ),
197
- 'addons-of-x' => __( 'Add Ons of Plugin %s', 'freemius' ),
198
- 'delete-all-confirm' => __( 'Are you sure you want to delete the all Freemius data?', 'freemius' ),
199
- 'actions' => __( 'Actions', 'freemius' ),
200
- 'delete-all-accounts' => __( 'Delete All Accounts', 'freemius' ),
201
- 'clear-api-cache' => __( 'Clear API Cache', 'freemius' ),
202
- 'sync-data-from-server' => __( 'Sync Data From Server', 'freemius' ),
203
- #endregion Debug
204
-
205
- #region Expressions
206
- 'congrats' => _x( 'Congrats', 'as congratulations', 'freemius' ),
207
- 'oops' => _x( 'Oops', 'exclamation', 'freemius' ),
208
- 'yee-haw' => _x( 'Yee-haw', 'interjection expressing joy or exuberance', 'freemius' ),
209
- 'woot' => _x( 'W00t', '(especially in electronic communication) used to express elation, enthusiasm, or triumph.', 'freemius' ),
210
- 'right-on' => _x( 'Right on', 'a positive response', 'freemius' ),
211
- 'hmm' => _x( 'Hmm', 'something somebody says when they are thinking about what you have just said. ', 'freemius' ),
212
- 'ok' => __( 'O.K', 'freemius' ),
213
- 'hey' => _x( 'Hey', 'exclamation', 'freemius' ),
214
- 'heads-up' => _x( 'Heads up', 'advance notice of something that will need attention.', 'freemius' ),
215
- #endregion Expressions
216
-
217
- #region Admin Notices
218
- 'you-have-latest' => __( 'Seems like you got the latest release.', 'freemius' ),
219
- 'you-are-good' => __( 'You are all good!', 'freemius' ),
220
- 'user-exist-message' => __( 'Sorry, we could not complete the email update. Another user with the same email is already registered.', 'freemius' ),
221
- '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' ),
222
- 'email-updated-message' => __( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.', 'freemius' ),
223
- 'name-updated-message' => __( 'Your name was successfully updated.', 'freemius' ),
224
- 'x-updated' => __( 'You have successfully updated your %s.', 'freemius' ),
225
- 'name-update-failed-message' => __( 'Please provide your full name.', 'freemius' ),
226
- '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' ),
227
- 'addons-info-external-message' => __( 'Just letting you know that the add-ons information of %s is being pulled from external server.', 'freemius' ),
228
- 'no-cc-required' => __( 'No credit card required', 'freemius' ),
229
- 'premium-activated-message' => __( 'Premium plugin version was successfully activated.', 'freemius' ),
230
- 'successful-version-upgrade-message' => __( 'The upgrade of %s was successfully completed.', 'freemius' ),
231
- 'activation-with-plan-x-message' => __( 'Your account was successfully activated with the %s plan.', 'freemius' ),
232
- 'download-latest-x-version' => __( 'Download the latest %s version now', 'freemius' ),
233
- 'download-latest-version' => __( 'Download the latest version now', 'freemius' ),
234
- 'addon-successfully-purchased-message' => _x( '%s Add-on was successfully purchased.', '%s - product name, e.g. Facebook add-on was successfully...', 'freemius' ),
235
- 'addon-successfully-upgraded-message' => __( 'Your %s Add-on plan was successfully upgraded.', 'freemius' ),
236
- 'email-verified-message' => __( 'Your email has been successfully verified - you are AWESOME!', 'freemius' ),
237
- 'plan-upgraded-message' => __( 'Your plan was successfully upgraded.', 'freemius' ),
238
- 'plan-changed-to-x-message' => __( 'Your plan was successfully changed to %s.', 'freemius' ),
239
- 'license-expired-blocking-message' => __( 'Your license has expired. You can still continue using the free plugin forever.', 'freemius' ),
240
- 'trial-started-message' => __( 'Your trial has been successfully started.', 'freemius' ),
241
- 'license-activated-message' => __( 'Your license was successfully activated.', 'freemius' ),
242
- 'no-active-license-message' => __( 'It looks like your site currently don\'t have an active license.', 'freemius' ),
243
- 'license-deactivation-message' => __( 'Your license was successfully deactivated, you are back to the %s plan.', 'freemius' ),
244
- 'license-deactivation-failed-message' => __( 'It looks like the license deactivation failed.', 'freemius' ),
245
- 'license-activation-failed-message' => __( 'It looks like the license could not be activated.', 'freemius' ),
246
- 'server-error-message' => __( 'Error received from the server:', 'freemius' ),
247
- 'trial-expired-message' => __( 'Your trial has expired. You can still continue using all our free features.', 'freemius' ),
248
- 'plan-x-downgraded-message' => __( 'Your plan was successfully downgraded. Your %s plan license will expire in %s.', 'freemius' ),
249
- 'plan-downgraded-failure-message' => __( 'Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes.', 'freemius' ),
250
- 'trial-cancel-no-trial-message' => __( 'It looks like you are not in trial mode anymore so there\'s nothing to cancel :)', 'freemius' ),
251
- 'trial-cancel-message' => __( 'Your %s Plan trial was successfully cancelled.', 'freemius' ),
252
- 'version-x-released' => _x( 'Version %s was released.', '%s - numeric version number', 'freemius' ),
253
- 'please-download-x' => __( 'Please download %s.', 'freemius' ),
254
- 'latest-x-version' => _x( 'the latest %s version here', '%s - plan name, as the latest professional version here', 'freemius' ),
255
- 'trial-x-promotion-message' => __( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.', 'freemius' ),
256
- 'start-free-trial' => _x( 'Start free trial', 'call to action', 'freemius' ),
257
- 'trial-cancel-failure-message' => __( 'Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes.', 'freemius' ),
258
- 'no-commitment-for-x-days' => __( 'No commitment for %s days - cancel anytime!', 'freemius' ),
259
- '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' ),
260
- 'could-not-activate-x' => __( 'Couldn\'t activate %s.', 'freemius' ),
261
- 'contact-us-with-error-message' => __( 'Please contact us with the following message:', 'freemius' ),
262
- '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' ),
263
- 'contact-us-here' => __( 'Please contact us here', 'freemius' ),
264
- 'plan-did-not-change-email-message' => __( 'I have upgraded my account but when I try to Sync the License, the plan remains %s.', 'freemius' ),
265
- #endregion Admin Notices
266
- #region Connectivity Issues
267
- 'connectivity-test-fails-message' => __( 'From unknown reason, the API connectivity test fails.', 'freemius' ),
268
- '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' ),
269
- 'cloudflare-blocks-connection-message' => __( 'From unknown reason, CloudFlare, the firewall we use, blocks the connection.', 'freemius' ),
270
- 'x-requires-access-to-api' => _x( '%s requires an access to our API.', 'as pluginX requires an access to our API', 'freemius' ),
271
- 'squid-blocks-connection-message' => __( 'It looks like your server is using Squid ACL (access control lists), which blocks the connection.', 'freemius' ),
272
- 'squid-no-clue-title' => __( 'I don\'t know what is Squid or ACL, help me!', 'freemius' ),
273
- '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.', 'freemius' ),
274
- 'sysadmin-title' => __( 'I\'m a system administrator', 'freemius' ),
275
- 'squid-sysadmin-desc' => __( 'Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again.', 'freemius' ),
276
- 'curl-missing-no-clue-title' => __( 'I don\'t know what is cURL or how to install it, help me!', 'freemius' ),
277
- '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.', 'freemius' ),
278
- '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.', 'freemius' ),
279
- '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' ),
280
- 'fix-issue-title' => __( 'Yes - I\'m giving you a chance to fix it', 'freemius' ),
281
- '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' ),
282
- 'install-previous-title' => __( 'Let\'s try your previous version', 'freemius' ),
283
- 'install-previous-desc' => __( 'Uninstall this version and install the previous one.', 'freemius' ),
284
- 'deactivate-plugin-title' => __( 'That\'s exhausting, please deactivate', 'freemius' ),
285
- 'deactivate-plugin-desc' => __( 'We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future.', 'freemius' ),
286
- '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' ),
287
- 'server-blocking-access' => _x( 'Your server is blocking the access to Freemius\' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s', '%1s - plugin title, %2s - API domain', 'freemius' ),
288
- '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' ),
289
- #endregion Connectivity Issues
290
- #region Change Owner
291
- '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' ),
292
- 'change-owner-request_owner-confirmed' => __( 'Thanks for confirming the ownership change. An email was just sent to %s for final approval.', 'freemius' ),
293
- 'change-owner-request_candidate-confirmed' => __( '%s is the new owner of the account.', 'freemius' ),
294
- #endregion Change Owner
295
- 'addon-x-cannot-run-without-y' => _x( '%s cannot run without %s.', 'addonX cannot run without pluginY', 'freemius' ),
296
- 'addon-x-cannot-run-without-parent' => _x( '%s cannot run without the plugin.', 'addonX cannot run...', 'freemius' ),
297
- 'plugin-x-activation-message' => _x( '%s activation was successfully completed.', 'pluginX activation was successfully...', 'freemius' ),
298
- 'features-and-pricing' => _x( 'Features & Pricing', 'Plugin installer section title', 'freemius' ),
299
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * All strings can now be overridden.
15
+ *
16
+ * For example, if we want to override:
17
+ * 'you-are-step-away' => 'You are just one step away - %s',
18
+ *
19
+ * We can use the filter:
20
+ * fs_override_i18n( array(
21
+ * 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
22
+ * 'skip' => __( 'Not today', '{your-text_domain}' ),
23
+ * ), '{plugin_slug}' );
24
+ *
25
+ * Or with the Freemius instance:
26
+ *
27
+ * my_freemius->override_i18n( array(
28
+ * 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
29
+ * 'skip' => __( 'Not today', '{your-text_domain}' ),
30
+ * );
31
+ */
32
+ global $fs_text;
33
+
34
+ $fs_text = array(
35
+ 'account' => __( 'Account', 'freemius' ),
36
+ 'addon' => __( 'Add On', 'freemius' ),
37
+ 'contact-us' => __( 'Contact Us', 'freemius' ),
38
+ 'contact-support' => __( 'Contact Support', 'freemius' ),
39
+ 'change-ownership' => __( 'Change Ownership', 'freemius' ),
40
+ 'support' => __( 'Support', 'freemius' ),
41
+ 'support-forum' => __( 'Support Forum', 'freemius' ),
42
+ 'add-ons' => __( 'Add Ons', 'freemius' ),
43
+ 'upgrade' => _x( 'Upgrade', 'verb', 'freemius' ),
44
+ 'awesome' => __( 'Awesome', 'freemius' ),
45
+ 'pricing' => _x( 'Pricing', 'noun', 'freemius' ),
46
+ 'price' => _x( 'Price', 'noun', 'freemius' ),
47
+ 'unlimited-updates' => __( 'Unlimited Updates', 'freemius' ),
48
+ 'downgrade' => _x( 'Downgrade', 'verb', 'freemius' ),
49
+ 'cancel-trial' => __( 'Cancel Trial', 'freemius' ),
50
+ 'free-trial' => __( 'Free Trial', 'freemius' ),
51
+ 'start-free-x' => __( 'Start my free %s', 'freemius' ),
52
+ 'no-commitment-x' => __( 'No commitment for %s - cancel anytime', 'freemius' ),
53
+ 'after-x-pay-as-little-y' => __( 'After your free %s, pay as little as %s', 'freemius' ),
54
+ 'details' => __( 'Details', 'freemius' ),
55
+ 'account-details' => __( 'Account Details', 'freemius' ),
56
+ 'delete' => _x( 'Delete', 'verb', 'freemius' ),
57
+ 'show' => _x( 'Show', 'verb', 'freemius' ),
58
+ 'hide' => _x( 'Hide', 'verb', 'freemius' ),
59
+ 'edit' => _x( 'Edit', 'verb', 'freemius' ),
60
+ 'date' => __( 'Date', 'freemius' ),
61
+ 'amount' => __( 'Amount', 'freemius' ),
62
+ 'invoice' => __( 'Invoice', 'freemius' ),
63
+ 'billing' => __( 'Billing', 'freemius' ),
64
+ 'payments' => __( 'Payments', 'freemius' ),
65
+ 'delete-account' => __( 'Delete Account', 'freemius' ),
66
+ 'dismiss' => _x( 'Dismiss', 'as close a window', 'freemius' ),
67
+ 'plan' => _x( 'Plan', 'as product pricing plan', 'freemius' ),
68
+ 'change-plan' => __( 'Change Plan', 'freemius' ),
69
+ 'download-x-version' => _x( 'Download %s Version', 'as download professional version', 'freemius' ),
70
+ 'download-x-version-now' => _x( 'Download %s version now', 'as download professional version now', 'freemius' ),
71
+ 'download-latest' => _x( 'Download Latest', 'as download latest version', 'freemius' ),
72
+ 'you-have-x-license' => _x( 'You have a %s license.', 'E.g. you have a professional license.', 'freemius' ),
73
+ 'new' => __( 'New', 'freemius' ),
74
+ 'free' => __( 'Free', 'freemius' ),
75
+ 'trial' => _x( 'Trial', 'as trial plan', 'freemius' ),
76
+ 'purchase' => _x( 'Purchase', 'verb', 'freemius' ),
77
+ 'purchase-license' => __( 'Purchase License', 'freemius' ),
78
+ 'buy' => _x( 'Buy', 'verb', 'freemius' ),
79
+ 'buy-license' => __( 'Buy License', 'freemius' ),
80
+ 'license-single-site' => __( 'Single Site License', 'freemius' ),
81
+ 'license-unlimited' => __( 'Unlimited Licenses', 'freemius' ),
82
+ 'license-x-sites' => __( 'Up to %s Sites', 'freemius' ),
83
+ 'renew-license-now' => __( '%sRenew your license now%s to access version %s features and support.', 'freemius' ),
84
+ 'ask-for-upgrade-email-address' => __( "Enter the email address you've used for the upgrade below and we will resend you the license key.", 'freemius' ),
85
+ 'x-plan' => _x( '%s Plan', 'e.g. Professional Plan', 'freemius' ),
86
+ 'you-are-step-away' => __( 'You are just one step away - %s', 'freemius' ),
87
+ 'activate-x-now' => _x( 'Complete "%s" Activation Now', '%s - plugin name. As complete "Jetpack" activation now', 'freemius' ),
88
+ 'few-plugin-tweaks' => __( 'We made a few tweaks to the plugin, %s', 'freemius' ),
89
+ 'optin-x-now' => __( 'Opt-in to make "%s" Better!', 'freemius' ),
90
+ 'error' => __( 'Error', 'freemius' ),
91
+ 'failed-finding-main-path' => __( 'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.', 'freemius' ),
92
+ #region Account
93
+
94
+ 'expiration' => _x( 'Expiration', 'as expiration date', 'freemius' ),
95
+ 'license' => _x( 'License', 'as software license', 'freemius' ),
96
+ 'not-verified' => __( 'not verified', 'freemius' ),
97
+ 'verify-email' => __( 'Verify Email', 'freemius' ),
98
+ 'expires-in' => _x( 'Expires in %s', 'e.g. expires in 2 months', 'freemius' ),
99
+ 'renews-in' => _x( 'Auto renews in %s', 'e.g. auto renews in 2 months', 'freemius' ),
100
+ 'no-expiration' => __( 'No expiration', 'freemius' ),
101
+ 'expired' => __( 'Expired', 'freemius' ),
102
+ 'cancelled' => __( 'Cancelled', 'freemius' ),
103
+ 'in-x' => _x( 'In %s', 'e.g. In 2 hours', 'freemius' ),
104
+ 'x-ago' => _x( '%s ago', 'e.g. 2 min ago', 'freemius' ),
105
+ 'version' => _x( 'Version', 'as plugin version', 'freemius' ),
106
+ 'name' => __( 'Name', 'freemius' ),
107
+ 'email' => __( 'Email', 'freemius' ),
108
+ 'email-address' => __( 'Email address', 'freemius' ),
109
+ 'verified' => __( 'Verified', 'freemius' ),
110
+ 'plugin' => __( 'Plugin', 'freemius' ),
111
+ 'plugins' => __( 'Plugins', 'freemius' ),
112
+ 'themes' => __( 'Themes', 'freemius' ),
113
+ 'path' => _x( 'Path', 'as file/folder path', 'freemius' ),
114
+ 'title' => __( 'Title', 'freemius' ),
115
+ 'free-version' => __( 'Free version', 'freemius' ),
116
+ 'premium-version' => __( 'Premium version', 'freemius' ),
117
+ 'slug' => _x( 'Slug', 'as WP plugin slug', 'freemius' ),
118
+ 'id' => __( 'ID', 'freemius' ),
119
+ 'users' => __( 'Users', 'freemius' ),
120
+ 'plugin-installs' => __( 'Plugin Installs', 'freemius' ),
121
+ 'sites' => _x( 'Sites', 'like websites', 'freemius' ),
122
+ 'user-id' => __( 'User ID', 'freemius' ),
123
+ 'site-id' => __( 'Site ID', 'freemius' ),
124
+ 'public-key' => __( 'Public Key', 'freemius' ),
125
+ 'secret-key' => __( 'Secret Key', 'freemius' ),
126
+ 'no-secret' => _x( 'No Secret', 'as secret encryption key missing', 'freemius' ),
127
+ 'no-id' => __( 'No ID', 'freemius' ),
128
+ 'sync-license' => _x( 'Sync License', 'as synchronize license', 'freemius' ),
129
+ 'sync' => _x( 'Sync', 'as synchronize', 'freemius' ),
130
+ 'activate-license' => __( 'Activate License', 'freemius' ),
131
+ 'activate-free-version' => __( 'Activate Free Version', 'freemius' ),
132
+ 'activate-license-message' => __( 'Please enter the license key that you received in the email right after the purchase:', 'freemius' ),
133
+ 'activating-license' => __( 'Activating license...', 'freemius' ),
134
+ 'change-license' => __( 'Change License', 'freemius' ),
135
+ 'update-license' => __( 'Update License', 'freemius' ),
136
+ 'deactivate-license' => __( 'Deactivate License', 'freemius' ),
137
+ 'activate' => __( 'Activate', 'freemius' ),
138
+ 'deactivate' => __( 'Deactivate', 'freemius' ),
139
+ 'skip-deactivate' => __( 'Skip & Deactivate', 'freemius' ),
140
+ 'no-deactivate' => __( 'No - just deactivate', 'freemius' ),
141
+ 'yes-do-your-thing' => __( 'Yes - do your thing', 'freemius' ),
142
+ 'active' => _x( 'Active', 'active mode', 'freemius' ),
143
+ 'is-active' => _x( 'Is Active', 'is active mode?', 'freemius' ),
144
+ 'install-now' => __( 'Install Now', 'freemius' ),
145
+ 'install-update-now' => __( 'Install Update Now', 'freemius' ),
146
+ 'more-information-about-x' => __( 'More information about %s', 'freemius' ),
147
+ 'localhost' => __( 'Localhost', 'freemius' ),
148
+ 'activate-x-plan' => _x( 'Activate %s Plan', 'as activate Professional plan', 'freemius' ),
149
+ 'x-left' => _x( '%s left', 'as 5 licenses left', 'freemius' ),
150
+ 'last-license' => __( 'Last license', 'freemius' ),
151
+ 'what-is-your-x' => __( 'What is your %s?', 'freemius' ),
152
+ 'activate-this-addon' => __( 'Activate this add-on', 'freemius' ),
153
+ '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' ),
154
+ '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' ),
155
+ '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' ),
156
+ 'downgrade-x-confirm' => __( 'Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s.', 'freemius' ),
157
+ 'cancel-trial-confirm' => __( 'Cancelling the trial will immediately block access to all premium features. Are you sure?', 'freemius' ),
158
+ 'after-downgrade-non-blocking' => __( 'You can still enjoy all %s features but you will not have access to plugin updates and support.', 'freemius' ),
159
+ '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' ),
160
+ 'proceed-confirmation' => __( 'Are you sure you want to proceed?', 'freemius' ),
161
+ #endregion Account
162
+
163
+ 'add-ons-for-x' => __( 'Add Ons for %s', 'freemius' ),
164
+ 'add-ons-missing' => __( 'We could\'nt load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.', 'freemius' ),
165
+ #region Plugin Deactivation
166
+ 'anonymous-feedback' => __( 'Anonymous feedback', 'freemius' ),
167
+ 'quick-feedback' => __( 'Quick feedback', 'freemius' ),
168
+ 'deactivation-share-reason' => __( 'If you have a moment, please let us know why you are deactivating', 'freemius' ),
169
+ 'deactivation-modal-button-confirm' => __( 'Yes - Deactivate', 'freemius' ),
170
+ 'deactivation-modal-button-submit' => __( 'Submit & Deactivate', 'freemius' ),
171
+ 'deactivation-modal-button-cancel' => _x( 'Cancel', 'the text of the cancel button of the plugin deactivation dialog box.', 'freemius' ),
172
+ 'reason-no-longer-needed' => __( 'I no longer need the plugin', 'freemius' ),
173
+ 'reason-found-a-better-plugin' => __( 'I found a better plugin', 'freemius' ),
174
+ 'reason-needed-for-a-short-period' => __( 'I only needed the plugin for a short period', 'freemius' ),
175
+ 'reason-broke-my-site' => __( 'The plugin broke my site', 'freemius' ),
176
+ 'reason-suddenly-stopped-working' => __( 'The plugin suddenly stopped working', 'freemius' ),
177
+ 'reason-cant-pay-anymore' => __( "I can't pay for it anymore", 'freemius' ),
178
+ 'reason-temporary-deactivation' => __( "It's a temporary deactivation. I'm just debugging an issue.", 'freemius' ),
179
+ 'reason-other' => _x( 'Other', 'the text of the "other" reason for deactivating the plugin that is shown in the modal box.', 'freemius' ),
180
+ 'ask-for-reason-message' => __( 'Kindly tell us the reason so we can improve.', 'freemius' ),
181
+ 'placeholder-plugin-name' => __( "What's the plugin's name?", 'freemius' ),
182
+ 'placeholder-comfortable-price' => __( 'What price would you feel comfortable paying?', 'freemius' ),
183
+ 'reason-couldnt-make-it-work' => __( "I couldn't understand how to make it work", 'freemius' ),
184
+ 'reason-great-but-need-specific-feature' => __( "The plugin is great, but I need specific feature that you don't support", 'freemius' ),
185
+ 'reason-not-working' => __( 'The plugin is not working', 'freemius' ),
186
+ 'reason-not-what-i-was-looking-for' => __( "It's not what I was looking for", 'freemius' ),
187
+ 'reason-didnt-work-as-expected' => __( "The plugin didn't work as expected", 'freemius' ),
188
+ 'placeholder-feature' => __( 'What feature?', 'freemius' ),
189
+ 'placeholder-share-what-didnt-work' => __( "Kindly share what didn't work so we can fix it for future users...", 'freemius' ),
190
+ 'placeholder-what-youve-been-looking-for' => __( "What you've been looking for?", 'freemius' ),
191
+ 'placeholder-what-did-you-expect' => __( "What did you expect?", 'freemius' ),
192
+ 'reason-didnt-work' => __( "The plugin didn't work", 'freemius' ),
193
+ 'reason-dont-like-to-share-my-information' => __( "I don't like to share my information with you", 'freemius' ),
194
+ 'dont-have-to-share-any-data' => __( "You might have missed it, but you don't have to share any data and can just %s the opt-in.", 'freemius' ),
195
+ #endregion Plugin Deactivation
196
+
197
+ #region Connect
198
+ 'hey-x' => _x( 'Hey %s,', 'greeting', 'freemius' ),
199
+ 'thanks-x' => _x( 'Thanks %s!', 'a greeting. E.g. Thanks John!', 'freemius' ),
200
+ 'connect-message' => __( 'In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s', 'freemius' ),
201
+ 'connect-message_on-update' => __( 'Please help us improve %2$s! If you opt-in, some data about your usage of %2$s will be sent to %5$s. If you skip this, that\'s okay! %2$s will still work just fine.', 'freemius' ),
202
+ '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' ),
203
+ 'thanks-for-purchasing' => __( 'Thanks for purchasing %s! To get started, please enter your license key:', 'freemius' ),
204
+ 'license-sync-disclaimer' => __( 'The plugin will be periodically sending data to %s to check for plugin updates and verify the validity of your license.', 'freemius' ),
205
+ 'what-permissions' => __( 'What permissions are being granted?', 'freemius' ),
206
+ 'permissions-profile' => __( 'Your Profile Overview', 'freemius' ),
207
+ 'permissions-profile_desc' => __( 'Name and email address', 'freemius' ),
208
+ 'permissions-site' => __( 'Your Site Overview', 'freemius' ),
209
+ 'permissions-site_desc' => __( 'Site URL, WP version, PHP info, plugins & themes', 'freemius' ),
210
+ 'permissions-events' => __( 'Current Plugin Events', 'freemius' ),
211
+ 'permissions-events_desc' => __( 'Activation, deactivation and uninstall', 'freemius' ),
212
+ 'permissions-plugins_themes' => __( 'Plugins & Themes', 'freemius' ),
213
+ 'permissions-plugins_themes_desc' => __( 'Titles, versions and state.', 'freemius' ),
214
+ 'permissions-newsletter' => __( 'Newsletter', 'freemius' ),
215
+ 'permissions-newsletter_desc' => __( 'Updates, announcements, marketing, no spam', 'freemius' ),
216
+ 'privacy-policy' => __( 'Privacy Policy', 'freemius' ),
217
+ 'tos' => __( 'Terms of Service', 'freemius' ),
218
+ 'activating' => _x( 'Activating', 'as activating plugin', 'freemius' ),
219
+ 'sending-email' => _x( 'Sending email', 'as in the process of sending an email', 'freemius' ),
220
+ 'opt-in-connect' => _x( 'Allow & Continue', 'button label', 'freemius' ),
221
+ 'agree-activate-license' => _x( 'Agree & Activate License', 'button label', 'freemius' ),
222
+ 'skip' => _x( 'Skip', 'verb', 'freemius' ),
223
+ 'click-here-to-use-plugin-anonymously' => __( 'Click here to use the plugin anonymously', 'freemius' ),
224
+ 'resend-activation-email' => __( 'Re-send activation email', 'freemius' ),
225
+ 'license-key' => __( 'License key', 'freemius' ),
226
+ 'send-license-key' => __( 'Send License Key', 'freemius' ),
227
+ 'sending-license-key' => __( 'Sending license key', 'freemius' ),
228
+ 'have-license-key' => __( 'Have a license key?', 'freemius' ),
229
+ 'dont-have-license-key' => __( 'Don\'t have a license key?', 'freemius' ),
230
+ 'cant-find-license-key' => __( "Can't find your license key?", 'freemius' ),
231
+ 'email-not-found' => __( "We couldn't find your email address in the system, are you sure it's the right address?" ),
232
+ 'no-active-licenses' => __( "We can't see any active licenses associated with that email address, are you sure it's the right address?" ),
233
+ #endregion Connect
234
+
235
+ #region Screenshots
236
+ 'screenshots' => __( 'Screenshots', 'freemius' ),
237
+ 'view-full-size-x' => __( 'Click to view full-size screenshot %d', 'freemius' ),
238
+ #endregion Screenshots
239
+
240
+ #region Debug
241
+ 'freemius-debug' => __( 'Freemius Debug', 'freemius' ),
242
+ 'on' => _x( 'On', 'as turned on', 'freemius' ),
243
+ 'off' => _x( 'Off', 'as turned off', 'freemius' ),
244
+ 'debugging' => _x( 'Debugging', 'as code debugging', 'freemius' ),
245
+ 'freemius-state' => __( 'Freemius State', 'freemius' ),
246
+ 'connected' => _x( 'Connected', 'as connection was successful', 'freemius' ),
247
+ 'blocked' => _x( 'Blocked', 'as connection blocked', 'freemius' ),
248
+ 'api' => _x( 'API', 'as application program interface', 'freemius' ),
249
+ 'sdk' => _x( 'SDK', 'as software development kit versions', 'freemius' ),
250
+ 'sdk-versions' => _x( 'SDK Versions', 'as software development kit versions', 'freemius' ),
251
+ 'plugin-path' => _x( 'Plugin Path', 'as plugin folder path', 'freemius' ),
252
+ 'sdk-path' => _x( 'SDK Path', 'as sdk path', 'freemius' ),
253
+ 'addons-of-x' => __( 'Add Ons of Plugin %s', 'freemius' ),
254
+ 'delete-all-confirm' => __( 'Are you sure you want to delete all Freemius data?', 'freemius' ),
255
+ 'actions' => __( 'Actions', 'freemius' ),
256
+ 'delete-all-accounts' => __( 'Delete All Accounts', 'freemius' ),
257
+ 'start-fresh' => __( 'Start Fresh', 'freemius' ),
258
+ 'clear-api-cache' => __( 'Clear API Cache', 'freemius' ),
259
+ 'sync-data-from-server' => __( 'Sync Data From Server', 'freemius' ),
260
+ 'scheduled-crons' => __( 'Scheduled Crons', 'freemius' ),
261
+ 'plugins-themes-sync' => __( 'Plugins & Themes Sync', 'freemius' ),
262
+ #endregion Debug
263
+
264
+ #region Expressions
265
+ 'congrats' => _x( 'Congrats', 'as congratulations', 'freemius' ),
266
+ 'oops' => _x( 'Oops', 'exclamation', 'freemius' ),
267
+ 'yee-haw' => _x( 'Yee-haw', 'interjection expressing joy or exuberance', 'freemius' ),
268
+ 'woot' => _x( 'W00t', '(especially in electronic communication) used to express elation, enthusiasm, or triumph.', 'freemius' ),
269
+ 'right-on' => _x( 'Right on', 'a positive response', 'freemius' ),
270
+ 'hmm' => _x( 'Hmm', 'something somebody says when they are thinking about what you have just said. ', 'freemius' ),
271
+ 'ok' => __( 'O.K', 'freemius' ),
272
+ 'hey' => _x( 'Hey', 'exclamation', 'freemius' ),
273
+ 'heads-up' => _x( 'Heads up', 'advance notice of something that will need attention.', 'freemius' ),
274
+ #endregion Expressions
275
+
276
+ #region Admin Notices
277
+ 'you-have-latest' => __( 'Seems like you got the latest release.', 'freemius' ),
278
+ 'you-are-good' => __( 'You are all good!', 'freemius' ),
279
+ 'user-exist-message' => __( 'Sorry, we could not complete the email update. Another user with the same email is already registered.', 'freemius' ),
280
+ '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' ),
281
+ 'email-updated-message' => __( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.', 'freemius' ),
282
+ 'name-updated-message' => __( 'Your name was successfully updated.', 'freemius' ),
283
+ 'x-updated' => __( 'You have successfully updated your %s.', 'freemius' ),
284
+ 'name-update-failed-message' => __( 'Please provide your full name.', 'freemius' ),
285
+ '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' ),
286
+ 'addons-info-external-message' => __( 'Just letting you know that the add-ons information of %s is being pulled from an external server.', 'freemius' ),
287
+ 'no-cc-required' => __( 'No credit card required', 'freemius' ),
288
+ 'premium-activated-message' => __( 'Premium plugin version was successfully activated.', 'freemius' ),
289
+ 'successful-version-upgrade-message' => __( 'The upgrade of %s was successfully completed.', 'freemius' ),
290
+ 'activation-with-plan-x-message' => __( 'Your account was successfully activated with the %s plan.', 'freemius' ),
291
+ 'download-latest-x-version-now' => __( 'Download the latest %s version now', 'freemius' ),
292
+ 'follow-steps-to-complete-upgrade' => __( 'Please follow these steps to complete the upgrade', 'freemius' ),
293
+ 'download-latest-x-version' => __( 'Download the latest %s version', 'freemius' ),
294
+ 'deactivate-free-version' => __( 'Deactivate the free version', 'freemius' ),
295
+ 'upload-and-activate' => __( 'Upload and activate the downloaded version', 'freemius' ),
296
+ 'howto-upload-activate' => __( 'How to upload and activate?', 'freemius' ),
297
+ 'addon-successfully-purchased-message' => _x( '%s Add-on was successfully purchased.', '%s - product name, e.g. Facebook add-on was successfully...', 'freemius' ),
298
+ 'addon-successfully-upgraded-message' => __( 'Your %s Add-on plan was successfully upgraded.', 'freemius' ),
299
+ 'email-verified-message' => __( 'Your email has been successfully verified - you are AWESOME!', 'freemius' ),
300
+ 'plan-upgraded-message' => __( 'Your plan was successfully upgraded.', 'freemius' ),
301
+ 'plan-changed-to-x-message' => __( 'Your plan was successfully changed to %s.', 'freemius' ),
302
+ 'license-expired-blocking-message' => __( 'Your license has expired. You can still continue using the free plugin forever.', 'freemius' ),
303
+ 'license-cancelled' => __( 'Your license has been cancelled. If you think it\'s a mistake, please contact support.', 'freemius' ),
304
+ 'trial-started-message' => __( 'Your trial has been successfully started.', 'freemius' ),
305
+ 'license-activated-message' => __( 'Your license was successfully activated.', 'freemius' ),
306
+ 'no-active-license-message' => __( 'It looks like your site currently doesn\'t have an active license.', 'freemius' ),
307
+ 'license-deactivation-message' => __( 'Your license was successfully deactivated, you are back to the %s plan.', 'freemius' ),
308
+ 'license-deactivation-failed-message' => __( 'It looks like the license deactivation failed.', 'freemius' ),
309
+ 'license-activation-failed-message' => __( 'It looks like the license could not be activated.', 'freemius' ),
310
+ 'server-error-message' => __( 'Error received from the server:', 'freemius' ),
311
+ 'trial-expired-message' => __( 'Your trial has expired. You can still continue using all our free features.', 'freemius' ),
312
+ 'plan-x-downgraded-message' => __( 'Your plan was successfully downgraded. Your %s plan license will expire in %s.', 'freemius' ),
313
+ 'plan-downgraded-failure-message' => __( 'Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes.', 'freemius' ),
314
+ 'trial-cancel-no-trial-message' => __( 'It looks like you are not in trial mode anymore so there\'s nothing to cancel :)', 'freemius' ),
315
+ 'trial-cancel-message' => __( 'Your %s free trial was successfully cancelled.', 'freemius' ),
316
+ 'version-x-released' => _x( 'Version %s was released.', '%s - numeric version number', 'freemius' ),
317
+ 'please-download-x' => __( 'Please download %s.', 'freemius' ),
318
+ 'latest-x-version' => _x( 'the latest %s version here', '%s - plan name, as the latest professional version here', 'freemius' ),
319
+ 'trial-x-promotion-message' => __( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.', 'freemius' ),
320
+ 'start-free-trial' => _x( 'Start free trial', 'call to action', 'freemius' ),
321
+ 'trial-cancel-failure-message' => __( 'Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes.', 'freemius' ),
322
+ 'trial-utilized' => __( 'You already utilized a trial before.', 'freemius' ),
323
+ 'in-trial-mode' => __( 'You are already running the plugin in a trial mode.', 'freemius' ),
324
+ 'trial-plan-x-not-exist' => __( 'Plan %s do not exist, therefore, can\'t start a trial.', 'freemius' ),
325
+ 'plan-x-no-trial' => __( 'Plan %s does not support a trial period.', 'freemius' ),
326
+ 'no-trials' => __( 'None of the plugin\'s plans supports a trial period.', 'freemius' ),
327
+ 'unexpected-api-error' => __( 'Unexpected API error. Please contact the plugin\'s author with the following error.', 'freemius' ),
328
+ 'no-commitment-for-x-days' => __( 'No commitment for %s days - cancel anytime!', 'freemius' ),
329
+ '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' ),
330
+ 'could-not-activate-x' => __( 'Couldn\'t activate %s.', 'freemius' ),
331
+ 'contact-us-with-error-message' => __( 'Please contact us with the following message:', 'freemius' ),
332
+ 'plan-did-not-change-message' => __( 'It looks like you are still on the %s plan. If you did upgrade or change your plan, it\'s probably an issue on our side - sorry.', 'freemius' ),
333
+ 'contact-us-here' => __( 'Please contact us here', 'freemius' ),
334
+ 'plan-did-not-change-email-message' => __( 'I have upgraded my account but when I try to Sync the License, the plan remains %s.', 'freemius' ),
335
+ #endregion Admin Notices
336
+ #region Connectivity Issues
337
+ 'connectivity-test-fails-message' => __( 'From unknown reason, the API connectivity test failed.', 'freemius' ),
338
+ 'connectivity-test-maybe-temporary' => __( 'It\'s probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?', 'freemius' ),
339
+ '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' ),
340
+ 'cloudflare-blocks-connection-message' => __( 'From unknown reason, CloudFlare, the firewall we use, blocks the connection.', 'freemius' ),
341
+ 'x-requires-access-to-api' => _x( '%s requires an access to our API.', 'as pluginX requires an access to our API', 'freemius' ),
342
+ 'squid-blocks-connection-message' => __( 'It looks like your server is using Squid ACL (access control lists), which blocks the connection.', 'freemius' ),
343
+ 'squid-no-clue-title' => __( 'I don\'t know what is Squid or ACL, help me!', 'freemius' ),
344
+ '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.', 'freemius' ),
345
+ 'sysadmin-title' => __( 'I\'m a system administrator', 'freemius' ),
346
+ 'squid-sysadmin-desc' => __( 'Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again.', 'freemius' ),
347
+ 'curl-missing-no-clue-title' => __( 'I don\'t know what is cURL or how to install it, help me!', 'freemius' ),
348
+ '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.', 'freemius' ),
349
+ '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.', 'freemius' ),
350
+ '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' ),
351
+ 'contact-support-before-deactivation' => __( 'Sorry for the inconvenience and we are here to help if you give us a chance.', 'freemius' ),
352
+ 'fix-issue-title' => __( 'Yes - I\'m giving you a chance to fix it', 'freemius' ),
353
+ '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' ),
354
+ 'install-previous-title' => __( 'Let\'s try your previous version', 'freemius' ),
355
+ 'install-previous-desc' => __( 'Uninstall this version and install the previous one.', 'freemius' ),
356
+ 'deactivate-plugin-title' => __( 'That\'s exhausting, please deactivate', 'freemius' ),
357
+ 'deactivate-plugin-desc' => __( 'We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future.', 'freemius' ),
358
+ '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' ),
359
+ 'server-blocking-access' => _x( 'Your server is blocking the access to Freemius\' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s', '%1s - plugin title, %2s - API domain', 'freemius' ),
360
+ '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' ),
361
+ #endregion Connectivity Issues
362
+ #region Change Owner
363
+ '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' ),
364
+ 'change-owner-request_owner-confirmed' => __( 'Thanks for confirming the ownership change. An email was just sent to %s for final approval.', 'freemius' ),
365
+ 'change-owner-request_candidate-confirmed' => __( '%s is the new owner of the account.', 'freemius' ),
366
+ #endregion Change Owner
367
+ 'addon-x-cannot-run-without-y' => _x( '%s cannot run without %s.', 'addonX cannot run without pluginY', 'freemius' ),
368
+ 'addon-x-cannot-run-without-parent' => _x( '%s cannot run without the plugin.', 'addonX cannot run...', 'freemius' ),
369
+ 'plugin-x-activation-message' => _x( '%s activation was successfully completed.', 'pluginX activation was successfully...', 'freemius' ),
370
+ 'features-and-pricing' => _x( 'Features & Pricing', 'Plugin installer section title', 'freemius' ),
371
+ 'free-addon-not-deployed' => __( 'Add-on must be deployed to WordPress.org or Freemius.', 'freemius' ),
372
+ 'paid-addon-not-deployed' => __( 'Paid add-on must be deployed to Freemius.', 'freemius' ),
373
+ #region Add-On Licensing
374
+ 'addon-no-license-message' => __( '%s is a premium only add-on. You have to purchase a license first before activating the plugin.', 'freemius' ),
375
+ 'addon-trial-cancelled-message' => __( '%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you\'ll have to purchase a license.', 'freemius' ),
376
+ #endregion Add-On Licensing
377
+ #region Billing Cycles
378
+ 'monthly' => _x( 'Monthly', 'as every month', 'freemius' ),
379
+ 'mo' => _x( 'mo', 'as monthly period', 'freemius' ),
380
+ 'annual' => _x( 'Annual', 'as once a year', 'freemius' ),
381
+ 'annually' => _x( 'Annually', 'as once a year', 'freemius' ),
382
+ 'once' => _x( 'Once', 'as once a year', 'freemius' ),
383
+ 'year' => _x( 'year', 'as annual period', 'freemius' ),
384
+ 'lifetime' => __( 'Lifetime', 'freemius' ),
385
+ 'best' => _x( 'Best', 'e.g. the best product', 'freemius' ),
386
+ 'billed-x' => _x( 'Billed %s', 'e.g. billed monthly', 'freemius' ),
387
+ 'save-x' => _x( 'Save %s', 'as a discount of $5 or 10%', 'freemius' ),
388
+ #endregion Billing Cycles
389
+ 'view-details' => __( 'View details', 'freemius' ),
390
+ );
freemius/includes/managers/class-fs-admin-menu-manager.php CHANGED
@@ -58,7 +58,7 @@
58
  /**
59
  * @since 1.1.3
60
  *
61
- * @var string[]bool
62
  */
63
  private $_default_submenu_items;
64
  /**
@@ -110,7 +110,7 @@
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
@@ -527,6 +527,9 @@
527
  } else {
528
  global $menu;
529
 
 
 
 
530
  // Create new top-level menu action.
531
  $hookname = add_menu_page(
532
  $found_menu['menu'][3],
@@ -537,9 +540,6 @@
537
  $found_menu['menu'][6],
538
  $found_menu['position']
539
  );
540
-
541
- // Remove original CPT menu.
542
- unset( $menu[ $found_menu['position'] ] );
543
  }
544
 
545
  return $hookname;
58
  /**
59
  * @since 1.1.3
60
  *
61
+ * @var array<string,bool>
62
  */
63
  private $_default_submenu_items;
64
  /**
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
527
  } else {
528
  global $menu;
529
 
530
+ // Remove original CPT menu.
531
+ unset( $menu[ $found_menu['position'] ] );
532
+
533
  // Create new top-level menu action.
534
  $hookname = add_menu_page(
535
  $found_menu['menu'][3],
540
  $found_menu['menu'][6],
541
  $found_menu['position']
542
  );
 
 
 
543
  }
544
 
545
  return $hookname;
freemius/includes/managers/class-fs-admin-notice-manager.php CHANGED
@@ -1,303 +1,310 @@
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
  }
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_fs_dismiss_notice_action_{$slug}", 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 ( function_exists( 'current_user_can' ) &&
133
+ ! current_user_can( 'manage_options' )
134
+ ) {
135
+ // Only show messages to admins.
136
+ return;
137
+ }
138
+
139
+ if ( ! isset( $this->_admin_messages[ $notice_type ] ) || ! is_array( $this->_admin_messages[ $notice_type ] ) ) {
140
+ return;
141
+ }
142
+
143
+ foreach ( $this->_admin_messages[ $notice_type ] as $id => $msg ) {
144
+ fs_require_template( 'admin-notice.php', $msg );
145
+
146
+ if ( $msg['sticky'] ) {
147
+ self::has_sticky_messages();
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Handle all_admin_notices by printing the admin messages stacked in the queue.
154
+ *
155
+ * @author Vova Feldman (@svovaf)
156
+ * @since 1.0.4
157
+ *
158
+ */
159
+ function _all_admin_notices_hook() {
160
+ $notice_type = 'all_admin_notices';
161
+
162
+ if ( ! isset( $this->_admin_messages[ $notice_type ] ) || ! is_array( $this->_admin_messages[ $notice_type ] ) ) {
163
+ return;
164
+ }
165
+
166
+ foreach ( $this->_admin_messages[ $notice_type ] as $id => $msg ) {
167
+ fs_require_template( 'all-admin-notice.php', $msg );
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Enqueue common stylesheet to style admin notice.
173
+ *
174
+ * @author Vova Feldman (@svovaf)
175
+ * @since 1.0.7
176
+ */
177
+ function _enqueue_styles() {
178
+ fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
179
+ }
180
+
181
+ /**
182
+ * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
183
+ *
184
+ * @author Vova Feldman (@svovaf)
185
+ * @since 1.0.4
186
+ *
187
+ * @param string $message
188
+ * @param string $title
189
+ * @param string $type
190
+ * @param bool $is_sticky
191
+ * @param bool $all_admin
192
+ * @param string $id Message ID
193
+ * @param bool $store_if_sticky
194
+ *
195
+ * @uses add_action()
196
+ */
197
+ function add( $message, $title = '', $type = 'success', $is_sticky = false, $all_admin = false, $id = '', $store_if_sticky = true ) {
198
+ $key = ( $all_admin ? 'all_admin_notices' : 'admin_notices' );
199
+
200
+ if ( ! isset( $this->_admin_messages[ $key ] ) ) {
201
+ $this->_admin_messages[ $key ] = array();
202
+
203
+ add_action( $key, array( &$this, "_{$key}_hook" ) );
204
+ add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_styles' ) );
205
+
206
+ }
207
+
208
+ if ( '' === $id ) {
209
+ $id = md5( $title . ' ' . $message . ' ' . $type );
210
+ }
211
+
212
+ $message_object = array(
213
+ 'message' => $message,
214
+ 'title' => $title,
215
+ 'type' => $type,
216
+ 'sticky' => $is_sticky,
217
+ 'id' => $id,
218
+ 'all' => $all_admin,
219
+ 'slug' => $this->_slug,
220
+ 'plugin' => $this->_title,
221
+ );
222
+
223
+ if ( $is_sticky && $store_if_sticky ) {
224
+ $this->_sticky_storage->{$id} = $message_object;
225
+ }
226
+
227
+ $this->_admin_messages[ $key ][ $id ] = $message_object;
228
+ }
229
+
230
+ /**
231
+ * @author Vova Feldman (@svovaf)
232
+ * @since 1.0.7
233
+ *
234
+ * @param string|string[] $ids
235
+ */
236
+ function remove_sticky( $ids ) {
237
+ if ( ! is_array( $ids ) ) {
238
+ $ids = array( $ids );
239
+ }
240
+
241
+ foreach ( $ids as $id ) {
242
+ // Remove from sticky storage.
243
+ $this->_sticky_storage->remove( $id );
244
+
245
+ // Remove from current admin messages.
246
+ if ( isset( $this->_admin_messages['all_admin_notices'] ) && isset( $this->_admin_messages['all_admin_notices'][ $id ] ) ) {
247
+ unset( $this->_admin_messages['all_admin_notices'][ $id ] );
248
+ }
249
+ if ( isset( $this->_admin_messages['admin_notices'] ) && isset( $this->_admin_messages['admin_notices'][ $id ] ) ) {
250
+ unset( $this->_admin_messages['admin_notices'][ $id ] );
251
+ }
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Check if sticky message exists by id.
257
+ *
258
+ * @author Vova Feldman (@svovaf)
259
+ * @since 1.0.9
260
+ *
261
+ * @param $id
262
+ *
263
+ * @return bool
264
+ */
265
+ function has_sticky( $id ) {
266
+ return isset( $this->_sticky_storage[ $id ] );
267
+ }
268
+
269
+ /**
270
+ * Adds sticky admin notification.
271
+ *
272
+ * @author Vova Feldman (@svovaf)
273
+ * @since 1.0.7
274
+ *
275
+ * @param string $message
276
+ * @param string $id Message ID
277
+ * @param string $title
278
+ * @param string $type
279
+ * @param bool $all_admin
280
+ */
281
+ function add_sticky( $message, $id, $title = '', $type = 'success', $all_admin = false ) {
282
+ $this->add( $message, $title, $type, true, $all_admin, $id );
283
+ }
284
+
285
+ /**
286
+ * Clear all sticky messages.
287
+ *
288
+ * @author Vova Feldman (@svovaf)
289
+ * @since 1.0.8
290
+ */
291
+ function clear_all_sticky() {
292
+ $this->_sticky_storage->clear_all();
293
+ }
294
+
295
+ /**
296
+ * Add admin message to all admin messages queue, and hook to all_admin_notices if not yet hooked.
297
+ *
298
+ * @author Vova Feldman (@svovaf)
299
+ * @since 1.0.4
300
+ *
301
+ * @param string $message
302
+ * @param string $title
303
+ * @param string $type
304
+ * @param bool $is_sticky
305
+ * @param string $id Message ID
306
+ */
307
+ function add_all( $message, $title = '', $type = 'success', $is_sticky = false, $id = '' ) {
308
+ $this->add( $message, $title, $type, $is_sticky, true, $id );
309
+ }
310
  }
freemius/includes/managers/class-fs-cache-manager.php CHANGED
@@ -195,6 +195,32 @@
195
  $this->_options->set_option( $key, $cache_entry, true );
196
  }
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  /**
199
  * Purge cached item.
200
  *
195
  $this->_options->set_option( $key, $cache_entry, true );
196
  }
197
 
198
+ /**
199
+ * Get cached record expiration, or false if not cached or expired.
200
+ *
201
+ * @author Vova Feldman (@svovaf)
202
+ * @since 1.1.7.3
203
+ *
204
+ * @param string $key
205
+ *
206
+ * @return bool|int
207
+ */
208
+ function get_record_expiration( $key ) {
209
+ $this->_logger->entrance( 'key = ' . $key );
210
+
211
+ $cache_entry = $this->_options->get_option( $key, false );
212
+
213
+ if ( is_object( $cache_entry ) &&
214
+ isset( $cache_entry->timestamp ) &&
215
+ is_numeric( $cache_entry->timestamp ) &&
216
+ $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME
217
+ ) {
218
+ return $cache_entry->timestamp;
219
+ }
220
+
221
+ return false;
222
+ }
223
+
224
  /**
225
  * Purge cached item.
226
  *
freemius/includes/managers/class-fs-key-value-storage.php CHANGED
@@ -10,6 +10,37 @@
10
  exit;
11
  }
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable {
14
  /**
15
  * @var string
@@ -86,6 +117,10 @@
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;
@@ -236,7 +271,7 @@
236
  * @return void Any returned value is ignored.
237
  */
238
  public function next() {
239
- return next( $this->_data );
240
  }
241
 
242
  /**
10
  exit;
11
  }
12
 
13
+ /**
14
+ * Class FS_Key_Value_Storage
15
+ *
16
+ * @property int $install_timestamp
17
+ * @property int $activation_timestamp
18
+ * @property int $sync_timestamp
19
+ * @property object $sync_cron
20
+ * @property int $install_sync_timestamp
21
+ * @property array $connectivity_test
22
+ * @property array $is_on
23
+ * @property object $trial_plan
24
+ * @property bool $has_trial_plan
25
+ * @property bool $trial_promotion_shown
26
+ * @property string $sdk_version
27
+ * @property string $sdk_last_version
28
+ * @property bool $sdk_upgrade_mode
29
+ * @property bool $sdk_downgrade_mode
30
+ * @property bool $plugin_upgrade_mode
31
+ * @property bool $plugin_downgrade_mode
32
+ * @property string $plugin_version
33
+ * @property string $plugin_last_version
34
+ * @property bool $is_plugin_new_install
35
+ * @property bool $was_plugin_loaded
36
+ * @property object $plugin_main_file
37
+ * @property bool $prev_is_premium
38
+ * @property array $is_anonymous
39
+ * @property bool $is_pending_activation
40
+ * @property bool $sticky_optin_added
41
+ * @property object $uninstall_reason
42
+ * @property object $subscription
43
+ */
44
  class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable {
45
  /**
46
  * @var string
117
  * @param bool $flush
118
  */
119
  function store( $key, $value, $flush = true ) {
120
+ if ( $this->_logger->is_on() ) {
121
+ $this->_logger->entrance( $key . ' = ' . var_export( $value, true ) );
122
+ }
123
+
124
  if ( array_key_exists( $key, $this->_data ) && $value === $this->_data[ $key ] ) {
125
  // No need to store data if the value wasn't changed.
126
  return;
271
  * @return void Any returned value is ignored.
272
  */
273
  public function next() {
274
+ next( $this->_data );
275
  }
276
 
277
  /**
freemius/includes/managers/class-fs-license-manager.php CHANGED
@@ -90,6 +90,9 @@
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
  }
90
  static function has_premium_license( $licenses ) {
91
  if ( is_array( $licenses ) ) {
92
  foreach ( $licenses as $license ) {
93
+ /**
94
+ * @var FS_Plugin_License $license
95
+ */
96
  if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
97
  return true;
98
  }
freemius/includes/managers/class-fs-option-manager.php CHANGED
@@ -100,6 +100,11 @@
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
  }
100
  $option_name = $this->_get_option_manager_name();
101
 
102
  if ( $flush || ! isset( $this->_options ) ) {
103
+ if ( isset( $this->_options ) ) {
104
+ // Clear prev options.
105
+ $this->clear();
106
+ }
107
+
108
  if ( ! WP_FS__DEBUG_SDK ) {
109
  $this->_options = wp_cache_get( $option_name, WP_FS__SLUG );
110
  }
freemius/includes/managers/class-fs-plan-manager.php CHANGED
@@ -37,6 +37,9 @@
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;
@@ -62,6 +65,9 @@
62
  return false;
63
  }
64
 
 
 
 
65
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
66
  if ( ! $plans[ $i ]->is_free() ) {
67
  return true;
@@ -88,6 +94,9 @@
88
  return true;
89
  }
90
 
 
 
 
91
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
92
  if ( $plans[ $i ]->is_free() ) {
93
  return true;
@@ -111,6 +120,9 @@
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 ];
@@ -136,6 +148,9 @@
136
  return true;
137
  }
138
 
 
 
 
139
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
140
  if ( $plans[ $i ]->has_trial() ) {
141
  return true;
37
  */
38
  function has_premium_license( $licenses ) {
39
  if ( is_array( $licenses ) ) {
40
+ /**
41
+ * @var FS_Plugin_License[] $licenses
42
+ */
43
  foreach ( $licenses as $license ) {
44
  if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
45
  return true;
65
  return false;
66
  }
67
 
68
+ /**
69
+ * @var FS_Plugin_Plan[] $plans
70
+ */
71
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
72
  if ( ! $plans[ $i ]->is_free() ) {
73
  return true;
94
  return true;
95
  }
96
 
97
+ /**
98
+ * @var FS_Plugin_Plan[] $plans
99
+ */
100
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
101
  if ( $plans[ $i ]->is_free() ) {
102
  return true;
120
  $trial_plans = array();
121
 
122
  if ( is_array( $plans ) && 0 < count( $plans ) ) {
123
+ /**
124
+ * @var FS_Plugin_Plan[] $plans
125
+ */
126
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
127
  if ( $plans[ $i ]->has_trial() ) {
128
  $trial_plans[] = $plans[ $i ];
148
  return true;
149
  }
150
 
151
+ /**
152
+ * @var FS_Plugin_Plan[] $plans
153
+ */
154
  for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
155
  if ( $plans[ $i ]->has_trial() ) {
156
  return true;
freemius/includes/sdk/Freemius.php CHANGED
@@ -41,6 +41,10 @@
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
  }
@@ -49,15 +53,7 @@
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'.
@@ -236,6 +232,46 @@
236
  ) ), $this->_isSandbox );
237
  }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  /**
240
  * @param string $pCanonizedPath
241
  * @param string $pMethod
@@ -271,7 +307,12 @@
271
  $pCurlHandler = curl_init();
272
  }
273
 
274
- $opts = self::$CURL_OPTS;
 
 
 
 
 
275
 
276
  if ( ! isset( $opts[ CURLOPT_HTTPHEADER ] ) || ! is_array( $opts[ CURLOPT_HTTPHEADER ] ) ) {
277
  $opts[ CURLOPT_HTTPHEADER ] = array();
@@ -287,7 +328,9 @@
287
  $opts[ CURLOPT_RETURNTRANSFER ] = true;
288
  }
289
 
290
- $opts[ CURLOPT_URL ] = Freemius_Api::GetUrl( $pCanonizedPath, $pIsSandbox );
 
 
291
  $opts[ CURLOPT_CUSTOMREQUEST ] = $pMethod;
292
 
293
  $resource = explode( '?', $pCanonizedPath );
@@ -296,7 +339,7 @@
296
  // for 2 seconds if the server does not support this header.
297
  $opts[ CURLOPT_HTTPHEADER ][] = 'Expect:';
298
 
299
- if ( 'https' === substr( strtolower( $pCanonizedPath ), 0, 5 ) ) {
300
  $opts[ CURLOPT_SSL_VERIFYHOST ] = false;
301
  $opts[ CURLOPT_SSL_VERIFYPEER ] = false;
302
  }
@@ -308,7 +351,7 @@
308
  }
309
 
310
  curl_setopt_array( $pCurlHandler, $opts );
311
- $result = curl_exec( $pCurlHandler );
312
 
313
  /*if (curl_errno($ch) == 60) // CURLE_SSL_CACERT
314
  {
@@ -329,9 +372,9 @@
329
  if ( preg_match( $regex, curl_error( $pCurlHandler ), $matches ) ) {
330
  if ( strlen( @inet_pton( $matches[1] ) ) === 16 ) {
331
  // self::errorLog('Invalid IPv6 configuration on server, Please disable or get native IPv6 on your server.');
332
- self::$CURL_OPTS[ CURLOPT_IPRESOLVE ] = CURL_IPRESOLVE_V4;
333
  curl_setopt( $pCurlHandler, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
334
- $result = curl_exec( $pCurlHandler );
335
  }
336
  }
337
  }
41
 
42
  define( 'FS_API__PROTOCOL', version_compare( $curl_version['version'], '7.37', '>=' ) ? 'https' : 'http' );
43
 
44
+ if ( ! defined( 'FS_API__LOGGER_ON' ) ) {
45
+ define( 'FS_API__LOGGER_ON', false );
46
+ }
47
+
48
  if ( ! defined( 'FS_API__ADDRESS' ) ) {
49
  define( 'FS_API__ADDRESS', '://api.freemius.com' );
50
  }
53
  }
54
 
55
  class Freemius_Api extends Freemius_Api_Base {
56
+ private static $_logger = array();
 
 
 
 
 
 
 
 
57
 
58
  /**
59
  * @param string $pScope 'app', 'developer', 'user' or 'install'.
232
  ) ), $this->_isSandbox );
233
  }
234
 
235
+ /**
236
+ * @param resource $pCurlHandler
237
+ * @param array $pCurlOptions
238
+ *
239
+ * @return mixed
240
+ */
241
+ private static function ExecuteRequest( &$pCurlHandler, &$pCurlOptions ) {
242
+ $start = microtime( true );
243
+
244
+ $result = curl_exec( $pCurlHandler );
245
+
246
+ if ( FS_API__LOGGER_ON ) {
247
+ $end = microtime( true );
248
+
249
+ $has_body = ( isset( $pCurlOptions[ CURLOPT_POST ] ) && 0 < $pCurlOptions[ CURLOPT_POST ] );
250
+
251
+ self::$_logger[] = array(
252
+ 'id' => count( self::$_logger ),
253
+ 'start' => $start,
254
+ 'end' => $end,
255
+ 'total' => ( $end - $start ),
256
+ 'method' => $pCurlOptions[ CURLOPT_CUSTOMREQUEST ],
257
+ 'path' => $pCurlOptions[ CURLOPT_URL ],
258
+ 'body' => $has_body ? $pCurlOptions[ CURLOPT_POSTFIELDS ] : null,
259
+ 'result' => $result,
260
+ 'code' => curl_getinfo( $pCurlHandler, CURLINFO_HTTP_CODE ),
261
+ 'backtrace' => debug_backtrace(),
262
+ );
263
+ }
264
+
265
+ return $result;
266
+ }
267
+
268
+ /**
269
+ * @return array
270
+ */
271
+ static function GetLogger() {
272
+ return self::$_logger;
273
+ }
274
+
275
  /**
276
  * @param string $pCanonizedPath
277
  * @param string $pMethod
307
  $pCurlHandler = curl_init();
308
  }
309
 
310
+ $opts = array(
311
+ CURLOPT_CONNECTTIMEOUT => 10,
312
+ CURLOPT_RETURNTRANSFER => true,
313
+ CURLOPT_TIMEOUT => 60,
314
+ CURLOPT_USERAGENT => FS_SDK__USER_AGENT,
315
+ );
316
 
317
  if ( ! isset( $opts[ CURLOPT_HTTPHEADER ] ) || ! is_array( $opts[ CURLOPT_HTTPHEADER ] ) ) {
318
  $opts[ CURLOPT_HTTPHEADER ] = array();
328
  $opts[ CURLOPT_RETURNTRANSFER ] = true;
329
  }
330
 
331
+ $request_url = Freemius_Api::GetUrl( $pCanonizedPath, $pIsSandbox );
332
+
333
+ $opts[ CURLOPT_URL ] = $request_url;
334
  $opts[ CURLOPT_CUSTOMREQUEST ] = $pMethod;
335
 
336
  $resource = explode( '?', $pCanonizedPath );
339
  // for 2 seconds if the server does not support this header.
340
  $opts[ CURLOPT_HTTPHEADER ][] = 'Expect:';
341
 
342
+ if ( 'https' === substr( strtolower( $request_url ), 0, 5 ) ) {
343
  $opts[ CURLOPT_SSL_VERIFYHOST ] = false;
344
  $opts[ CURLOPT_SSL_VERIFYPEER ] = false;
345
  }
351
  }
352
 
353
  curl_setopt_array( $pCurlHandler, $opts );
354
+ $result = self::ExecuteRequest( $pCurlHandler, $opts );
355
 
356
  /*if (curl_errno($ch) == 60) // CURLE_SSL_CACERT
357
  {
372
  if ( preg_match( $regex, curl_error( $pCurlHandler ), $matches ) ) {
373
  if ( strlen( @inet_pton( $matches[1] ) ) === 16 ) {
374
  // self::errorLog('Invalid IPv6 configuration on server, Please disable or get native IPv6 on your server.');
375
+ $opts[ CURLOPT_IPRESOLVE ] = CURL_IPRESOLVE_V4;
376
  curl_setopt( $pCurlHandler, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
377
+ $result = self::ExecuteRequest( $pCurlHandler, $opts );
378
  }
379
  }
380
  }
freemius/includes/sdk/FreemiusBase.php CHANGED
@@ -33,7 +33,7 @@
33
  );
34
 
35
  foreach ( $exceptions as $e ) {
36
- require FS_SDK__EXCEPTIONS_PATH . $e . '.php';
37
  }
38
 
39
  abstract class Freemius_Api_Base {
33
  );
34
 
35
  foreach ( $exceptions as $e ) {
36
+ require_once FS_SDK__EXCEPTIONS_PATH . $e . '.php';
37
  }
38
 
39
  abstract class Freemius_Api_Base {
freemius/languages/freemius-en.mo ADDED
Binary file
freemius/languages/freemius-en.po ADDED
@@ -0,0 +1,1396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+ # Copyright (C) 2016 freemius
15
+ # This file is distributed under the same license as the freemius package.
16
+ #: includes/i18n.php:41, includes/i18n.php:55
17
+ msgid "Yes - I'm in!"
18
+ msgstr "Yes - I'm in!"
19
+
20
+ #: includes/i18n.php:43, includes/i18n.php:57
21
+ msgid "Not today"
22
+ msgstr "Not today"
23
+
24
+ #: includes/i18n.php:69
25
+ msgid "Account"
26
+ msgstr "Account"
27
+
28
+ #: includes/i18n.php:71
29
+ msgid "Add On"
30
+ msgstr "Add On"
31
+
32
+ #: includes/i18n.php:73
33
+ msgid "Contact Us"
34
+ msgstr "Contact Us"
35
+
36
+ #: includes/i18n.php:75
37
+ msgid "Contact Support"
38
+ msgstr "Contact Support"
39
+
40
+ #: includes/i18n.php:77
41
+ msgid "Change Ownership"
42
+ msgstr "Change Ownership"
43
+
44
+ #: includes/i18n.php:79
45
+ msgid "Support"
46
+ msgstr "Support"
47
+
48
+ #: includes/i18n.php:81
49
+ msgid "Support Forum"
50
+ msgstr "Support Forum"
51
+
52
+ #: includes/i18n.php:83
53
+ msgid "Add Ons"
54
+ msgstr "Add Ons"
55
+
56
+ #: includes/i18n.php:85
57
+ msgctxt "verb"
58
+ msgid "Upgrade"
59
+ msgstr "Upgrade"
60
+
61
+ #: includes/i18n.php:87
62
+ msgid "Awesome"
63
+ msgstr "Awesome"
64
+
65
+ #: includes/i18n.php:89
66
+ msgctxt "noun"
67
+ msgid "Pricing"
68
+ msgstr "Pricing"
69
+
70
+ #: includes/i18n.php:91
71
+ msgctxt "noun"
72
+ msgid "Price"
73
+ msgstr "Price"
74
+
75
+ #: includes/i18n.php:93
76
+ msgid "Unlimited Updates"
77
+ msgstr "Unlimited Updates"
78
+
79
+ #: includes/i18n.php:95
80
+ msgctxt "verb"
81
+ msgid "Downgrade"
82
+ msgstr "Downgrade"
83
+
84
+ #: includes/i18n.php:97
85
+ msgid "Cancel Trial"
86
+ msgstr "Cancel Trial"
87
+
88
+ #: includes/i18n.php:99
89
+ msgid "Free Trial"
90
+ msgstr "Free Trial"
91
+
92
+ #: includes/i18n.php:101
93
+ msgid "Start my free %s"
94
+ msgstr "Start my free %s"
95
+
96
+ #: includes/i18n.php:103
97
+ msgid "No commitment for %s - cancel anytime"
98
+ msgstr "No commitment for %s - cancel anytime"
99
+
100
+ #: includes/i18n.php:105
101
+ msgid "After your free %s, pay as little as %s"
102
+ msgstr "After your free %s, pay as little as %s"
103
+
104
+ #: includes/i18n.php:107
105
+ msgid "Details"
106
+ msgstr "Details"
107
+
108
+ #: includes/i18n.php:109
109
+ msgid "Account Details"
110
+ msgstr "Account Details"
111
+
112
+ #: includes/i18n.php:111
113
+ msgctxt "verb"
114
+ msgid "Delete"
115
+ msgstr "Delete"
116
+
117
+ #: includes/i18n.php:113
118
+ msgctxt "verb"
119
+ msgid "Show"
120
+ msgstr "Show"
121
+
122
+ #: includes/i18n.php:115
123
+ msgctxt "verb"
124
+ msgid "Hide"
125
+ msgstr "Hide"
126
+
127
+ #: includes/i18n.php:117
128
+ msgctxt "verb"
129
+ msgid "Edit"
130
+ msgstr "Edit"
131
+
132
+ #: includes/i18n.php:119
133
+ msgid "Date"
134
+ msgstr "Date"
135
+
136
+ #: includes/i18n.php:121
137
+ msgid "Amount"
138
+ msgstr "Amount"
139
+
140
+ #: includes/i18n.php:123
141
+ msgid "Invoice"
142
+ msgstr "Invoice"
143
+
144
+ #: includes/i18n.php:125
145
+ msgid "Billing"
146
+ msgstr "Billing"
147
+
148
+ #: includes/i18n.php:127
149
+ msgid "Payments"
150
+ msgstr "Payments"
151
+
152
+ #: includes/i18n.php:129
153
+ msgid "Delete Account"
154
+ msgstr "Delete Account"
155
+
156
+ #: includes/i18n.php:131
157
+ msgctxt "as close a window"
158
+ msgid "Dismiss"
159
+ msgstr "Dismiss"
160
+
161
+ #: includes/i18n.php:133
162
+ msgctxt "as product pricing plan"
163
+ msgid "Plan"
164
+ msgstr "Plan"
165
+
166
+ #: includes/i18n.php:135
167
+ msgid "Change Plan"
168
+ msgstr "Change Plan"
169
+
170
+ #: includes/i18n.php:137
171
+ msgctxt "as download professional version"
172
+ msgid "Download %s Version"
173
+ msgstr "Download %s Version"
174
+
175
+ #: includes/i18n.php:139
176
+ msgctxt "as download professional version now"
177
+ msgid "Download %s version now"
178
+ msgstr "Download %s version now"
179
+
180
+ #: includes/i18n.php:141
181
+ msgctxt "as download latest version"
182
+ msgid "Download Latest"
183
+ msgstr "Download Latest"
184
+
185
+ #: includes/i18n.php:143
186
+ msgctxt "E.g. you have a professional license."
187
+ msgid "You have a %s license."
188
+ msgstr "You have a %s license."
189
+
190
+ #: includes/i18n.php:145
191
+ msgid "New"
192
+ msgstr "New"
193
+
194
+ #: includes/i18n.php:147
195
+ msgid "Free"
196
+ msgstr "Free"
197
+
198
+ #: includes/i18n.php:149
199
+ msgctxt "as trial plan"
200
+ msgid "Trial"
201
+ msgstr "Trial"
202
+
203
+ #: includes/i18n.php:151
204
+ msgctxt "verb"
205
+ msgid "Purchase"
206
+ msgstr "Purchase"
207
+
208
+ #: includes/i18n.php:153
209
+ msgid "Purchase License"
210
+ msgstr "Purchase License"
211
+
212
+ #: includes/i18n.php:155
213
+ msgctxt "verb"
214
+ msgid "Buy"
215
+ msgstr "Buy"
216
+
217
+ #: includes/i18n.php:157
218
+ msgid "Buy License"
219
+ msgstr "Buy License"
220
+
221
+ #: includes/i18n.php:159
222
+ msgid "Single Site License"
223
+ msgstr "Single Site License"
224
+
225
+ #: includes/i18n.php:161
226
+ msgid "Unlimited Licenses"
227
+ msgstr "Unlimited Licenses"
228
+
229
+ #: includes/i18n.php:163
230
+ msgid "Up to %s Sites"
231
+ msgstr "Up to %s Sites"
232
+
233
+ #: includes/i18n.php:165
234
+ msgid "%sRenew your license now%s to access version %s features and support."
235
+ msgstr "%sRenew your license now%s to access version %s features and support."
236
+
237
+ #: includes/i18n.php:167
238
+ msgid "Enter the email address you've used for the upgrade below and we will resend you the license key."
239
+ msgstr "Enter the email address you've used for the upgrade below and we will resend you the license key."
240
+
241
+ #: includes/i18n.php:169
242
+ msgctxt "e.g. Professional Plan"
243
+ msgid "%s Plan"
244
+ msgstr "%s Plan"
245
+
246
+ #: includes/i18n.php:171
247
+ msgid "You are just one step away - %s"
248
+ msgstr "You are just one step away - %s"
249
+
250
+ #: includes/i18n.php:173
251
+ msgctxt "%s - plugin name. As complete \"Jetpack\" activation now"
252
+ msgid "Complete \"%s\" Activation Now"
253
+ msgstr "Complete \"%s\" Activation Now"
254
+
255
+ #: includes/i18n.php:175
256
+ msgid "We made a few tweaks to the plugin, %s"
257
+ msgstr "We made a few tweaks to the plugin, %s"
258
+
259
+ #: includes/i18n.php:177
260
+ msgid "Opt-in to make \"%s\" Better!"
261
+ msgstr "Opt-in to make \"%s\" Better!"
262
+
263
+ #: includes/i18n.php:179
264
+ msgid "Error"
265
+ msgstr "Error"
266
+
267
+ #: includes/i18n.php:181
268
+ msgid "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
269
+ msgstr "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
270
+
271
+ #: includes/i18n.php:187
272
+ msgctxt "as expiration date"
273
+ msgid "Expiration"
274
+ msgstr "Expiration"
275
+
276
+ #: includes/i18n.php:189
277
+ msgctxt "as software license"
278
+ msgid "License"
279
+ msgstr "License"
280
+
281
+ #: includes/i18n.php:191
282
+ msgid "not verified"
283
+ msgstr "not verified"
284
+
285
+ #: includes/i18n.php:193
286
+ msgid "Verify Email"
287
+ msgstr "Verify Email"
288
+
289
+ #: includes/i18n.php:195
290
+ msgctxt "e.g. expires in 2 months"
291
+ msgid "Expires in %s"
292
+ msgstr "Expires in %s"
293
+
294
+ #: includes/i18n.php:197
295
+ msgctxt "e.g. auto renews in 2 months"
296
+ msgid "Auto renews in %s"
297
+ msgstr "Auto renews in %s"
298
+
299
+ #: includes/i18n.php:199
300
+ msgid "No expiration"
301
+ msgstr "No expiration"
302
+
303
+ #: includes/i18n.php:201
304
+ msgid "Expired"
305
+ msgstr "Expired"
306
+
307
+ #: includes/i18n.php:203
308
+ msgid "Cancelled"
309
+ msgstr "Cancelled"
310
+
311
+ #: includes/i18n.php:205
312
+ msgctxt "e.g. In 2 hours"
313
+ msgid "In %s"
314
+ msgstr "In %s"
315
+
316
+ #: includes/i18n.php:207
317
+ msgctxt "e.g. 2 min ago"
318
+ msgid "%s ago"
319
+ msgstr "%s ago"
320
+
321
+ #: includes/i18n.php:209
322
+ msgctxt "as plugin version"
323
+ msgid "Version"
324
+ msgstr "Version"
325
+
326
+ #: includes/i18n.php:211
327
+ msgid "Name"
328
+ msgstr "Name"
329
+
330
+ #: includes/i18n.php:213
331
+ msgid "Email"
332
+ msgstr "Email"
333
+
334
+ #: includes/i18n.php:215
335
+ msgid "Email address"
336
+ msgstr "Email address"
337
+
338
+ #: includes/i18n.php:217
339
+ msgid "Verified"
340
+ msgstr "Verified"
341
+
342
+ #: includes/i18n.php:219
343
+ msgid "Plugin"
344
+ msgstr "Plugin"
345
+
346
+ #: includes/i18n.php:221
347
+ msgid "Plugins"
348
+ msgstr "Plugins"
349
+
350
+ #: includes/i18n.php:223
351
+ msgid "Themes"
352
+ msgstr "Themes"
353
+
354
+ #: includes/i18n.php:225
355
+ msgctxt "as file/folder path"
356
+ msgid "Path"
357
+ msgstr "Path"
358
+
359
+ #: includes/i18n.php:227
360
+ msgid "Title"
361
+ msgstr "Title"
362
+
363
+ #: includes/i18n.php:229
364
+ msgid "Free version"
365
+ msgstr "Free version"
366
+
367
+ #: includes/i18n.php:231
368
+ msgid "Premium version"
369
+ msgstr "Premium version"
370
+
371
+ #: includes/i18n.php:233
372
+ msgctxt "as WP plugin slug"
373
+ msgid "Slug"
374
+ msgstr "Slug"
375
+
376
+ #: includes/i18n.php:235
377
+ msgid "ID"
378
+ msgstr "ID"
379
+
380
+ #: includes/i18n.php:237
381
+ msgid "Users"
382
+ msgstr "Users"
383
+
384
+ #: includes/i18n.php:239
385
+ msgid "Plugin Installs"
386
+ msgstr "Plugin Installs"
387
+
388
+ #: includes/i18n.php:241
389
+ msgctxt "like websites"
390
+ msgid "Sites"
391
+ msgstr "Sites"
392
+
393
+ #: includes/i18n.php:243
394
+ msgid "User ID"
395
+ msgstr "User ID"
396
+
397
+ #: includes/i18n.php:245
398
+ msgid "Site ID"
399
+ msgstr "Site ID"
400
+
401
+ #: includes/i18n.php:247
402
+ msgid "Public Key"
403
+ msgstr "Public Key"
404
+
405
+ #: includes/i18n.php:249
406
+ msgid "Secret Key"
407
+ msgstr "Secret Key"
408
+
409
+ #: includes/i18n.php:251
410
+ msgctxt "as secret encryption key missing"
411
+ msgid "No Secret"
412
+ msgstr "No Secret"
413
+
414
+ #: includes/i18n.php:253
415
+ msgid "No ID"
416
+ msgstr "No ID"
417
+
418
+ #: includes/i18n.php:255
419
+ msgctxt "as synchronize license"
420
+ msgid "Sync License"
421
+ msgstr "Sync License"
422
+
423
+ #: includes/i18n.php:257
424
+ msgctxt "as synchronize"
425
+ msgid "Sync"
426
+ msgstr "Sync"
427
+
428
+ #: includes/i18n.php:259
429
+ msgid "Activate License"
430
+ msgstr "Activate License"
431
+
432
+ #: includes/i18n.php:261
433
+ msgid "Activate Free Version"
434
+ msgstr "Activate Free Version"
435
+
436
+ #: includes/i18n.php:263
437
+ msgid "Please enter the license key that you received in the email right after the purchase:"
438
+ msgstr "Please enter the license key that you received in the email right after the purchase:"
439
+
440
+ #: includes/i18n.php:265
441
+ msgid "Activating license..."
442
+ msgstr "Activating license..."
443
+
444
+ #: includes/i18n.php:267
445
+ msgid "Change License"
446
+ msgstr "Change License"
447
+
448
+ #: includes/i18n.php:269
449
+ msgid "Update License"
450
+ msgstr "Update License"
451
+
452
+ #: includes/i18n.php:271
453
+ msgid "Deactivate License"
454
+ msgstr "Deactivate License"
455
+
456
+ #: includes/i18n.php:273
457
+ msgid "Activate"
458
+ msgstr "Activate"
459
+
460
+ #: includes/i18n.php:275
461
+ msgid "Deactivate"
462
+ msgstr "Deactivate"
463
+
464
+ #: includes/i18n.php:277
465
+ msgid "Skip & Deactivate"
466
+ msgstr "Skip & Deactivate"
467
+
468
+ #: includes/i18n.php:279
469
+ msgid "No - just deactivate"
470
+ msgstr "No - just deactivate"
471
+
472
+ #: includes/i18n.php:281
473
+ msgid "Yes - do your thing"
474
+ msgstr "Yes - do your thing"
475
+
476
+ #: includes/i18n.php:283
477
+ msgctxt "active mode"
478
+ msgid "Active"
479
+ msgstr "Active"
480
+
481
+ #: includes/i18n.php:285
482
+ msgctxt "is active mode?"
483
+ msgid "Is Active"
484
+ msgstr "Is Active"
485
+
486
+ #: includes/i18n.php:287
487
+ msgid "Install Now"
488
+ msgstr "Install Now"
489
+
490
+ #: includes/i18n.php:289
491
+ msgid "Install Update Now"
492
+ msgstr "Install Update Now"
493
+
494
+ #: includes/i18n.php:291
495
+ msgid "More information about %s"
496
+ msgstr "More information about %s"
497
+
498
+ #: includes/i18n.php:293
499
+ msgid "Localhost"
500
+ msgstr "Localhost"
501
+
502
+ #: includes/i18n.php:295
503
+ msgctxt "as activate Professional plan"
504
+ msgid "Activate %s Plan"
505
+ msgstr "Activate %s Plan"
506
+
507
+ #: includes/i18n.php:297
508
+ msgctxt "as 5 licenses left"
509
+ msgid "%s left"
510
+ msgstr "%s left"
511
+
512
+ #: includes/i18n.php:299
513
+ msgid "Last license"
514
+ msgstr "Last license"
515
+
516
+ #: includes/i18n.php:301
517
+ msgid "What is your %s?"
518
+ msgstr "What is your %s?"
519
+
520
+ #: includes/i18n.php:303
521
+ msgid "Activate this add-on"
522
+ msgstr "Activate this add-on"
523
+
524
+ #: includes/i18n.php:305
525
+ msgid "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?"
526
+ msgstr "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?"
527
+
528
+ #: includes/i18n.php:307
529
+ msgid "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?"
530
+ msgstr "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?"
531
+
532
+ #: includes/i18n.php:309
533
+ msgid "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?"
534
+ msgstr "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?"
535
+
536
+ #: includes/i18n.php:311
537
+ msgid "Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s."
538
+ msgstr "Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s."
539
+
540
+ #: includes/i18n.php:313
541
+ msgid "Cancelling the trial will immediately block access to all premium features. Are you sure?"
542
+ msgstr "Cancelling the trial will immediately block access to all premium features. Are you sure?"
543
+
544
+ #: includes/i18n.php:315
545
+ msgid "You can still enjoy all %s features but you will not have access to plugin updates and support."
546
+ msgstr "You can still enjoy all %s features but you will not have access to plugin updates and support."
547
+
548
+ #: includes/i18n.php:317
549
+ msgid "Once your license expire you can still use the Free version but you will NOT have access to the %s features."
550
+ msgstr "Once your license expire you can still use the Free version but you will NOT have access to the %s features."
551
+
552
+ #: includes/i18n.php:319
553
+ msgid "Are you sure you want to proceed?"
554
+ msgstr "Are you sure you want to proceed?"
555
+
556
+ #: includes/i18n.php:325
557
+ msgid "Add Ons for %s"
558
+ msgstr "Add Ons for %s"
559
+
560
+ #: includes/i18n.php:327
561
+ msgid "We could'nt load the add-ons list. It's probably an issue on our side, please try to come back in few minutes."
562
+ msgstr "We could'nt load the add-ons list. It's probably an issue on our side, please try to come back in few minutes."
563
+
564
+ #: includes/i18n.php:331
565
+ msgid "Anonymous feedback"
566
+ msgstr "Anonymous feedback"
567
+
568
+ #: includes/i18n.php:333
569
+ msgid "Quick feedback"
570
+ msgstr "Quick feedback"
571
+
572
+ #: includes/i18n.php:335
573
+ msgid "If you have a moment, please let us know why you are deactivating"
574
+ msgstr "If you have a moment, please let us know why you are deactivating"
575
+
576
+ #: includes/i18n.php:337
577
+ msgid "Yes - Deactivate"
578
+ msgstr "Yes - Deactivate"
579
+
580
+ #: includes/i18n.php:339
581
+ msgid "Submit & Deactivate"
582
+ msgstr "Submit & Deactivate"
583
+
584
+ #: includes/i18n.php:341
585
+ msgctxt "the text of the cancel button of the plugin deactivation dialog box."
586
+ msgid "Cancel"
587
+ msgstr "Cancel"
588
+
589
+ #: includes/i18n.php:343
590
+ msgid "I no longer need the plugin"
591
+ msgstr "I no longer need the plugin"
592
+
593
+ #: includes/i18n.php:345
594
+ msgid "I found a better plugin"
595
+ msgstr "I found a better plugin"
596
+
597
+ #: includes/i18n.php:347
598
+ msgid "I only needed the plugin for a short period"
599
+ msgstr "I only needed the plugin for a short period"
600
+
601
+ #: includes/i18n.php:349
602
+ msgid "The plugin broke my site"
603
+ msgstr "The plugin broke my site"
604
+
605
+ #: includes/i18n.php:351
606
+ msgid "The plugin suddenly stopped working"
607
+ msgstr "The plugin suddenly stopped working"
608
+
609
+ #: includes/i18n.php:353
610
+ msgid "I can't pay for it anymore"
611
+ msgstr "I can't pay for it anymore"
612
+
613
+ #: includes/i18n.php:355
614
+ msgid "It's a temporary deactivation. I'm just debugging an issue."
615
+ msgstr "It's a temporary deactivation. I'm just debugging an issue."
616
+
617
+ #: includes/i18n.php:357
618
+ msgctxt "the text of the \"other\" reason for deactivating the plugin that is shown in the modal box."
619
+ msgid "Other"
620
+ msgstr "Other"
621
+
622
+ #: includes/i18n.php:359
623
+ msgid "Kindly tell us the reason so we can improve."
624
+ msgstr "Kindly tell us the reason so we can improve."
625
+
626
+ #: includes/i18n.php:361
627
+ msgid "What's the plugin's name?"
628
+ msgstr "What's the plugin's name?"
629
+
630
+ #: includes/i18n.php:363
631
+ msgid "What price would you feel comfortable paying?"
632
+ msgstr "What price would you feel comfortable paying?"
633
+
634
+ #: includes/i18n.php:365
635
+ msgid "I couldn't understand how to make it work"
636
+ msgstr "I couldn't understand how to make it work"
637
+
638
+ #: includes/i18n.php:367
639
+ msgid "The plugin is great, but I need specific feature that you don't support"
640
+ msgstr "The plugin is great, but I need specific feature that you don't support"
641
+
642
+ #: includes/i18n.php:369
643
+ msgid "The plugin is not working"
644
+ msgstr "The plugin is not working"
645
+
646
+ #: includes/i18n.php:371
647
+ msgid "It's not what I was looking for"
648
+ msgstr "It's not what I was looking for"
649
+
650
+ #: includes/i18n.php:373
651
+ msgid "The plugin didn't work as expected"
652
+ msgstr "The plugin didn't work as expected"
653
+
654
+ #: includes/i18n.php:375
655
+ msgid "What feature?"
656
+ msgstr "What feature?"
657
+
658
+ #: includes/i18n.php:377
659
+ msgid "Kindly share what didn't work so we can fix it for future users..."
660
+ msgstr "Kindly share what didn't work so we can fix it for future users..."
661
+
662
+ #: includes/i18n.php:379
663
+ msgid "What you've been looking for?"
664
+ msgstr "What you've been looking for?"
665
+
666
+ #: includes/i18n.php:381
667
+ msgid "What did you expect?"
668
+ msgstr "What did you expect?"
669
+
670
+ #: includes/i18n.php:383
671
+ msgid "The plugin didn't work"
672
+ msgstr "The plugin didn't work"
673
+
674
+ #: includes/i18n.php:385
675
+ msgid "I don't like to share my information with you"
676
+ msgstr "I don't like to share my information with you"
677
+
678
+ #: includes/i18n.php:387
679
+ msgid "You might have missed it, but you don't have to share any data and can just %s the opt-in."
680
+ msgstr "You might have missed it, but you don't have to share any data and can just %s the opt-in."
681
+
682
+ #: includes/i18n.php:395
683
+ msgctxt "greeting"
684
+ msgid "Hey %s,"
685
+ msgstr "Hey %s,"
686
+
687
+ #: includes/i18n.php:397
688
+ msgctxt "a greeting. E.g. Thanks John!"
689
+ msgid "Thanks %s!"
690
+ msgstr "Thanks %s!"
691
+
692
+ #: includes/i18n.php:399
693
+ msgid "In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s"
694
+ msgstr "In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s"
695
+
696
+ #: includes/i18n.php:401
697
+ msgid "Please help us improve %2$s! If you opt-in, some data about your usage of %2$s will be sent to %5$s. If you skip this, that's okay! %2$s will still work just fine."
698
+ msgstr "Please help us improve %2$s! If you opt-in, some data about your usage of %2$s will be sent to %5$s. If you skip this, that's okay! %2$s will still work just fine."
699
+
700
+ #: includes/i18n.php:403
701
+ msgid "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."
702
+ msgstr "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."
703
+
704
+ #: includes/i18n.php:405
705
+ msgid "Thanks for purchasing %s! To get started, please enter your license key:"
706
+ msgstr "Thanks for purchasing %s! To get started, please enter your license key:"
707
+
708
+ #: includes/i18n.php:407
709
+ msgid "The plugin will be periodically sending data to %s to check for plugin updates and verify the validity of your license."
710
+ msgstr "The plugin will be periodically sending data to %s to check for plugin updates and verify the validity of your license."
711
+
712
+ #: includes/i18n.php:409
713
+ msgid "What permissions are being granted?"
714
+ msgstr "What permissions are being granted?"
715
+
716
+ #: includes/i18n.php:411
717
+ msgid "Your Profile Overview"
718
+ msgstr "Your Profile Overview"
719
+
720
+ #: includes/i18n.php:413
721
+ msgid "Name and email address"
722
+ msgstr "Name and email address"
723
+
724
+ #: includes/i18n.php:415
725
+ msgid "Your Site Overview"
726
+ msgstr "Your Site Overview"
727
+
728
+ #: includes/i18n.php:417
729
+ msgid "Site URL, WP version, PHP info, plugins & themes"
730
+ msgstr "Site URL, WP version, PHP info, plugins & themes"
731
+
732
+ #: includes/i18n.php:419
733
+ msgid "Current Plugin Events"
734
+ msgstr "Current Plugin Events"
735
+
736
+ #: includes/i18n.php:421
737
+ msgid "Activation, deactivation and uninstall"
738
+ msgstr "Activation, deactivation and uninstall"
739
+
740
+ #: includes/i18n.php:423
741
+ msgid "Plugins & Themes"
742
+ msgstr "Plugins & Themes"
743
+
744
+ #: includes/i18n.php:425
745
+ msgid "Titles, versions and state."
746
+ msgstr "Titles, versions and state."
747
+
748
+ #: includes/i18n.php:427
749
+ msgid "Newsletter"
750
+ msgstr "Newsletter"
751
+
752
+ #: includes/i18n.php:429
753
+ msgid "Updates, announcements, marketing, no spam"
754
+ msgstr "Updates, announcements, marketing, no spam"
755
+
756
+ #: includes/i18n.php:431
757
+ msgid "Privacy Policy"
758
+ msgstr "Privacy Policy"
759
+
760
+ #: includes/i18n.php:433
761
+ msgid "Terms of Service"
762
+ msgstr "Terms of Service"
763
+
764
+ #: includes/i18n.php:435
765
+ msgctxt "as activating plugin"
766
+ msgid "Activating"
767
+ msgstr "Activating"
768
+
769
+ #: includes/i18n.php:437
770
+ msgctxt "as in the process of sending an email"
771
+ msgid "Sending email"
772
+ msgstr "Sending email"
773
+
774
+ #: includes/i18n.php:439
775
+ msgctxt "button label"
776
+ msgid "Allow & Continue"
777
+ msgstr "Allow & Continue"
778
+
779
+ #: includes/i18n.php:441
780
+ msgctxt "button label"
781
+ msgid "Agree & Activate License"
782
+ msgstr "Agree & Activate License"
783
+
784
+ #: includes/i18n.php:443
785
+ msgctxt "verb"
786
+ msgid "Skip"
787
+ msgstr "Skip"
788
+
789
+ #: includes/i18n.php:445
790
+ msgid "Click here to use the plugin anonymously"
791
+ msgstr "Click here to use the plugin anonymously"
792
+
793
+ #: includes/i18n.php:447
794
+ msgid "Re-send activation email"
795
+ msgstr "Re-send activation email"
796
+
797
+ #: includes/i18n.php:449
798
+ msgid "License key"
799
+ msgstr "License key"
800
+
801
+ #: includes/i18n.php:451
802
+ msgid "Send License Key"
803
+ msgstr "Send License Key"
804
+
805
+ #: includes/i18n.php:453
806
+ msgid "Sending license key"
807
+ msgstr "Sending license key"
808
+
809
+ #: includes/i18n.php:455
810
+ msgid "Have a license key?"
811
+ msgstr "Have a license key?"
812
+
813
+ #: includes/i18n.php:457
814
+ msgid "Don't have a license key?"
815
+ msgstr "Don't have a license key?"
816
+
817
+ #: includes/i18n.php:459
818
+ msgid "Can't find your license key?"
819
+ msgstr "Can't find your license key?"
820
+
821
+ #: includes/i18n.php:471
822
+ msgid "Screenshots"
823
+ msgstr "Screenshots"
824
+
825
+ #: includes/i18n.php:473
826
+ msgid "Click to view full-size screenshot %d"
827
+ msgstr "Click to view full-size screenshot %d"
828
+
829
+ #: includes/i18n.php:481
830
+ msgid "Freemius Debug"
831
+ msgstr "Freemius Debug"
832
+
833
+ #: includes/i18n.php:483
834
+ msgctxt "as turned on"
835
+ msgid "On"
836
+ msgstr "On"
837
+
838
+ #: includes/i18n.php:485
839
+ msgctxt "as turned off"
840
+ msgid "Off"
841
+ msgstr "Off"
842
+
843
+ #: includes/i18n.php:487
844
+ msgctxt "as code debugging"
845
+ msgid "Debugging"
846
+ msgstr "Debugging"
847
+
848
+ #: includes/i18n.php:489
849
+ msgid "Freemius State"
850
+ msgstr "Freemius State"
851
+
852
+ #: includes/i18n.php:491
853
+ msgctxt "as connection was successful"
854
+ msgid "Connected"
855
+ msgstr "Connected"
856
+
857
+ #: includes/i18n.php:493
858
+ msgctxt "as connection blocked"
859
+ msgid "Blocked"
860
+ msgstr "Blocked"
861
+
862
+ #: includes/i18n.php:495
863
+ msgctxt "as application program interface"
864
+ msgid "API"
865
+ msgstr "API"
866
+
867
+ #: includes/i18n.php:497
868
+ msgctxt "as software development kit versions"
869
+ msgid "SDK"
870
+ msgstr "SDK"
871
+
872
+ #: includes/i18n.php:499
873
+ msgctxt "as software development kit versions"
874
+ msgid "SDK Versions"
875
+ msgstr "SDK Versions"
876
+
877
+ #: includes/i18n.php:501
878
+ msgctxt "as plugin folder path"
879
+ msgid "Plugin Path"
880
+ msgstr "Plugin Path"
881
+
882
+ #: includes/i18n.php:503
883
+ msgctxt "as sdk path"
884
+ msgid "SDK Path"
885
+ msgstr "SDK Path"
886
+
887
+ #: includes/i18n.php:505
888
+ msgid "Add Ons of Plugin %s"
889
+ msgstr "Add Ons of Plugin %s"
890
+
891
+ #: includes/i18n.php:507
892
+ msgid "Are you sure you want to delete all Freemius data?"
893
+ msgstr "Are you sure you want to delete all Freemius data?"
894
+
895
+ #: includes/i18n.php:509
896
+ msgid "Actions"
897
+ msgstr "Actions"
898
+
899
+ #: includes/i18n.php:511
900
+ msgid "Delete All Accounts"
901
+ msgstr "Delete All Accounts"
902
+
903
+ #: includes/i18n.php:513
904
+ msgid "Start Fresh"
905
+ msgstr "Start Fresh"
906
+
907
+ #: includes/i18n.php:515
908
+ msgid "Clear API Cache"
909
+ msgstr "Clear API Cache"
910
+
911
+ #: includes/i18n.php:517
912
+ msgid "Sync Data From Server"
913
+ msgstr "Sync Data From Server"
914
+
915
+ #: includes/i18n.php:519
916
+ msgid "Scheduled Crons"
917
+ msgstr "Scheduled Crons"
918
+
919
+ #: includes/i18n.php:521
920
+ msgid "Plugins & Themes Sync"
921
+ msgstr "Plugins & Themes Sync"
922
+
923
+ #: includes/i18n.php:529
924
+ msgctxt "as congratulations"
925
+ msgid "Congrats"
926
+ msgstr "Congrats"
927
+
928
+ #: includes/i18n.php:531
929
+ msgctxt "exclamation"
930
+ msgid "Oops"
931
+ msgstr "Oops"
932
+
933
+ #: includes/i18n.php:533
934
+ msgctxt "interjection expressing joy or exuberance"
935
+ msgid "Yee-haw"
936
+ msgstr "Yee-haw"
937
+
938
+ #: includes/i18n.php:535
939
+ msgctxt "(especially in electronic communication) used to express elation, enthusiasm, or triumph."
940
+ msgid "W00t"
941
+ msgstr "W00t"
942
+
943
+ #: includes/i18n.php:537
944
+ msgctxt "a positive response"
945
+ msgid "Right on"
946
+ msgstr "Right on"
947
+
948
+ #: includes/i18n.php:539
949
+ msgctxt "something somebody says when they are thinking about what you have just said. "
950
+ msgid "Hmm"
951
+ msgstr "Hmm"
952
+
953
+ #: includes/i18n.php:541
954
+ msgid "O.K"
955
+ msgstr "O.K"
956
+
957
+ #: includes/i18n.php:543
958
+ msgctxt "exclamation"
959
+ msgid "Hey"
960
+ msgstr "Hey"
961
+
962
+ #: includes/i18n.php:545
963
+ msgctxt "advance notice of something that will need attention."
964
+ msgid "Heads up"
965
+ msgstr "Heads up"
966
+
967
+ #: includes/i18n.php:553
968
+ msgid "Seems like you got the latest release."
969
+ msgstr "Seems like you got the latest release."
970
+
971
+ #: includes/i18n.php:555
972
+ msgid "You are all good!"
973
+ msgstr "You are all good!"
974
+
975
+ #: includes/i18n.php:557
976
+ msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
977
+ msgstr "Sorry, we could not complete the email update. Another user with the same email is already registered."
978
+
979
+ #: includes/i18n.php:559
980
+ msgid "If you would like to give up the ownership of the plugin's account to %s click the Change Ownership button."
981
+ msgstr "If you would like to give up the ownership of the plugin's account to %s click the Change Ownership button."
982
+
983
+ #: includes/i18n.php:561
984
+ msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
985
+ msgstr "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
986
+
987
+ #: includes/i18n.php:563
988
+ msgid "Your name was successfully updated."
989
+ msgstr "Your name was successfully updated."
990
+
991
+ #: includes/i18n.php:565
992
+ msgid "You have successfully updated your %s."
993
+ msgstr "You have successfully updated your %s."
994
+
995
+ #: includes/i18n.php:567
996
+ msgid "Please provide your full name."
997
+ msgstr "Please provide your full name."
998
+
999
+ #: includes/i18n.php:569
1000
+ msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
1001
+ msgstr "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
1002
+
1003
+ #: includes/i18n.php:571
1004
+ msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
1005
+ msgstr "Just letting you know that the add-ons information of %s is being pulled from an external server."
1006
+
1007
+ #: includes/i18n.php:573
1008
+ msgid "No credit card required"
1009
+ msgstr "No credit card required"
1010
+
1011
+ #: includes/i18n.php:575
1012
+ msgid "Premium plugin version was successfully activated."
1013
+ msgstr "Premium plugin version was successfully activated."
1014
+
1015
+ #: includes/i18n.php:577
1016
+ msgid "The upgrade of %s was successfully completed."
1017
+ msgstr "The upgrade of %s was successfully completed."
1018
+
1019
+ #: includes/i18n.php:579
1020
+ msgid "Your account was successfully activated with the %s plan."
1021
+ msgstr "Your account was successfully activated with the %s plan."
1022
+
1023
+ #: includes/i18n.php:581
1024
+ msgid "Download the latest %s version now"
1025
+ msgstr "Download the latest %s version now"
1026
+
1027
+ #: includes/i18n.php:583
1028
+ msgid "Please follow these steps to complete the upgrade"
1029
+ msgstr "Please follow these steps to complete the upgrade"
1030
+
1031
+ #: includes/i18n.php:585
1032
+ msgid "Download the latest %s version"
1033
+ msgstr "Download the latest %s version"
1034
+
1035
+ #: includes/i18n.php:587
1036
+ msgid "Deactivate the free version"
1037
+ msgstr "Deactivate the free version"
1038
+
1039
+ #: includes/i18n.php:589
1040
+ msgid "Upload and activate the downloaded version"
1041
+ msgstr "Upload and activate the downloaded version"
1042
+
1043
+ #: includes/i18n.php:591
1044
+ msgid "How to upload and activate?"
1045
+ msgstr "How to upload and activate?"
1046
+
1047
+ #: includes/i18n.php:593
1048
+ msgctxt "%s - product name, e.g. Facebook add-on was successfully..."
1049
+ msgid "%s Add-on was successfully purchased."
1050
+ msgstr "%s Add-on was successfully purchased."
1051
+
1052
+ #: includes/i18n.php:595
1053
+ msgid "Your %s Add-on plan was successfully upgraded."
1054
+ msgstr "Your %s Add-on plan was successfully upgraded."
1055
+
1056
+ #: includes/i18n.php:597
1057
+ msgid "Your email has been successfully verified - you are AWESOME!"
1058
+ msgstr "Your email has been successfully verified - you are AWESOME!"
1059
+
1060
+ #: includes/i18n.php:599
1061
+ msgid "Your plan was successfully upgraded."
1062
+ msgstr "Your plan was successfully upgraded."
1063
+
1064
+ #: includes/i18n.php:601
1065
+ msgid "Your plan was successfully changed to %s."
1066
+ msgstr "Your plan was successfully changed to %s."
1067
+
1068
+ #: includes/i18n.php:603
1069
+ msgid "Your license has expired. You can still continue using the free plugin forever."
1070
+ msgstr "Your license has expired. You can still continue using the free plugin forever."
1071
+
1072
+ #: includes/i18n.php:605
1073
+ msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
1074
+ msgstr "Your license has been cancelled. If you think it's a mistake, please contact support."
1075
+
1076
+ #: includes/i18n.php:607
1077
+ msgid "Your trial has been successfully started."
1078
+ msgstr "Your trial has been successfully started."
1079
+
1080
+ #: includes/i18n.php:609
1081
+ msgid "Your license was successfully activated."
1082
+ msgstr "Your license was successfully activated."
1083
+
1084
+ #: includes/i18n.php:611
1085
+ msgid "It looks like your site currently doesn't have an active license."
1086
+ msgstr "It looks like your site currently doesn't have an active license."
1087
+
1088
+ #: includes/i18n.php:613
1089
+ msgid "Your license was successfully deactivated, you are back to the %s plan."
1090
+ msgstr "Your license was successfully deactivated, you are back to the %s plan."
1091
+
1092
+ #: includes/i18n.php:615
1093
+ msgid "It looks like the license deactivation failed."
1094
+ msgstr "It looks like the license deactivation failed."
1095
+
1096
+ #: includes/i18n.php:617
1097
+ msgid "It looks like the license could not be activated."
1098
+ msgstr "It looks like the license could not be activated."
1099
+
1100
+ #: includes/i18n.php:619
1101
+ msgid "Error received from the server:"
1102
+ msgstr "Error received from the server:"
1103
+
1104
+ #: includes/i18n.php:621
1105
+ msgid "Your trial has expired. You can still continue using all our free features."
1106
+ msgstr "Your trial has expired. You can still continue using all our free features."
1107
+
1108
+ #: includes/i18n.php:623
1109
+ msgid "Your plan was successfully downgraded. Your %s plan license will expire in %s."
1110
+ msgstr "Your plan was successfully downgraded. Your %s plan license will expire in %s."
1111
+
1112
+ #: includes/i18n.php:625
1113
+ msgid "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
1114
+ msgstr "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
1115
+
1116
+ #: includes/i18n.php:627
1117
+ msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
1118
+ msgstr "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
1119
+
1120
+ #: includes/i18n.php:629
1121
+ msgid "Your %s free trial was successfully cancelled."
1122
+ msgstr "Your %s free trial was successfully cancelled."
1123
+
1124
+ #: includes/i18n.php:631
1125
+ msgctxt "%s - numeric version number"
1126
+ msgid "Version %s was released."
1127
+ msgstr "Version %s was released."
1128
+
1129
+ #: includes/i18n.php:633
1130
+ msgid "Please download %s."
1131
+ msgstr "Please download %s."
1132
+
1133
+ #: includes/i18n.php:635
1134
+ msgctxt "%s - plan name, as the latest professional version here"
1135
+ msgid "the latest %s version here"
1136
+ msgstr "the latest %s version here"
1137
+
1138
+ #: includes/i18n.php:637
1139
+ msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
1140
+ msgstr "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
1141
+
1142
+ #: includes/i18n.php:639
1143
+ msgctxt "call to action"
1144
+ msgid "Start free trial"
1145
+ msgstr "Start free trial"
1146
+
1147
+ #: includes/i18n.php:641
1148
+ msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
1149
+ msgstr "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
1150
+
1151
+ #: includes/i18n.php:643
1152
+ msgid "You already utilized a trial before."
1153
+ msgstr "You already utilized a trial before."
1154
+
1155
+ #: includes/i18n.php:645
1156
+ msgid "You are already running the plugin in a trial mode."
1157
+ msgstr "You are already running the plugin in a trial mode."
1158
+
1159
+ #: includes/i18n.php:647
1160
+ msgid "Plan %s do not exist, therefore, can't start a trial."
1161
+ msgstr "Plan %s do not exist, therefore, can't start a trial."
1162
+
1163
+ #: includes/i18n.php:649
1164
+ msgid "Plan %s does not support a trial period."
1165
+ msgstr "Plan %s does not support a trial period."
1166
+
1167
+ #: includes/i18n.php:651
1168
+ msgid "None of the plugin's plans supports a trial period."
1169
+ msgstr "None of the plugin's plans supports a trial period."
1170
+
1171
+ #: includes/i18n.php:653
1172
+ msgid "Unexpected API error. Please contact the plugin's author with the following error."
1173
+ msgstr "Unexpected API error. Please contact the plugin's author with the following error."
1174
+
1175
+ #: includes/i18n.php:655
1176
+ msgid "No commitment for %s days - cancel anytime!"
1177
+ msgstr "No commitment for %s days - cancel anytime!"
1178
+
1179
+ #: includes/i18n.php:657
1180
+ msgid "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."
1181
+ msgstr "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."
1182
+
1183
+ #: includes/i18n.php:659
1184
+ msgid "Couldn't activate %s."
1185
+ msgstr "Couldn't activate %s."
1186
+
1187
+ #: includes/i18n.php:661
1188
+ msgid "Please contact us with the following message:"
1189
+ msgstr "Please contact us with the following message:"
1190
+
1191
+ #: includes/i18n.php:663
1192
+ msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
1193
+ msgstr "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
1194
+
1195
+ #: includes/i18n.php:665
1196
+ msgid "Please contact us here"
1197
+ msgstr "Please contact us here"
1198
+
1199
+ #: includes/i18n.php:667
1200
+ msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
1201
+ msgstr "I have upgraded my account but when I try to Sync the License, the plan remains %s."
1202
+
1203
+ #: includes/i18n.php:673
1204
+ msgid "From unknown reason, the API connectivity test failed."
1205
+ msgstr "From unknown reason, the API connectivity test failed."
1206
+
1207
+ #: includes/i18n.php:675
1208
+ msgid "It's probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?"
1209
+ msgstr "It's probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?"
1210
+
1211
+ #: includes/i18n.php:677
1212
+ msgid "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."
1213
+ msgstr "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."
1214
+
1215
+ #: includes/i18n.php:679
1216
+ msgid "From unknown reason, CloudFlare, the firewall we use, blocks the connection."
1217
+ msgstr "From unknown reason, CloudFlare, the firewall we use, blocks the connection."
1218
+
1219
+ #: includes/i18n.php:681
1220
+ msgctxt "as pluginX requires an access to our API"
1221
+ msgid "%s requires an access to our API."
1222
+ msgstr "%s requires an access to our API."
1223
+
1224
+ #: includes/i18n.php:683
1225
+ msgid "It looks like your server is using Squid ACL (access control lists), which blocks the connection."
1226
+ msgstr "It looks like your server is using Squid ACL (access control lists), which blocks the connection."
1227
+
1228
+ #: includes/i18n.php:685
1229
+ msgid "I don't know what is Squid or ACL, help me!"
1230
+ msgstr "I don't know what is Squid or ACL, help me!"
1231
+
1232
+ #: includes/i18n.php:687, includes/i18n.php:695
1233
+ msgid "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."
1234
+ msgstr "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."
1235
+
1236
+ #: includes/i18n.php:689
1237
+ msgid "I'm a system administrator"
1238
+ msgstr "I'm a system administrator"
1239
+
1240
+ #: includes/i18n.php:691
1241
+ msgid "Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again."
1242
+ msgstr "Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again."
1243
+
1244
+ #: includes/i18n.php:693
1245
+ msgid "I don't know what is cURL or how to install it, help me!"
1246
+ msgstr "I don't know what is cURL or how to install it, help me!"
1247
+
1248
+ #: includes/i18n.php:697
1249
+ msgid "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."
1250
+ msgstr "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."
1251
+
1252
+ #: includes/i18n.php:699
1253
+ msgid "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."
1254
+ msgstr "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."
1255
+
1256
+ #: includes/i18n.php:701
1257
+ msgid "Sorry for the inconvenience and we are here to help if you give us a chance."
1258
+ msgstr "Sorry for the inconvenience and we are here to help if you give us a chance."
1259
+
1260
+ #: includes/i18n.php:703
1261
+ msgid "Yes - I'm giving you a chance to fix it"
1262
+ msgstr "Yes - I'm giving you a chance to fix it"
1263
+
1264
+ #: includes/i18n.php:705
1265
+ msgid "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."
1266
+ msgstr "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."
1267
+
1268
+ #: includes/i18n.php:707
1269
+ msgid "Let's try your previous version"
1270
+ msgstr "Let's try your previous version"
1271
+
1272
+ #: includes/i18n.php:709
1273
+ msgid "Uninstall this version and install the previous one."
1274
+ msgstr "Uninstall this version and install the previous one."
1275
+
1276
+ #: includes/i18n.php:711
1277
+ msgid "That's exhausting, please deactivate"
1278
+ msgstr "That's exhausting, please deactivate"
1279
+
1280
+ #: includes/i18n.php:713
1281
+ msgid "We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future."
1282
+ msgstr "We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future."
1283
+
1284
+ #: includes/i18n.php:715
1285
+ msgid "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."
1286
+ msgstr "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."
1287
+
1288
+ #: includes/i18n.php:717
1289
+ msgctxt "%1s - plugin title, %2s - API domain"
1290
+ msgid "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
1291
+ msgstr "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
1292
+
1293
+ #: includes/i18n.php:719
1294
+ msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
1295
+ msgstr "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
1296
+
1297
+ #: includes/i18n.php:725
1298
+ msgid "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."
1299
+ msgstr "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."
1300
+
1301
+ #: includes/i18n.php:727
1302
+ msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
1303
+ msgstr "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
1304
+
1305
+ #: includes/i18n.php:729
1306
+ msgid "%s is the new owner of the account."
1307
+ msgstr "%s is the new owner of the account."
1308
+
1309
+ #: includes/i18n.php:733
1310
+ msgctxt "addonX cannot run without pluginY"
1311
+ msgid "%s cannot run without %s."
1312
+ msgstr "%s cannot run without %s."
1313
+
1314
+ #: includes/i18n.php:735
1315
+ msgctxt "addonX cannot run..."
1316
+ msgid "%s cannot run without the plugin."
1317
+ msgstr "%s cannot run without the plugin."
1318
+
1319
+ #: includes/i18n.php:737
1320
+ msgctxt "pluginX activation was successfully..."
1321
+ msgid "%s activation was successfully completed."
1322
+ msgstr "%s activation was successfully completed."
1323
+
1324
+ #: includes/i18n.php:739
1325
+ msgctxt "Plugin installer section title"
1326
+ msgid "Features & Pricing"
1327
+ msgstr "Features & Pricing"
1328
+
1329
+ #: includes/i18n.php:741
1330
+ msgid "Add-on must be deployed to WordPress.org or Freemius."
1331
+ msgstr "Add-on must be deployed to WordPress.org or Freemius."
1332
+
1333
+ #: includes/i18n.php:743
1334
+ msgid "Paid add-on must be deployed to Freemius."
1335
+ msgstr "Paid add-on must be deployed to Freemius."
1336
+
1337
+ #: includes/i18n.php:747
1338
+ msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
1339
+ msgstr "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
1340
+
1341
+ #: includes/i18n.php:749
1342
+ msgid "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
1343
+ msgstr "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
1344
+
1345
+ #: includes/i18n.php:755
1346
+ msgctxt "as every month"
1347
+ msgid "Monthly"
1348
+ msgstr "Monthly"
1349
+
1350
+ #: includes/i18n.php:757
1351
+ msgctxt "as monthly period"
1352
+ msgid "mo"
1353
+ msgstr "mo"
1354
+
1355
+ #: includes/i18n.php:759
1356
+ msgctxt "as once a year"
1357
+ msgid "Annual"
1358
+ msgstr "Annual"
1359
+
1360
+ #: includes/i18n.php:761
1361
+ msgctxt "as once a year"
1362
+ msgid "Annually"
1363
+ msgstr "Annually"
1364
+
1365
+ #: includes/i18n.php:763
1366
+ msgctxt "as once a year"
1367
+ msgid "Once"
1368
+ msgstr "Once"
1369
+
1370
+ #: includes/i18n.php:765
1371
+ msgctxt "as annual period"
1372
+ msgid "year"
1373
+ msgstr "year"
1374
+
1375
+ #: includes/i18n.php:767
1376
+ msgid "Lifetime"
1377
+ msgstr "Lifetime"
1378
+
1379
+ #: includes/i18n.php:769
1380
+ msgctxt "e.g. the best product"
1381
+ msgid "Best"
1382
+ msgstr "Best"
1383
+
1384
+ #: includes/i18n.php:771
1385
+ msgctxt "e.g. billed monthly"
1386
+ msgid "Billed %s"
1387
+ msgstr "Billed %s"
1388
+
1389
+ #: includes/i18n.php:773
1390
+ msgctxt "as a discount of $5 or 10%"
1391
+ msgid "Save %s"
1392
+ msgstr "Save %s"
1393
+
1394
+ #: includes/i18n.php:777
1395
+ msgid "View details"
1396
+ msgstr "View details"
freemius/languages/freemius-it_IT.mo ADDED
Binary file
freemius/languages/freemius-it_IT.po ADDED
@@ -0,0 +1,1521 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Translators:
3
+ # Alessandro Benassi <plasmax@gmail.com>, 2016
4
+ # Daniele Scasciafratte Mte90 <mte90net@gmail.com>, 2015
5
+ # Vova Feldman <vova@freemius.com>, 2015
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: WordPress SDK\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: \n"
11
+ "PO-Revision-Date: 2016-09-13 08:22+0000\n"
12
+ "Last-Translator: Alessandro Benassi <plasmax@gmail.com>\n"
13
+ "Language-Team: Italian (Italy) (http://www.transifex.com/freemius/wordpress-sdk/language/it_IT/)\n"
14
+ "Content-Type: text/plain; charset=UTF-8\n"
15
+ "Content-Transfer-Encoding: \n"
16
+ "Language: it_IT\n"
17
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18
+
19
+ # Copyright (C) 2016 freemius
20
+ # This file is distributed under the same license as the freemius package.
21
+ #: includes/i18n.php41, includes/i18n.php:55
22
+ msgid "Yes - I'm in!"
23
+ msgstr "Sì, ci sto!"
24
+
25
+ #: includes/i18n.php43, includes/i18n.php:57
26
+ msgid "Not today"
27
+ msgstr "Non oggi"
28
+
29
+ #: includes/i18n.php:69
30
+ msgid "Account"
31
+ msgstr "Account"
32
+
33
+ #: includes/i18n.php:71
34
+ msgid "Add On"
35
+ msgstr "Add-on"
36
+
37
+ #: includes/i18n.php:73
38
+ msgid "Contact Us"
39
+ msgstr "Contattaci"
40
+
41
+ #: includes/i18n.php:75
42
+ msgid "Contact Support"
43
+ msgstr "Contatta il supporto"
44
+
45
+ #: includes/i18n.php:77
46
+ msgid "Change Ownership"
47
+ msgstr "Cambia Proprietario"
48
+
49
+ #: includes/i18n.php:79
50
+ msgid "Support"
51
+ msgstr "Supporto"
52
+
53
+ #: includes/i18n.php:81
54
+ msgid "Support Forum"
55
+ msgstr "Forum di supporto"
56
+
57
+ #: includes/i18n.php:83
58
+ msgid "Add Ons"
59
+ msgstr "Add-on"
60
+
61
+ #: includes/i18n.php:85
62
+ msgctxt "verb"
63
+ msgid "Upgrade"
64
+ msgstr "Aggiornamento"
65
+
66
+ #: includes/i18n.php:87
67
+ msgid "Awesome"
68
+ msgstr "Fantastico"
69
+
70
+ #: includes/i18n.php:89
71
+ msgctxt "noun"
72
+ msgid "Pricing"
73
+ msgstr "Prezzi"
74
+
75
+ #: includes/i18n.php:91
76
+ msgctxt "noun"
77
+ msgid "Price"
78
+ msgstr "Prezzo"
79
+
80
+ #: includes/i18n.php:93
81
+ msgid "Unlimited Updates"
82
+ msgstr "Aggiornamenti Illimitati"
83
+
84
+ #: includes/i18n.php:95
85
+ msgctxt "verb"
86
+ msgid "Downgrade"
87
+ msgstr "Downgrade"
88
+
89
+ #: includes/i18n.php:97
90
+ msgid "Cancel Trial"
91
+ msgstr "Annulla prova gratuita"
92
+
93
+ #: includes/i18n.php:99
94
+ msgid "Free Trial"
95
+ msgstr "Prova gratuita"
96
+
97
+ #: includes/i18n.php:101
98
+ msgid "Start my free %s"
99
+ msgstr "Inizia la mia %s"
100
+
101
+ #: includes/i18n.php:103
102
+ msgid "No commitment for %s - cancel anytime"
103
+ msgstr "Nessun impegno con %s - cancella quando vuoi"
104
+
105
+ #: includes/i18n.php:105
106
+ msgid "After your free %s, pay as little as %s"
107
+ msgstr "Dopo il tuo %s gratuito, paghi solamente %s"
108
+
109
+ #: includes/i18n.php:107
110
+ msgid "Details"
111
+ msgstr "Dettagli"
112
+
113
+ #: includes/i18n.php:109
114
+ msgid "Account Details"
115
+ msgstr "Dettagli dell'account"
116
+
117
+ #: includes/i18n.php:111
118
+ msgctxt "verb"
119
+ msgid "Delete"
120
+ msgstr "Elimina"
121
+
122
+ #: includes/i18n.php:113
123
+ msgctxt "verb"
124
+ msgid "Show"
125
+ msgstr "Mostra"
126
+
127
+ #: includes/i18n.php:115
128
+ msgctxt "verb"
129
+ msgid "Hide"
130
+ msgstr "Nascondi"
131
+
132
+ #: includes/i18n.php:117
133
+ msgctxt "verb"
134
+ msgid "Edit"
135
+ msgstr "Modifica"
136
+
137
+ #: includes/i18n.php:119
138
+ msgid "Date"
139
+ msgstr "Data"
140
+
141
+ #: includes/i18n.php:121
142
+ msgid "Amount"
143
+ msgstr "Importo"
144
+
145
+ #: includes/i18n.php:123
146
+ msgid "Invoice"
147
+ msgstr "Fattura"
148
+
149
+ #: includes/i18n.php:125
150
+ msgid "Billing"
151
+ msgstr "Fatturazione"
152
+
153
+ #: includes/i18n.php:127
154
+ msgid "Payments"
155
+ msgstr "Pagamenti"
156
+
157
+ #: includes/i18n.php:129
158
+ msgid "Delete Account"
159
+ msgstr "Elimina Account"
160
+
161
+ #: includes/i18n.php:131
162
+ msgctxt "as close a window"
163
+ msgid "Dismiss"
164
+ msgstr "Chiudi"
165
+
166
+ #: includes/i18n.php:133
167
+ msgctxt "as product pricing plan"
168
+ msgid "Plan"
169
+ msgstr "Piano"
170
+
171
+ #: includes/i18n.php:135
172
+ msgid "Change Plan"
173
+ msgstr "Cambia piano"
174
+
175
+ #: includes/i18n.php:137
176
+ msgctxt "as download professional version"
177
+ msgid "Download %s Version"
178
+ msgstr "Scarica la versione %s"
179
+
180
+ #: includes/i18n.php:139
181
+ msgctxt "as download professional version now"
182
+ msgid "Download %s version now"
183
+ msgstr "Scarica la versione %s ora"
184
+
185
+ #: includes/i18n.php:141
186
+ msgctxt "as download latest version"
187
+ msgid "Download Latest"
188
+ msgstr "Scarica l'ultima versione"
189
+
190
+ #: includes/i18n.php:143
191
+ msgctxt "E.g. you have a professional license."
192
+ msgid "You have a %s license."
193
+ msgstr "Hai la licenza %s."
194
+
195
+ #: includes/i18n.php:145
196
+ msgid "New"
197
+ msgstr "Nuovo"
198
+
199
+ #: includes/i18n.php:147
200
+ msgid "Free"
201
+ msgstr "Gratuito"
202
+
203
+ #: includes/i18n.php:149
204
+ msgctxt "as trial plan"
205
+ msgid "Trial"
206
+ msgstr "Prova gratuita"
207
+
208
+ #: includes/i18n.php:151
209
+ msgctxt "verb"
210
+ msgid "Purchase"
211
+ msgstr "Acquisto"
212
+
213
+ #: includes/i18n.php:153
214
+ msgid "Purchase License"
215
+ msgstr "Acquista licenza"
216
+
217
+ #: includes/i18n.php:155
218
+ msgctxt "verb"
219
+ msgid "Buy"
220
+ msgstr "Compra"
221
+
222
+ #: includes/i18n.php:157
223
+ msgid "Buy License"
224
+ msgstr "Compra licenza"
225
+
226
+ #: includes/i18n.php:159
227
+ msgid "Single Site License"
228
+ msgstr "Licenza per sito singolo"
229
+
230
+ #: includes/i18n.php:161
231
+ msgid "Unlimited Licenses"
232
+ msgstr "Licenze illimitate"
233
+
234
+ #: includes/i18n.php:163
235
+ msgid "Up to %s Sites"
236
+ msgstr "Fino a %s siti"
237
+
238
+ #: includes/i18n.php:165
239
+ msgid "%sRenew your license now%s to access version %s features and support."
240
+ msgstr "%sRinnova la tua licenza ora%s per accedere a funzionalità e supporto della versione %s."
241
+
242
+ #: includes/i18n.php:167
243
+ msgid ""
244
+ "Enter the email address you've used for the upgrade below and we will resend"
245
+ " you the license key."
246
+ msgstr "Inserisci qui sotto l'indirizzo email che hai usato per registrare l'aggiornamento e ti invieremo di nuovo la chiave di licenza."
247
+
248
+ #: includes/i18n.php:169
249
+ msgctxt "e.g. Professional Plan"
250
+ msgid "%s Plan"
251
+ msgstr "Piano %s"
252
+
253
+ #: includes/i18n.php:171
254
+ msgid "You are just one step away - %s"
255
+ msgstr "Sei a un passo dalla fine - %s"
256
+
257
+ #: includes/i18n.php:173
258
+ msgctxt "%s - plugin name. As complete \"Jetpack\" activation now"
259
+ msgid "Complete \"%s\" Activation Now"
260
+ msgstr "Completa l'attivazione di \"%s\" ora"
261
+
262
+ #: includes/i18n.php:175
263
+ msgid "We made a few tweaks to the plugin, %s"
264
+ msgstr "Abbiamo apportato alcune modifiche al plugin, %s"
265
+
266
+ #: includes/i18n.php:177
267
+ msgid "Opt-in to make \"%s\" Better!"
268
+ msgstr "Contribuisci a rendere \"%s\" migliore!"
269
+
270
+ #: includes/i18n.php:179
271
+ msgid "Error"
272
+ msgstr "Errore"
273
+
274
+ #: includes/i18n.php:181
275
+ msgid ""
276
+ "Freemius SDK couldn't find the plugin's main file. Please contact "
277
+ "sdk@freemius.com with the current error."
278
+ msgstr "L'SDK di Freemius non è riuscito a trovare il file principale del plugin. Per favore contatta sdk@freemius.com riportando l'errore."
279
+
280
+ #: includes/i18n.php:187
281
+ msgctxt "as expiration date"
282
+ msgid "Expiration"
283
+ msgstr "Scadenza"
284
+
285
+ #: includes/i18n.php:189
286
+ msgctxt "as software license"
287
+ msgid "License"
288
+ msgstr "Licenza"
289
+
290
+ #: includes/i18n.php:191
291
+ msgid "not verified"
292
+ msgstr "non verificato"
293
+
294
+ #: includes/i18n.php:193
295
+ msgid "Verify Email"
296
+ msgstr "Verifica email"
297
+
298
+ #: includes/i18n.php:195
299
+ msgctxt "e.g. expires in 2 months"
300
+ msgid "Expires in %s"
301
+ msgstr "Scade in %s"
302
+
303
+ #: includes/i18n.php:197
304
+ msgctxt "e.g. auto renews in 2 months"
305
+ msgid "Auto renews in %s"
306
+ msgstr "Rinnovo automatico in %s"
307
+
308
+ #: includes/i18n.php:199
309
+ msgid "No expiration"
310
+ msgstr "Nessuna scadenza"
311
+
312
+ #: includes/i18n.php:201
313
+ msgid "Expired"
314
+ msgstr "Scaduto"
315
+
316
+ #: includes/i18n.php:203
317
+ msgid "Cancelled"
318
+ msgstr "Annullato"
319
+
320
+ #: includes/i18n.php:205
321
+ msgctxt "e.g. In 2 hours"
322
+ msgid "In %s"
323
+ msgstr "In %s"
324
+
325
+ #: includes/i18n.php:207
326
+ msgctxt "e.g. 2 min ago"
327
+ msgid "%s ago"
328
+ msgstr "%s fa"
329
+
330
+ #: includes/i18n.php:209
331
+ msgctxt "as plugin version"
332
+ msgid "Version"
333
+ msgstr "Versione"
334
+
335
+ #: includes/i18n.php:211
336
+ msgid "Name"
337
+ msgstr "Nome"
338
+
339
+ #: includes/i18n.php:213
340
+ msgid "Email"
341
+ msgstr "Email"
342
+
343
+ #: includes/i18n.php:215
344
+ msgid "Email address"
345
+ msgstr "Indirizzo email"
346
+
347
+ #: includes/i18n.php:217
348
+ msgid "Verified"
349
+ msgstr "Verificato"
350
+
351
+ #: includes/i18n.php:219
352
+ msgid "Plugin"
353
+ msgstr "Plugin"
354
+
355
+ #: includes/i18n.php:221
356
+ msgid "Plugins"
357
+ msgstr "Plugin"
358
+
359
+ #: includes/i18n.php:223
360
+ msgid "Themes"
361
+ msgstr "Temi"
362
+
363
+ #: includes/i18n.php:225
364
+ msgctxt "as file/folder path"
365
+ msgid "Path"
366
+ msgstr "Percorso"
367
+
368
+ #: includes/i18n.php:227
369
+ msgid "Title"
370
+ msgstr "Titolo"
371
+
372
+ #: includes/i18n.php:229
373
+ msgid "Free version"
374
+ msgstr "Versione gratuita"
375
+
376
+ #: includes/i18n.php:231
377
+ msgid "Premium version"
378
+ msgstr "Versione premium"
379
+
380
+ #: includes/i18n.php:233
381
+ msgctxt "as WP plugin slug"
382
+ msgid "Slug"
383
+ msgstr "Slug"
384
+
385
+ #: includes/i18n.php:235
386
+ msgid "ID"
387
+ msgstr "ID"
388
+
389
+ #: includes/i18n.php:237
390
+ msgid "Users"
391
+ msgstr "Utenti"
392
+
393
+ #: includes/i18n.php:239
394
+ msgid "Plugin Installs"
395
+ msgstr "Installazioni Plugin"
396
+
397
+ #: includes/i18n.php:241
398
+ msgctxt "like websites"
399
+ msgid "Sites"
400
+ msgstr "Siti"
401
+
402
+ #: includes/i18n.php:243
403
+ msgid "User ID"
404
+ msgstr "ID utente"
405
+
406
+ #: includes/i18n.php:245
407
+ msgid "Site ID"
408
+ msgstr "ID del sito"
409
+
410
+ #: includes/i18n.php:247
411
+ msgid "Public Key"
412
+ msgstr "Chiave pubblica"
413
+
414
+ #: includes/i18n.php:249
415
+ msgid "Secret Key"
416
+ msgstr "Chiave segreta"
417
+
418
+ #: includes/i18n.php:251
419
+ msgctxt "as secret encryption key missing"
420
+ msgid "No Secret"
421
+ msgstr "Nessuna chiave"
422
+
423
+ #: includes/i18n.php:253
424
+ msgid "No ID"
425
+ msgstr "Nessun ID"
426
+
427
+ #: includes/i18n.php:255
428
+ msgctxt "as synchronize license"
429
+ msgid "Sync License"
430
+ msgstr "Sincronizza la licenza"
431
+
432
+ #: includes/i18n.php:257
433
+ msgctxt "as synchronize"
434
+ msgid "Sync"
435
+ msgstr "Sincronizza"
436
+
437
+ #: includes/i18n.php:259
438
+ msgid "Activate License"
439
+ msgstr "Attiva licenza"
440
+
441
+ #: includes/i18n.php:261
442
+ msgid "Activate Free Version"
443
+ msgstr "Attiva versione gratuita"
444
+
445
+ #: includes/i18n.php:263
446
+ msgid ""
447
+ "Please enter the license key that you received in the email right after the "
448
+ "purchase:"
449
+ msgstr "Per favore inserisci la chiave di licenza che hai ricevuto via mail subito dopo l'acquisto:"
450
+
451
+ #: includes/i18n.php:265
452
+ msgid "Activating license..."
453
+ msgstr "Sto attivando la licenza..."
454
+
455
+ #: includes/i18n.php:267
456
+ msgid "Change License"
457
+ msgstr "Cambia licenza"
458
+
459
+ #: includes/i18n.php:269
460
+ msgid "Update License"
461
+ msgstr "Aggiorna licenza"
462
+
463
+ #: includes/i18n.php:271
464
+ msgid "Deactivate License"
465
+ msgstr "Disattiva licenza"
466
+
467
+ #: includes/i18n.php:273
468
+ msgid "Activate"
469
+ msgstr "Attiva"
470
+
471
+ #: includes/i18n.php:275
472
+ msgid "Deactivate"
473
+ msgstr "Disattiva"
474
+
475
+ #: includes/i18n.php:277
476
+ msgid "Skip & Deactivate"
477
+ msgstr "Salta e disattiva"
478
+
479
+ #: includes/i18n.php:279
480
+ msgid "No - just deactivate"
481
+ msgstr "No - disattiva e basta"
482
+
483
+ #: includes/i18n.php:281
484
+ msgid "Yes - do your thing"
485
+ msgstr "Sì - fai pure"
486
+
487
+ #: includes/i18n.php:283
488
+ msgctxt "active mode"
489
+ msgid "Active"
490
+ msgstr "Attiva"
491
+
492
+ #: includes/i18n.php:285
493
+ msgctxt "is active mode?"
494
+ msgid "Is Active"
495
+ msgstr "è attiva"
496
+
497
+ #: includes/i18n.php:287
498
+ msgid "Install Now"
499
+ msgstr "Installa ora"
500
+
501
+ #: includes/i18n.php:289
502
+ msgid "Install Update Now"
503
+ msgstr "Installa l'aggiornamento ora"
504
+
505
+ #: includes/i18n.php:291
506
+ msgid "More information about %s"
507
+ msgstr "Ulteriori informazioni su %s"
508
+
509
+ #: includes/i18n.php:293
510
+ msgid "Localhost"
511
+ msgstr "Localhost"
512
+
513
+ #: includes/i18n.php:295
514
+ msgctxt "as activate Professional plan"
515
+ msgid "Activate %s Plan"
516
+ msgstr "Attivare il piano %s"
517
+
518
+ #: includes/i18n.php:297
519
+ msgctxt "as 5 licenses left"
520
+ msgid "%s left"
521
+ msgstr "%s rimanenti"
522
+
523
+ #: includes/i18n.php:299
524
+ msgid "Last license"
525
+ msgstr "Ultima licenza"
526
+
527
+ #: includes/i18n.php:301
528
+ msgid "What is your %s?"
529
+ msgstr "Qual è il tuo %s?"
530
+
531
+ #: includes/i18n.php:303
532
+ msgid "Activate this add-on"
533
+ msgstr "Attivare questo addon"
534
+
535
+ #: includes/i18n.php:305
536
+ msgid ""
537
+ "Deactivating your license will block all premium features, but will enable "
538
+ "you to activate the license on another site. Are you sure you want to "
539
+ "proceed?"
540
+ msgstr "La disattivazione della licenza bloccherà tutte le funzionalità premium, ma vi permetterà di attivare la licenza su un altro sito. Sei sicuro di voler procedere?"
541
+
542
+ #: includes/i18n.php:307
543
+ msgid ""
544
+ "Deleting the account will automatically deactivate your %s plan license so "
545
+ "you can use it on other sites. If you want to terminate the recurring "
546
+ "payments as well, click the \"Cancel\" button, and first \"Downgrade\" your "
547
+ "account. Are you sure you would like to continue with the deletion?"
548
+ msgstr "L'eliminazione dell'account disattiva automaticamente la tua licenza del piano %s quindi è possibile utilizzarlo su altri siti. Se si desidera anche terminare i pagamenti ricorrenti, fare clic sul pulsante \"Annulla\" ed effettuare il \"Downgrade\" del tuo account. Sei sicuro di voler continuare con l'eliminazione?"
549
+
550
+ #: includes/i18n.php:309
551
+ msgid ""
552
+ "Deletion is not temporary. Only delete if you no longer want to use this "
553
+ "plugin anymore. Are you sure you would like to continue with the deletion?"
554
+ msgstr "L'eliminazione non è temporanea. Cancella solo se non si desidera più utilizzare questo plugin. Sei sicuro di voler continuare con l'eliminazione?"
555
+
556
+ #: includes/i18n.php:311
557
+ msgid ""
558
+ "Downgrading your plan will immediately stop all future recurring payments "
559
+ "and your %s plan license will expire in %s."
560
+ msgstr "Effettuare il downgrade del piano interromperà immediatamente tutti i futuri pagamenti ricorrenti e la licenza del piano %s scadrà in %s."
561
+
562
+ #: includes/i18n.php:313
563
+ msgid ""
564
+ "Cancelling the trial will immediately block access to all premium features. "
565
+ "Are you sure?"
566
+ msgstr "Cancellando il periodo di prova gratuito bloccherai immediatamente l'accesso a tutte le funzionalità premium. Vuoi continuare?"
567
+
568
+ #: includes/i18n.php:315
569
+ msgid ""
570
+ "You can still enjoy all %s features but you will not have access to plugin "
571
+ "updates and support."
572
+ msgstr "Puoi ancora sfruttare tutte le funzionalità di %s, ma non avrai accesso al supporto ed agli aggiornamenti del plugin."
573
+
574
+ #: includes/i18n.php:317
575
+ msgid ""
576
+ "Once your license expire you can still use the Free version but you will NOT"
577
+ " have access to the %s features."
578
+ msgstr "Una volta scaduta la licenza, sarà possibile ancora utilizzare la versione gratuita ma non avrete accesso alle funzionalità di %s."
579
+
580
+ #: includes/i18n.php:319
581
+ msgid "Are you sure you want to proceed?"
582
+ msgstr "Sei sicuro di voler procedere?"
583
+
584
+ #: includes/i18n.php:325
585
+ msgid "Add Ons for %s"
586
+ msgstr "Add-on per %s"
587
+
588
+ #: includes/i18n.php:327
589
+ msgid ""
590
+ "We could'nt load the add-ons list. It's probably an issue on our side, "
591
+ "please try to come back in few minutes."
592
+ msgstr "Non siamo riusciti a caricare la lista degli add-on. Si tratta probabilmente di un problema nel nostro sistema, per favore riprova tra qualche minuto."
593
+
594
+ #: includes/i18n.php:331
595
+ msgid "Anonymous feedback"
596
+ msgstr "Feedback anonimo"
597
+
598
+ #: includes/i18n.php:333
599
+ msgid "Quick feedback"
600
+ msgstr "Feedback veloce"
601
+
602
+ #: includes/i18n.php:335
603
+ msgid "If you have a moment, please let us know why you are deactivating"
604
+ msgstr "Se hai un momento, potresti dirci perché lo hai disattivato?"
605
+
606
+ #: includes/i18n.php:337
607
+ msgid "Yes - Deactivate"
608
+ msgstr "Si - Disattiva"
609
+
610
+ #: includes/i18n.php:339
611
+ msgid "Submit & Deactivate"
612
+ msgstr "Invia & Disattiva"
613
+
614
+ #: includes/i18n.php:341
615
+ msgctxt "the text of the cancel button of the plugin deactivation dialog box."
616
+ msgid "Cancel"
617
+ msgstr "Cancella"
618
+
619
+ #: includes/i18n.php:343
620
+ msgid "I no longer need the plugin"
621
+ msgstr "Non ho piú bisogno di questo plugin"
622
+
623
+ #: includes/i18n.php:345
624
+ msgid "I found a better plugin"
625
+ msgstr "Ho trovato un plugin migliore"
626
+
627
+ #: includes/i18n.php:347
628
+ msgid "I only needed the plugin for a short period"
629
+ msgstr "Avevo bisogno del plugin solo per un breve periodo"
630
+
631
+ #: includes/i18n.php:349
632
+ msgid "The plugin broke my site"
633
+ msgstr "Il plugin ha causato problemi al mio sito"
634
+
635
+ #: includes/i18n.php:351
636
+ msgid "The plugin suddenly stopped working"
637
+ msgstr "Il plugin ha smesso di funzionare"
638
+
639
+ #: includes/i18n.php:353
640
+ msgid "I can't pay for it anymore"
641
+ msgstr "Non posso piú pagarlo"
642
+
643
+ #: includes/i18n.php:355
644
+ msgid "It's a temporary deactivation. I'm just debugging an issue."
645
+ msgstr "È una disattivazione temporanea. Sto solo cercando di risolvere un problema."
646
+
647
+ #: includes/i18n.php:357
648
+ msgctxt ""
649
+ "the text of the \"other\" reason for deactivating the plugin that is shown "
650
+ "in the modal box."
651
+ msgid "Other"
652
+ msgstr "Altro"
653
+
654
+ #: includes/i18n.php:359
655
+ msgid "Kindly tell us the reason so we can improve."
656
+ msgstr "Spiegandoci il motivo ci aiuterai a migliorare."
657
+
658
+ #: includes/i18n.php:361
659
+ msgid "What's the plugin's name?"
660
+ msgstr "Qual è il nome del plugin?"
661
+
662
+ #: includes/i18n.php:363
663
+ msgid "What price would you feel comfortable paying?"
664
+ msgstr "Che prezzo ritieni opportuno pagare?"
665
+
666
+ #: includes/i18n.php:365
667
+ msgid "I couldn't understand how to make it work"
668
+ msgstr "Non capisco come farlo funzionare"
669
+
670
+ #: includes/i18n.php:367
671
+ msgid ""
672
+ "The plugin is great, but I need specific feature that you don't support"
673
+ msgstr "Il plugin é ottimo ma ho bisogno di una funzionalitá specifica che non é supportata"
674
+
675
+ #: includes/i18n.php:369
676
+ msgid "The plugin is not working"
677
+ msgstr "Il plugin non funziona"
678
+
679
+ #: includes/i18n.php:371
680
+ msgid "It's not what I was looking for"
681
+ msgstr "Non é quello che stavo cercando"
682
+
683
+ #: includes/i18n.php:373
684
+ msgid "The plugin didn't work as expected"
685
+ msgstr "Il plugin non funziona come mi aspettavo"
686
+
687
+ #: includes/i18n.php:375
688
+ msgid "What feature?"
689
+ msgstr "Quale funzionalitá?"
690
+
691
+ #: includes/i18n.php:377
692
+ msgid "Kindly share what didn't work so we can fix it for future users..."
693
+ msgstr "Condividi cosa non ha funzionato in modo da migliorare il prodotto per gli utenti futuri..."
694
+
695
+ #: includes/i18n.php:379
696
+ msgid "What you've been looking for?"
697
+ msgstr "Che cosa stai cercando?"
698
+
699
+ #: includes/i18n.php:381
700
+ msgid "What did you expect?"
701
+ msgstr "Che cosa ti aspettavi?"
702
+
703
+ #: includes/i18n.php:383
704
+ msgid "The plugin didn't work"
705
+ msgstr "Il plugin non funziona"
706
+
707
+ #: includes/i18n.php:385
708
+ msgid "I don't like to share my information with you"
709
+ msgstr "Non voglio condividere i miei dati con te"
710
+
711
+ #: includes/i18n.php:387
712
+ msgid ""
713
+ "You might have missed it, but you don't have to share any data and can just "
714
+ "%s the opt-in."
715
+ msgstr "Potresti non averci fatto caso, ma non sei obbligato a condividere i tuoi dati e puoi semplicemente %s la tua partecipazione."
716
+
717
+ #: includes/i18n.php:395
718
+ msgctxt "greeting"
719
+ msgid "Hey %s,"
720
+ msgstr "Hey %s,"
721
+
722
+ #: includes/i18n.php:397
723
+ msgctxt "a greeting. E.g. Thanks John!"
724
+ msgid "Thanks %s!"
725
+ msgstr "Grazie %s!"
726
+
727
+ #: includes/i18n.php:399
728
+ msgid ""
729
+ "In order to enjoy all our features and functionality, %s needs to connect "
730
+ "your user, %s at %s, to %s"
731
+ msgstr "Per poter sfruttare tutte le caratteristiche e funzionalità, %s deve connettere il tuo utente, %s a %s su %s"
732
+
733
+ #: includes/i18n.php:401
734
+ msgid ""
735
+ "Please help us improve %2$s! If you opt-in, some data about your usage of "
736
+ "%2$s will be sent to %5$s. If you skip this, that's okay! %2$s will still "
737
+ "work just fine."
738
+ msgstr "Per favore aiutaci a migliorare %2$s! Se decidi di contribuire, alcuni dei tuoi dati di utilizzo inerenti a %2$s verranno inviati a %5$s. Se salti questo passaggio, non c'è problema! %2$s funzionerà comunque perfettamente."
739
+
740
+ #: includes/i18n.php:403
741
+ msgid ""
742
+ "You should receive an activation email for %s to your mailbox at %s. Please "
743
+ "make sure you click the activation button in that email to complete the "
744
+ "install."
745
+ msgstr "Dovresti ricevere un'email di attivazione di %s all'indirizzo %s. Assicurati di fare clic sul pulsante di attivazione nell'email per completare l'installazione."
746
+
747
+ #: includes/i18n.php:405
748
+ msgid ""
749
+ "Thanks for purchasing %s! To get started, please enter your license key:"
750
+ msgstr "Grazie per aver acquistato %s! Per iniziare, per favore inserisci la tua chiave di licenza:"
751
+
752
+ #: includes/i18n.php:407
753
+ msgid ""
754
+ "The plugin will be periodically sending data to %s to check for plugin "
755
+ "updates and verify the validity of your license."
756
+ msgstr "Il plugin invierà dati periodicamente a %s per controllare l'esistenza di aggiornamenti e verificare la validità della tua licenza."
757
+
758
+ #: includes/i18n.php:409
759
+ msgid "What permissions are being granted?"
760
+ msgstr "Quali autorizzazioni vengono concesse?"
761
+
762
+ #: includes/i18n.php:411
763
+ msgid "Your Profile Overview"
764
+ msgstr "Panoramica del tuo profilo"
765
+
766
+ #: includes/i18n.php:413
767
+ msgid "Name and email address"
768
+ msgstr "Nome ed indirizzo email"
769
+
770
+ #: includes/i18n.php:415
771
+ msgid "Your Site Overview"
772
+ msgstr "Panoramica del tuo sito"
773
+
774
+ #: includes/i18n.php:417
775
+ msgid "Site URL, WP version, PHP info, plugins & themes"
776
+ msgstr "URL del sito, versione di WP, informazioni PHP, plugin e temi"
777
+
778
+ #: includes/i18n.php:419
779
+ msgid "Current Plugin Events"
780
+ msgstr "Eventi correnti del plugin"
781
+
782
+ #: includes/i18n.php:421
783
+ msgid "Activation, deactivation and uninstall"
784
+ msgstr "Attiva, disattivazione e disinstallazione"
785
+
786
+ #: includes/i18n.php:423
787
+ msgid "Plugins & Themes"
788
+ msgstr "Plugin e temi"
789
+
790
+ #: includes/i18n.php:425
791
+ msgid "Titles, versions and state."
792
+ msgstr "Titoli, versioni e stato."
793
+
794
+ #: includes/i18n.php:427
795
+ msgid "Newsletter"
796
+ msgstr "Newsletter"
797
+
798
+ #: includes/i18n.php:429
799
+ msgid "Updates, announcements, marketing, no spam"
800
+ msgstr "Aggiornamenti, annunci, marketing, no spam"
801
+
802
+ #: includes/i18n.php:431
803
+ msgid "Privacy Policy"
804
+ msgstr "Politica sulla privacy"
805
+
806
+ #: includes/i18n.php:433
807
+ msgid "Terms of Service"
808
+ msgstr "Termini del Servizio"
809
+
810
+ #: includes/i18n.php:435
811
+ msgctxt "as activating plugin"
812
+ msgid "Activating"
813
+ msgstr "Attivazione"
814
+
815
+ #: includes/i18n.php:437
816
+ msgctxt "as in the process of sending an email"
817
+ msgid "Sending email"
818
+ msgstr "Invio email"
819
+
820
+ #: includes/i18n.php:439
821
+ msgctxt "button label"
822
+ msgid "Allow & Continue"
823
+ msgstr "Consenti & Continua"
824
+
825
+ #: includes/i18n.php:441
826
+ msgctxt "button label"
827
+ msgid "Agree & Activate License"
828
+ msgstr "Accetta e attiva la licenza"
829
+
830
+ #: includes/i18n.php:443
831
+ msgctxt "verb"
832
+ msgid "Skip"
833
+ msgstr "Salta"
834
+
835
+ #: includes/i18n.php:445
836
+ msgid "Click here to use the plugin anonymously"
837
+ msgstr "Fai clic qui per usare il plugin anonimamente"
838
+
839
+ #: includes/i18n.php:447
840
+ msgid "Re-send activation email"
841
+ msgstr "Invia nuovamente l'email di attivazione"
842
+
843
+ #: includes/i18n.php:449
844
+ msgid "License key"
845
+ msgstr "Chiave di licenza"
846
+
847
+ #: includes/i18n.php:451
848
+ msgid "Send License Key"
849
+ msgstr "Invia chiave di licenza"
850
+
851
+ #: includes/i18n.php:453
852
+ msgid "Sending license key"
853
+ msgstr "Invio chiave di licenza"
854
+
855
+ #: includes/i18n.php:455
856
+ msgid "Have a license key?"
857
+ msgstr "Hai una chiave di licenza?"
858
+
859
+ #: includes/i18n.php:457
860
+ msgid "Don't have a license key?"
861
+ msgstr "Non hai una chiave di licenza?"
862
+
863
+ #: includes/i18n.php:459
864
+ msgid "Can't find your license key?"
865
+ msgstr "Non trovi la tua chiave di licenza?"
866
+
867
+ #: includes/i18n.php:471
868
+ msgid "Screenshots"
869
+ msgstr "Screenshots"
870
+
871
+ #: includes/i18n.php:473
872
+ msgid "Click to view full-size screenshot %d"
873
+ msgstr "Fare clic per visualizzare lo screenshot in grandi dimensioni %d"
874
+
875
+ #: includes/i18n.php:481
876
+ msgid "Freemius Debug"
877
+ msgstr "Debug Freemius"
878
+
879
+ #: includes/i18n.php:483
880
+ msgctxt "as turned on"
881
+ msgid "On"
882
+ msgstr "Attivo"
883
+
884
+ #: includes/i18n.php:485
885
+ msgctxt "as turned off"
886
+ msgid "Off"
887
+ msgstr "Non attivo"
888
+
889
+ #: includes/i18n.php:487
890
+ msgctxt "as code debugging"
891
+ msgid "Debugging"
892
+ msgstr "Debugging"
893
+
894
+ #: includes/i18n.php:489
895
+ msgid "Freemius State"
896
+ msgstr "Stato di Freemius"
897
+
898
+ #: includes/i18n.php:491
899
+ msgctxt "as connection was successful"
900
+ msgid "Connected"
901
+ msgstr "Connesso"
902
+
903
+ #: includes/i18n.php:493
904
+ msgctxt "as connection blocked"
905
+ msgid "Blocked"
906
+ msgstr "Bloccato"
907
+
908
+ #: includes/i18n.php:495
909
+ msgctxt "as application program interface"
910
+ msgid "API"
911
+ msgstr "API"
912
+
913
+ #: includes/i18n.php:497
914
+ msgctxt "as software development kit versions"
915
+ msgid "SDK"
916
+ msgstr "SDK"
917
+
918
+ #: includes/i18n.php:499
919
+ msgctxt "as software development kit versions"
920
+ msgid "SDK Versions"
921
+ msgstr "Versioni SDK"
922
+
923
+ #: includes/i18n.php:501
924
+ msgctxt "as plugin folder path"
925
+ msgid "Plugin Path"
926
+ msgstr "Percorso del plugin"
927
+
928
+ #: includes/i18n.php:503
929
+ msgctxt "as sdk path"
930
+ msgid "SDK Path"
931
+ msgstr "Percorso SDK"
932
+
933
+ #: includes/i18n.php:505
934
+ msgid "Add Ons of Plugin %s"
935
+ msgstr "Add-on del Plugin %s"
936
+
937
+ #: includes/i18n.php:507
938
+ msgid "Are you sure you want to delete all Freemius data?"
939
+ msgstr "Sei sicuro di voler eliminare tutti i dati di Freemius?"
940
+
941
+ #: includes/i18n.php:509
942
+ msgid "Actions"
943
+ msgstr "Azioni"
944
+
945
+ #: includes/i18n.php:511
946
+ msgid "Delete All Accounts"
947
+ msgstr "Eliminare tutti gli account"
948
+
949
+ #: includes/i18n.php:513
950
+ msgid "Start Fresh"
951
+ msgstr "Inizia da capo"
952
+
953
+ #: includes/i18n.php:515
954
+ msgid "Clear API Cache"
955
+ msgstr "Elimina cache API"
956
+
957
+ #: includes/i18n.php:517
958
+ msgid "Sync Data From Server"
959
+ msgstr "Sincronizza i dati dal server"
960
+
961
+ #: includes/i18n.php:519
962
+ msgid "Scheduled Crons"
963
+ msgstr "Azioni programmate"
964
+
965
+ #: includes/i18n.php:521
966
+ msgid "Plugins & Themes Sync"
967
+ msgstr "Sincronizzazione plugin e temi"
968
+
969
+ #: includes/i18n.php:529
970
+ msgctxt "as congratulations"
971
+ msgid "Congrats"
972
+ msgstr "Congratulazioni"
973
+
974
+ #: includes/i18n.php:531
975
+ msgctxt "exclamation"
976
+ msgid "Oops"
977
+ msgstr "Ops"
978
+
979
+ #: includes/i18n.php:533
980
+ msgctxt "interjection expressing joy or exuberance"
981
+ msgid "Yee-haw"
982
+ msgstr "Evvai"
983
+
984
+ #: includes/i18n.php:535
985
+ msgctxt ""
986
+ "(especially in electronic communication) used to express elation, "
987
+ "enthusiasm, or triumph."
988
+ msgid "W00t"
989
+ msgstr "Forte"
990
+
991
+ #: includes/i18n.php:537
992
+ msgctxt "a positive response"
993
+ msgid "Right on"
994
+ msgstr "Sì"
995
+
996
+ #: includes/i18n.php:539
997
+ msgctxt ""
998
+ "something somebody says when they are thinking about what you have just "
999
+ "said. "
1000
+ msgid "Hmm"
1001
+ msgstr "Uhm"
1002
+
1003
+ #: includes/i18n.php:541
1004
+ msgid "O.K"
1005
+ msgstr "OK"
1006
+
1007
+ #: includes/i18n.php:543
1008
+ msgctxt "exclamation"
1009
+ msgid "Hey"
1010
+ msgstr "Hey"
1011
+
1012
+ #: includes/i18n.php:545
1013
+ msgctxt "advance notice of something that will need attention."
1014
+ msgid "Heads up"
1015
+ msgstr "Attenzione"
1016
+
1017
+ #: includes/i18n.php:553
1018
+ msgid "Seems like you got the latest release."
1019
+ msgstr "Sembra che tu abbia la versione più recente."
1020
+
1021
+ #: includes/i18n.php:555
1022
+ msgid "You are all good!"
1023
+ msgstr "Sei fantastico!"
1024
+
1025
+ #: includes/i18n.php:557
1026
+ msgid ""
1027
+ "Sorry, we could not complete the email update. Another user with the same "
1028
+ "email is already registered."
1029
+ msgstr "Siamo spiacenti, non siamo riusciti a completare l'aggiornamento via email. Un altro utente con lo stesso indirizzo email è già registrato."
1030
+
1031
+ #: includes/i18n.php:559
1032
+ msgid ""
1033
+ "If you would like to give up the ownership of the plugin's account to %s "
1034
+ "click the Change Ownership button."
1035
+ msgstr "Se vuoi cedere la proprietá dell'account del plugin a %s clicca su Cambia Proprietà."
1036
+
1037
+ #: includes/i18n.php:561
1038
+ msgid ""
1039
+ "Your email was successfully updated. You should receive an email with "
1040
+ "confirmation instructions in few moments."
1041
+ msgstr "Il tuo indirizzo email è stato aggiornato correttamente. Riceverai un'email con le istruzioni di conferma in pochi istanti."
1042
+
1043
+ #: includes/i18n.php:563
1044
+ msgid "Your name was successfully updated."
1045
+ msgstr "Il tuo nome è stato aggiornato correttamente."
1046
+
1047
+ #: includes/i18n.php:565
1048
+ msgid "You have successfully updated your %s."
1049
+ msgstr "Hai aggiornato con successo il tuo %s."
1050
+
1051
+ #: includes/i18n.php:567
1052
+ msgid "Please provide your full name."
1053
+ msgstr "Per favore inserisci il tuo nome completo."
1054
+
1055
+ #: includes/i18n.php:569
1056
+ msgid ""
1057
+ "Verification mail was just sent to %s. If you can't find it after 5 min, "
1058
+ "please check your spam box."
1059
+ msgstr "L'email di verifica è stata inviata a %s. Se dopo 5 minuti non è ancora arrivata, per favore controlla nella tua casella di posta indesiderata."
1060
+
1061
+ #: includes/i18n.php:571
1062
+ msgid ""
1063
+ "Just letting you know that the add-ons information of %s is being pulled "
1064
+ "from an external server."
1065
+ msgstr "Le informazioni sugli add-on di %s vengono scaricate da un server esterno."
1066
+
1067
+ #: includes/i18n.php:573
1068
+ msgid "No credit card required"
1069
+ msgstr "Nessuna carta di credito richiesta"
1070
+
1071
+ #: includes/i18n.php:575
1072
+ msgid "Premium plugin version was successfully activated."
1073
+ msgstr "La versione Premium del plugin è stata attivata correttamente."
1074
+
1075
+ #: includes/i18n.php:577
1076
+ msgid "The upgrade of %s was successfully completed."
1077
+ msgstr "L'aggiornamento di %s è stato completato con successo."
1078
+
1079
+ #: includes/i18n.php:579
1080
+ msgid "Your account was successfully activated with the %s plan."
1081
+ msgstr "Il tuo account è stato attivato correttamente con il piano %s."
1082
+
1083
+ #: includes/i18n.php:581
1084
+ msgid "Download the latest %s version now"
1085
+ msgstr "Scarica l'ultima versione di %s"
1086
+
1087
+ #: includes/i18n.php:583
1088
+ msgid "Please follow these steps to complete the upgrade"
1089
+ msgstr "Segui i passi seguenti per completare l'aggiornamento"
1090
+
1091
+ #: includes/i18n.php:585
1092
+ msgid "Download the latest %s version"
1093
+ msgstr "Scarica l'ultima versione di %s"
1094
+
1095
+ #: includes/i18n.php:587
1096
+ msgid "Deactivate the free version"
1097
+ msgstr "Disattiva la versione gratuita"
1098
+
1099
+ #: includes/i18n.php:589
1100
+ msgid "Upload and activate the downloaded version"
1101
+ msgstr "Carica e attiva la versione scaricata"
1102
+
1103
+ #: includes/i18n.php:591
1104
+ msgid "How to upload and activate?"
1105
+ msgstr "Come faccio a caricare ed attivare?"
1106
+
1107
+ #: includes/i18n.php:593
1108
+ msgctxt "%s - product name, e.g. Facebook add-on was successfully..."
1109
+ msgid "%s Add-on was successfully purchased."
1110
+ msgstr "L' add-on %s è stato acquistato con successo."
1111
+
1112
+ #: includes/i18n.php:595
1113
+ msgid "Your %s Add-on plan was successfully upgraded."
1114
+ msgstr "Il piano del tuo add-on %s è stato aggiornato con successo."
1115
+
1116
+ #: includes/i18n.php:597
1117
+ msgid "Your email has been successfully verified - you are AWESOME!"
1118
+ msgstr "Il tuo indirizzo email è stato verificato con successo - SEI UN GRANDE!"
1119
+
1120
+ #: includes/i18n.php:599
1121
+ msgid "Your plan was successfully upgraded."
1122
+ msgstr "Il piano è stato aggiornato con successo."
1123
+
1124
+ #: includes/i18n.php:601
1125
+ msgid "Your plan was successfully changed to %s."
1126
+ msgstr "Il piano è stato cambiato con successo a %s."
1127
+
1128
+ #: includes/i18n.php:603
1129
+ msgid ""
1130
+ "Your license has expired. You can still continue using the free plugin "
1131
+ "forever."
1132
+ msgstr "La licenza è scaduta. È comunque possibile continuare ad utilizzare il plugin gratuito per sempre."
1133
+
1134
+ #: includes/i18n.php:605
1135
+ msgid ""
1136
+ "Your license has been cancelled. If you think it's a mistake, please contact"
1137
+ " support."
1138
+ msgstr "La tua licenza è stata cancellata. Se credi sia un errore, per favore contatta il supporto."
1139
+
1140
+ #: includes/i18n.php:607
1141
+ msgid "Your trial has been successfully started."
1142
+ msgstr "La versione di prova è stata avviata correttamente."
1143
+
1144
+ #: includes/i18n.php:609
1145
+ msgid "Your license was successfully activated."
1146
+ msgstr "La tua licenza è stata attivata correttamente."
1147
+
1148
+ #: includes/i18n.php:611
1149
+ msgid "It looks like your site currently doesn't have an active license."
1150
+ msgstr "Sembra che il tuo sito non disponga di alcuna licenza attiva."
1151
+
1152
+ #: includes/i18n.php:613
1153
+ msgid ""
1154
+ "Your license was successfully deactivated, you are back to the %s plan."
1155
+ msgstr "La tua licenza é stata disattivata con successo, sei tornato al piano %s."
1156
+
1157
+ #: includes/i18n.php:615
1158
+ msgid "It looks like the license deactivation failed."
1159
+ msgstr "Sembra che la disattivazione della licenza non sia riuscita."
1160
+
1161
+ #: includes/i18n.php:617
1162
+ msgid "It looks like the license could not be activated."
1163
+ msgstr "Sembra che la licenza non possa essere attivata."
1164
+
1165
+ #: includes/i18n.php:619
1166
+ msgid "Error received from the server:"
1167
+ msgstr "Errore ricevuto dal server:"
1168
+
1169
+ #: includes/i18n.php:621
1170
+ msgid ""
1171
+ "Your trial has expired. You can still continue using all our free features."
1172
+ msgstr "La versione di prova è scaduta. Si può comunque continuare a utilizzare tutte le nostre funzioni gratuite."
1173
+
1174
+ #: includes/i18n.php:623
1175
+ msgid ""
1176
+ "Your plan was successfully downgraded. Your %s plan license will expire in "
1177
+ "%s."
1178
+ msgstr "Il tuo piano è stato declassato con successo. La licenza del piano %s scadrà in %s."
1179
+
1180
+ #: includes/i18n.php:625
1181
+ msgid ""
1182
+ "Seems like we are having some temporary issue with your plan downgrade. "
1183
+ "Please try again in few minutes."
1184
+ msgstr "Stiamo avendo qualche problema temporaneo con il downgrade del piano. Riprova tra qualche minuto."
1185
+
1186
+ #: includes/i18n.php:627
1187
+ msgid ""
1188
+ "It looks like you are not in trial mode anymore so there's nothing to cancel"
1189
+ " :)"
1190
+ msgstr "Sembra che tu non stia più usando la prova gratuita, quindi non c'è niente che tu debba annullare :)"
1191
+
1192
+ #: includes/i18n.php:629
1193
+ msgid "Your %s free trial was successfully cancelled."
1194
+ msgstr "Il tuo periodo di prova gratuito %s è stato annullato con successo."
1195
+
1196
+ #: includes/i18n.php:631
1197
+ msgctxt "%s - numeric version number"
1198
+ msgid "Version %s was released."
1199
+ msgstr "La versione %s é stata rilasciata."
1200
+
1201
+ #: includes/i18n.php:633
1202
+ msgid "Please download %s."
1203
+ msgstr "Scarica %s."
1204
+
1205
+ #: includes/i18n.php:635
1206
+ msgctxt "%s - plan name, as the latest professional version here"
1207
+ msgid "the latest %s version here"
1208
+ msgstr "l'ultima versione %s é quì"
1209
+
1210
+ #: includes/i18n.php:637
1211
+ msgid ""
1212
+ "How do you like %s so far? Test all our %s premium features with a %d-day "
1213
+ "free trial."
1214
+ msgstr "Come sta andando con %s? Prova tutte le funzionalità premium di %s con una prova gratuita di %d giorni."
1215
+
1216
+ #: includes/i18n.php:639
1217
+ msgctxt "call to action"
1218
+ msgid "Start free trial"
1219
+ msgstr "Inizia il periodo di prova gratuito"
1220
+
1221
+ #: includes/i18n.php:641
1222
+ msgid ""
1223
+ "Seems like we are having some temporary issue with your trial cancellation. "
1224
+ "Please try again in few minutes."
1225
+ msgstr "Stiamo avendo qualche problema temporaneo con l'annullamento del periodo di prova. Riprova tra qualche minuto."
1226
+
1227
+ #: includes/i18n.php:643
1228
+ msgid "You already utilized a trial before."
1229
+ msgstr "Hai già utilizzato una prova gratuita in passato."
1230
+
1231
+ #: includes/i18n.php:645
1232
+ msgid "You are already running the plugin in a trial mode."
1233
+ msgstr "Stai già usando il plugin in modalità di prova gratuita."
1234
+
1235
+ #: includes/i18n.php:647
1236
+ msgid "Plan %s do not exist, therefore, can't start a trial."
1237
+ msgstr "Il piano %s non esiste, per questo motivo non è possibile iniziare il periodo di prova."
1238
+
1239
+ #: includes/i18n.php:649
1240
+ msgid "Plan %s does not support a trial period."
1241
+ msgstr "Il piano %s non supporta il periodo di prova."
1242
+
1243
+ #: includes/i18n.php:651
1244
+ msgid "None of the plugin's plans supports a trial period."
1245
+ msgstr "Non esiste alcun piano del plugin che offra il periodo di prova."
1246
+
1247
+ #: includes/i18n.php:653
1248
+ msgid ""
1249
+ "Unexpected API error. Please contact the plugin's author with the following "
1250
+ "error."
1251
+ msgstr "Errore inaspettato dell'API. Per favore contatta l'autore del plugin riportando il seguente errore."
1252
+
1253
+ #: includes/i18n.php:655
1254
+ msgid "No commitment for %s days - cancel anytime!"
1255
+ msgstr "Nessun impegno per %s giorni - puoi annullare in qualsiasi momento!"
1256
+
1257
+ #: includes/i18n.php:657
1258
+ msgid ""
1259
+ "Your license has expired. You can still continue using all the %s features, "
1260
+ "but you'll need to renew your license to continue getting updates and "
1261
+ "support."
1262
+ msgstr "La licenza è scaduta. È comunque possibile continuare a utilizzare tutte le funzionalità di %s, ma sarà necessario rinnovare la licenza per continuare a ricevere gli aggiornamenti ed il supporto."
1263
+
1264
+ #: includes/i18n.php:659
1265
+ msgid "Couldn't activate %s."
1266
+ msgstr "Non é stato possibile attivare %s."
1267
+
1268
+ #: includes/i18n.php:661
1269
+ msgid "Please contact us with the following message:"
1270
+ msgstr "Contattaci con il seguente messaggio:"
1271
+
1272
+ #: includes/i18n.php:663
1273
+ msgid ""
1274
+ "It looks like you are still on the %s plan. If you did upgrade or change "
1275
+ "your plan, it's probably an issue on our side - sorry."
1276
+ msgstr "Sembra che tu sia ancora usando il piano %s. Se hai effettuato un upgrade o cambiato il piano, è probabile che ci sia un problema nei nostri sistemi."
1277
+
1278
+ #: includes/i18n.php:665
1279
+ msgid "Please contact us here"
1280
+ msgstr "Contattaci qui"
1281
+
1282
+ #: includes/i18n.php:667
1283
+ msgid ""
1284
+ "I have upgraded my account but when I try to Sync the License, the plan "
1285
+ "remains %s."
1286
+ msgstr "Ho aggiornato il mio account, ma quando cerco di sincronizzare la licenza, il piano rimane %s."
1287
+
1288
+ #: includes/i18n.php:673
1289
+ msgid "From unknown reason, the API connectivity test failed."
1290
+ msgstr "Il test di connettività dell'API ha fallito per motivi sconosciuti."
1291
+
1292
+ #: includes/i18n.php:675
1293
+ msgid ""
1294
+ "It's probably a temporary issue on our end. Just to be sure, with your "
1295
+ "permission, would it be o.k to run another connectivity test?"
1296
+ msgstr "Si tratta probabilmente di un problema nei nostri sistemi. Per esserne sicuri, potresti darci il permesso di effettuare un ulteriore test della connettività? "
1297
+
1298
+ #: includes/i18n.php:677
1299
+ msgid ""
1300
+ "We use PHP cURL library for the API calls, which is a very common library "
1301
+ "and usually installed out of the box. Unfortunately, cURL is not installed "
1302
+ "on your server."
1303
+ msgstr "Utilizziamo la libreria PHP cURL per le chiamate alla nostra API. Questa libreria è molto comune ed è installata di base. Sfortunatamente cURL non è presente nel tuo server."
1304
+
1305
+ #: includes/i18n.php:679
1306
+ msgid ""
1307
+ "From unknown reason, CloudFlare, the firewall we use, blocks the connection."
1308
+ msgstr "Per un motivo sconosciuto, CloudFlare, il firewall che utilizziamo, blocca la connessione."
1309
+
1310
+ #: includes/i18n.php:681
1311
+ msgctxt "as pluginX requires an access to our API"
1312
+ msgid "%s requires an access to our API."
1313
+ msgstr "%s richiede un accesso alla nostra API."
1314
+
1315
+ #: includes/i18n.php:683
1316
+ msgid ""
1317
+ "It looks like your server is using Squid ACL (access control lists), which "
1318
+ "blocks the connection."
1319
+ msgstr "Sembra che il tuo server stia usando Squid ACL (lista per il controllo degli accessi) il quale blocca la connessione."
1320
+
1321
+ #: includes/i18n.php:685
1322
+ msgid "I don't know what is Squid or ACL, help me!"
1323
+ msgstr "Non ho idea di cosa sia Squid o ACL, aiutami!"
1324
+
1325
+ #: includes/i18n.php687, includes/i18n.php:695
1326
+ msgid ""
1327
+ "We'll make sure to contact your hosting company and resolve the issue. You "
1328
+ "will get a follow-up email to %s once we have an update."
1329
+ msgstr "Contatteremo il tuo hosting e risolveremo il problema. Riceverai un' email a %s non appena ci saranno aggiornamenti."
1330
+
1331
+ #: includes/i18n.php:689
1332
+ msgid "I'm a system administrator"
1333
+ msgstr "Sono un sistemista"
1334
+
1335
+ #: includes/i18n.php:691
1336
+ msgid ""
1337
+ "Great, please whitelist the following domains: %s. Once you done, deactivate"
1338
+ " the plugin and activate it again."
1339
+ msgstr "Perfetto, aggiungi alla whitelist i seguenti domini: %s. Una volta che hai fatto, disattiva il plugin e attivalo di nuovo."
1340
+
1341
+ #: includes/i18n.php:693
1342
+ msgid "I don't know what is cURL or how to install it, help me!"
1343
+ msgstr "Non ho idea di cosa sia cURL o come installarlo, aiutami!"
1344
+
1345
+ #: includes/i18n.php:697
1346
+ msgid ""
1347
+ "Great, please install cURL and enable it in your php.ini file. To make sure "
1348
+ "it was successfully activated, use 'phpinfo()'. Once activated, deactivate "
1349
+ "the plugin and reactivate it back again."
1350
+ msgstr "Perfetto, installa cURL ed attivalo nel tuo file php.ini. Per essere sicuro di averlo attivato con successo, usa \"phpinfo()\". Una volta attivato disattva il plugin e attivalo di nuovo."
1351
+
1352
+ #: includes/i18n.php:699
1353
+ msgid ""
1354
+ "We are sure it's an issue on our side and more than happy to resolve it for "
1355
+ "you ASAP if you give us a chance."
1356
+ msgstr "Siamo sicuri che sia un nostro problema e siamo più che felici di risolverlo per te al più presto. Per poter procedere abbiamo bisogno del tuo consenso."
1357
+
1358
+ #: includes/i18n.php:701
1359
+ msgid ""
1360
+ "Sorry for the inconvenience and we are here to help if you give us a chance."
1361
+ msgstr "Siamo spiacenti per l'inconveniente e siamo qui per aiutarti con il tuo permesso."
1362
+
1363
+ #: includes/i18n.php:703
1364
+ msgid "Yes - I'm giving you a chance to fix it"
1365
+ msgstr "Sì - sto dandovi la possibilità di risolvere il problema"
1366
+
1367
+ #: includes/i18n.php:705
1368
+ msgid ""
1369
+ "We will do our best to whitelist your server and resolve this issue ASAP. "
1370
+ "You will get a follow-up email to %s once we have an update."
1371
+ msgstr "Faremo del nostro meglio per mettere il server in whitelist e risolvere il problema il prima possibile. Avrai un aggiornamento dello stato tramite email all'indirizzo %s."
1372
+
1373
+ #: includes/i18n.php:707
1374
+ msgid "Let's try your previous version"
1375
+ msgstr "Proviamo con la versione precedente"
1376
+
1377
+ #: includes/i18n.php:709
1378
+ msgid "Uninstall this version and install the previous one."
1379
+ msgstr "Disinstalla questa versione e installa quella precedente."
1380
+
1381
+ #: includes/i18n.php:711
1382
+ msgid "That's exhausting, please deactivate"
1383
+ msgstr "È estenuante, disattivalo"
1384
+
1385
+ #: includes/i18n.php:713
1386
+ msgid ""
1387
+ "We feel your frustration and sincerely apologize for the inconvenience. Hope"
1388
+ " to see you again in the future."
1389
+ msgstr "Capiamo la tua frustrazione e ci scusiamo per l'inconveniente. Speriamo di rivederti nuovamente in futuro."
1390
+
1391
+ #: includes/i18n.php:715
1392
+ msgid ""
1393
+ "Thank for giving us the chance to fix it! A message was just sent to our "
1394
+ "technical staff. We will get back to you as soon as we have an update to %s."
1395
+ " Appreciate your patience."
1396
+ msgstr "Grazie per averci dato la possibilità di risolvere il problema! È stato appena inviato un messaggio al nostro staff tecnico. Ti risponderemo non appena avremo un aggiornamento riguardante %s. Grazie per la tua pazienza."
1397
+
1398
+ #: includes/i18n.php:717
1399
+ msgctxt "%1s - plugin title, %2s - API domain"
1400
+ msgid ""
1401
+ "Your server is blocking the access to Freemius' API, which is crucial for "
1402
+ "%1s synchronization. Please contact your host to whitelist %2s"
1403
+ msgstr "Il tuo server sta bloccando l'accesso all'API di Freemius. L'accesso è cruciale per quanto riguarda la la sincronizzazione di %1s. Per favore contatta il tuo host per aggiungere %2s alla whitelist."
1404
+
1405
+ #: includes/i18n.php:719
1406
+ msgid ""
1407
+ "It seems like one of the authentication parameters is wrong. Update your "
1408
+ "Public Key, Secret Key & User ID, and try again."
1409
+ msgstr "Sembra che uno dei parametri di autenticazione sia sbagliato. Aggiorna la tua chiave pubblica, Secret Key & User ID e riprova."
1410
+
1411
+ #: includes/i18n.php:725
1412
+ msgid ""
1413
+ "Please check your mailbox, you should receive an email via %s to confirm the"
1414
+ " ownership change. From security reasons, you must confirm the change within"
1415
+ " the next 15 min. If you cannot find the email, please check your spam "
1416
+ "folder."
1417
+ msgstr "Verifica di aver ricevuto l'email da %s per confermare il cambiamento del proprietario. Per ragioni di sicurezza devi confermare il cambiamento entro 15 minuti. Se non trovi l'email controlla nella posta indesiderata."
1418
+
1419
+ #: includes/i18n.php:727
1420
+ msgid ""
1421
+ "Thanks for confirming the ownership change. An email was just sent to %s for"
1422
+ " final approval."
1423
+ msgstr "Grazie per aver confermato il cambiamento del proprietario. Un' email è stata appena inviata a %s per la conferma finale."
1424
+
1425
+ #: includes/i18n.php:729
1426
+ msgid "%s is the new owner of the account."
1427
+ msgstr "%s è il nuovo proprietario dell'account."
1428
+
1429
+ #: includes/i18n.php:733
1430
+ msgctxt "addonX cannot run without pluginY"
1431
+ msgid "%s cannot run without %s."
1432
+ msgstr "%s non può funzionare senza %s."
1433
+
1434
+ #: includes/i18n.php:735
1435
+ msgctxt "addonX cannot run..."
1436
+ msgid "%s cannot run without the plugin."
1437
+ msgstr "%s non può funzionare senza il plugin."
1438
+
1439
+ #: includes/i18n.php:737
1440
+ msgctxt "pluginX activation was successfully..."
1441
+ msgid "%s activation was successfully completed."
1442
+ msgstr "%s è stato attivato con successo."
1443
+
1444
+ #: includes/i18n.php:739
1445
+ msgctxt "Plugin installer section title"
1446
+ msgid "Features & Pricing"
1447
+ msgstr "Caratteristiche & prezzi"
1448
+
1449
+ #: includes/i18n.php:741
1450
+ msgid "Add-on must be deployed to WordPress.org or Freemius."
1451
+ msgstr "L'add-on dev'essere distribuito da WordPress.org o Freemius."
1452
+
1453
+ #: includes/i18n.php:743
1454
+ msgid "Paid add-on must be deployed to Freemius."
1455
+ msgstr "Gli add-on a pagamento devono essere distribuiti da Freemius."
1456
+
1457
+ #: includes/i18n.php:747
1458
+ msgid ""
1459
+ "%s is a premium only add-on. You have to purchase a license first before "
1460
+ "activating the plugin."
1461
+ msgstr "%s è un add-on premium. Devi comprare una licenza prima di poter attivare il plugin."
1462
+
1463
+ #: includes/i18n.php:749
1464
+ msgid ""
1465
+ "%s free trial was successfully cancelled. Since the add-on is premium only "
1466
+ "it was automatically deactivated. If you like to use it in the future, "
1467
+ "you'll have to purchase a license."
1468
+ msgstr "Il periodo di prova gratuito %s è stato annullato con successo. Siccome l'add-on è premium, è stato disattivato automaticamente. Se vorrai usarlo in futuro, dovrai comprare una licenza."
1469
+
1470
+ #: includes/i18n.php:755
1471
+ msgctxt "as every month"
1472
+ msgid "Monthly"
1473
+ msgstr "Mensilmente"
1474
+
1475
+ #: includes/i18n.php:757
1476
+ msgctxt "as monthly period"
1477
+ msgid "mo"
1478
+ msgstr "mese"
1479
+
1480
+ #: includes/i18n.php:759
1481
+ msgctxt "as once a year"
1482
+ msgid "Annual"
1483
+ msgstr "Annuale"
1484
+
1485
+ #: includes/i18n.php:761
1486
+ msgctxt "as once a year"
1487
+ msgid "Annually"
1488
+ msgstr "Annualmente"
1489
+
1490
+ #: includes/i18n.php:763
1491
+ msgctxt "as once a year"
1492
+ msgid "Once"
1493
+ msgstr "Una volta"
1494
+
1495
+ #: includes/i18n.php:765
1496
+ msgctxt "as annual period"
1497
+ msgid "year"
1498
+ msgstr "anno"
1499
+
1500
+ #: includes/i18n.php:767
1501
+ msgid "Lifetime"
1502
+ msgstr "Tutta la vita"
1503
+
1504
+ #: includes/i18n.php:769
1505
+ msgctxt "e.g. the best product"
1506
+ msgid "Best"
1507
+ msgstr "Migliore"
1508
+
1509
+ #: includes/i18n.php:771
1510
+ msgctxt "e.g. billed monthly"
1511
+ msgid "Billed %s"
1512
+ msgstr "Fatturato %s"
1513
+
1514
+ #: includes/i18n.php:773
1515
+ msgctxt "as a discount of $5 or 10%"
1516
+ msgid "Save %s"
1517
+ msgstr "Risparmia %s"
1518
+
1519
+ #: includes/i18n.php:777
1520
+ msgid "View details"
1521
+ msgstr "Visualizza dettagli"
freemius/languages/freemius.pot ADDED
@@ -0,0 +1,1399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2016 freemius
2
+ # This file is distributed under the same license as the freemius package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: freemius\n"
6
+ "Report-Msgid-Bugs-To: https://github.com/Freemius/wordpress-sdk/issues\n"
7
+ "MIME-Version: 1.0\n"
8
+ "Content-Type: text/plain; charset=UTF-8\n"
9
+ "Content-Transfer-Encoding: 8bit\n"
10
+ "PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
11
+ "Last-Translator: Vova Feldman <vova@freemius.com>\n"
12
+ "Language-Team: Freemius Team <admin@freemius.com>\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "X-Poedit-SourceCharset: UTF-8\n"
15
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
16
+ "X-Poedit-SearchPath-0: .\n"
17
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ #: includes/i18n.php:41, includes/i18n.php:55
20
+ msgid "Yes - I'm in!"
21
+ msgstr ""
22
+
23
+ #: includes/i18n.php:43, includes/i18n.php:57
24
+ msgid "Not today"
25
+ msgstr ""
26
+
27
+ #: includes/i18n.php:69
28
+ msgid "Account"
29
+ msgstr ""
30
+
31
+ #: includes/i18n.php:71
32
+ msgid "Add On"
33
+ msgstr ""
34
+
35
+ #: includes/i18n.php:73
36
+ msgid "Contact Us"
37
+ msgstr ""
38
+
39
+ #: includes/i18n.php:75
40
+ msgid "Contact Support"
41
+ msgstr ""
42
+
43
+ #: includes/i18n.php:77
44
+ msgid "Change Ownership"
45
+ msgstr ""
46
+
47
+ #: includes/i18n.php:79
48
+ msgid "Support"
49
+ msgstr ""
50
+
51
+ #: includes/i18n.php:81
52
+ msgid "Support Forum"
53
+ msgstr ""
54
+
55
+ #: includes/i18n.php:83
56
+ msgid "Add Ons"
57
+ msgstr ""
58
+
59
+ #: includes/i18n.php:85
60
+ msgctxt "verb"
61
+ msgid "Upgrade"
62
+ msgstr ""
63
+
64
+ #: includes/i18n.php:87
65
+ msgid "Awesome"
66
+ msgstr ""
67
+
68
+ #: includes/i18n.php:89
69
+ msgctxt "noun"
70
+ msgid "Pricing"
71
+ msgstr ""
72
+
73
+ #: includes/i18n.php:91
74
+ msgctxt "noun"
75
+ msgid "Price"
76
+ msgstr ""
77
+
78
+ #: includes/i18n.php:93
79
+ msgid "Unlimited Updates"
80
+ msgstr ""
81
+
82
+ #: includes/i18n.php:95
83
+ msgctxt "verb"
84
+ msgid "Downgrade"
85
+ msgstr ""
86
+
87
+ #: includes/i18n.php:97
88
+ msgid "Cancel Trial"
89
+ msgstr ""
90
+
91
+ #: includes/i18n.php:99
92
+ msgid "Free Trial"
93
+ msgstr ""
94
+
95
+ #: includes/i18n.php:101
96
+ msgid "Start my free %s"
97
+ msgstr ""
98
+
99
+ #: includes/i18n.php:103
100
+ msgid "No commitment for %s - cancel anytime"
101
+ msgstr ""
102
+
103
+ #: includes/i18n.php:105
104
+ msgid "After your free %s, pay as little as %s"
105
+ msgstr ""
106
+
107
+ #: includes/i18n.php:107
108
+ msgid "Details"
109
+ msgstr ""
110
+
111
+ #: includes/i18n.php:109
112
+ msgid "Account Details"
113
+ msgstr ""
114
+
115
+ #: includes/i18n.php:111
116
+ msgctxt "verb"
117
+ msgid "Delete"
118
+ msgstr ""
119
+
120
+ #: includes/i18n.php:113
121
+ msgctxt "verb"
122
+ msgid "Show"
123
+ msgstr ""
124
+
125
+ #: includes/i18n.php:115
126
+ msgctxt "verb"
127
+ msgid "Hide"
128
+ msgstr ""
129
+
130
+ #: includes/i18n.php:117
131
+ msgctxt "verb"
132
+ msgid "Edit"
133
+ msgstr ""
134
+
135
+ #: includes/i18n.php:119
136
+ msgid "Date"
137
+ msgstr ""
138
+
139
+ #: includes/i18n.php:121
140
+ msgid "Amount"
141
+ msgstr ""
142
+
143
+ #: includes/i18n.php:123
144
+ msgid "Invoice"
145
+ msgstr ""
146
+
147
+ #: includes/i18n.php:125
148
+ msgid "Billing"
149
+ msgstr ""
150
+
151
+ #: includes/i18n.php:127
152
+ msgid "Payments"
153
+ msgstr ""
154
+
155
+ #: includes/i18n.php:129
156
+ msgid "Delete Account"
157
+ msgstr ""
158
+
159
+ #: includes/i18n.php:131
160
+ msgctxt "as close a window"
161
+ msgid "Dismiss"
162
+ msgstr ""
163
+
164
+ #: includes/i18n.php:133
165
+ msgctxt "as product pricing plan"
166
+ msgid "Plan"
167
+ msgstr ""
168
+
169
+ #: includes/i18n.php:135
170
+ msgid "Change Plan"
171
+ msgstr ""
172
+
173
+ #: includes/i18n.php:137
174
+ msgctxt "as download professional version"
175
+ msgid "Download %s Version"
176
+ msgstr ""
177
+
178
+ #: includes/i18n.php:139
179
+ msgctxt "as download professional version now"
180
+ msgid "Download %s version now"
181
+ msgstr ""
182
+
183
+ #: includes/i18n.php:141
184
+ msgctxt "as download latest version"
185
+ msgid "Download Latest"
186
+ msgstr ""
187
+
188
+ #: includes/i18n.php:143
189
+ msgctxt "E.g. you have a professional license."
190
+ msgid "You have a %s license."
191
+ msgstr ""
192
+
193
+ #: includes/i18n.php:145
194
+ msgid "New"
195
+ msgstr ""
196
+
197
+ #: includes/i18n.php:147
198
+ msgid "Free"
199
+ msgstr ""
200
+
201
+ #: includes/i18n.php:149
202
+ msgctxt "as trial plan"
203
+ msgid "Trial"
204
+ msgstr ""
205
+
206
+ #: includes/i18n.php:151
207
+ msgctxt "verb"
208
+ msgid "Purchase"
209
+ msgstr ""
210
+
211
+ #: includes/i18n.php:153
212
+ msgid "Purchase License"
213
+ msgstr ""
214
+
215
+ #: includes/i18n.php:155
216
+ msgctxt "verb"
217
+ msgid "Buy"
218
+ msgstr ""
219
+
220
+ #: includes/i18n.php:157
221
+ msgid "Buy License"
222
+ msgstr ""
223
+
224
+ #: includes/i18n.php:159
225
+ msgid "Single Site License"
226
+ msgstr ""
227
+
228
+ #: includes/i18n.php:161
229
+ msgid "Unlimited Licenses"
230
+ msgstr ""
231
+
232
+ #: includes/i18n.php:163
233
+ msgid "Up to %s Sites"
234
+ msgstr ""
235
+
236
+ #: includes/i18n.php:165
237
+ msgid "%sRenew your license now%s to access version %s features and support."
238
+ msgstr ""
239
+
240
+ #: includes/i18n.php:167
241
+ msgid "Enter the email address you've used for the upgrade below and we will resend you the license key."
242
+ msgstr ""
243
+
244
+ #: includes/i18n.php:169
245
+ msgctxt "e.g. Professional Plan"
246
+ msgid "%s Plan"
247
+ msgstr ""
248
+
249
+ #: includes/i18n.php:171
250
+ msgid "You are just one step away - %s"
251
+ msgstr ""
252
+
253
+ #: includes/i18n.php:173
254
+ msgctxt "%s - plugin name. As complete \"Jetpack\" activation now"
255
+ msgid "Complete \"%s\" Activation Now"
256
+ msgstr ""
257
+
258
+ #: includes/i18n.php:175
259
+ msgid "We made a few tweaks to the plugin, %s"
260
+ msgstr ""
261
+
262
+ #: includes/i18n.php:177
263
+ msgid "Opt-in to make \"%s\" Better!"
264
+ msgstr ""
265
+
266
+ #: includes/i18n.php:179
267
+ msgid "Error"
268
+ msgstr ""
269
+
270
+ #: includes/i18n.php:181
271
+ msgid "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
272
+ msgstr ""
273
+
274
+ #: includes/i18n.php:187
275
+ msgctxt "as expiration date"
276
+ msgid "Expiration"
277
+ msgstr ""
278
+
279
+ #: includes/i18n.php:189
280
+ msgctxt "as software license"
281
+ msgid "License"
282
+ msgstr ""
283
+
284
+ #: includes/i18n.php:191
285
+ msgid "not verified"
286
+ msgstr ""
287
+
288
+ #: includes/i18n.php:193
289
+ msgid "Verify Email"
290
+ msgstr ""
291
+
292
+ #: includes/i18n.php:195
293
+ msgctxt "e.g. expires in 2 months"
294
+ msgid "Expires in %s"
295
+ msgstr ""
296
+
297
+ #: includes/i18n.php:197
298
+ msgctxt "e.g. auto renews in 2 months"
299
+ msgid "Auto renews in %s"
300
+ msgstr ""
301
+
302
+ #: includes/i18n.php:199
303
+ msgid "No expiration"
304
+ msgstr ""
305
+
306
+ #: includes/i18n.php:201
307
+ msgid "Expired"
308
+ msgstr ""
309
+
310
+ #: includes/i18n.php:203
311
+ msgid "Cancelled"
312
+ msgstr ""
313
+
314
+ #: includes/i18n.php:205
315
+ msgctxt "e.g. In 2 hours"
316
+ msgid "In %s"
317
+ msgstr ""
318
+
319
+ #: includes/i18n.php:207
320
+ msgctxt "e.g. 2 min ago"
321
+ msgid "%s ago"
322
+ msgstr ""
323
+
324
+ #: includes/i18n.php:209
325
+ msgctxt "as plugin version"
326
+ msgid "Version"
327
+ msgstr ""
328
+
329
+ #: includes/i18n.php:211
330
+ msgid "Name"
331
+ msgstr ""
332
+
333
+ #: includes/i18n.php:213
334
+ msgid "Email"
335
+ msgstr ""
336
+
337
+ #: includes/i18n.php:215
338
+ msgid "Email address"
339
+ msgstr ""
340
+
341
+ #: includes/i18n.php:217
342
+ msgid "Verified"
343
+ msgstr ""
344
+
345
+ #: includes/i18n.php:219
346
+ msgid "Plugin"
347
+ msgstr ""
348
+
349
+ #: includes/i18n.php:221
350
+ msgid "Plugins"
351
+ msgstr ""
352
+
353
+ #: includes/i18n.php:223
354
+ msgid "Themes"
355
+ msgstr ""
356
+
357
+ #: includes/i18n.php:225
358
+ msgctxt "as file/folder path"
359
+ msgid "Path"
360
+ msgstr ""
361
+
362
+ #: includes/i18n.php:227
363
+ msgid "Title"
364
+ msgstr ""
365
+
366
+ #: includes/i18n.php:229
367
+ msgid "Free version"
368
+ msgstr ""
369
+
370
+ #: includes/i18n.php:231
371
+ msgid "Premium version"
372
+ msgstr ""
373
+
374
+ #: includes/i18n.php:233
375
+ msgctxt "as WP plugin slug"
376
+ msgid "Slug"
377
+ msgstr ""
378
+
379
+ #: includes/i18n.php:235
380
+ msgid "ID"
381
+ msgstr ""
382
+
383
+ #: includes/i18n.php:237
384
+ msgid "Users"
385
+ msgstr ""
386
+
387
+ #: includes/i18n.php:239
388
+ msgid "Plugin Installs"
389
+ msgstr ""
390
+
391
+ #: includes/i18n.php:241
392
+ msgctxt "like websites"
393
+ msgid "Sites"
394
+ msgstr ""
395
+
396
+ #: includes/i18n.php:243
397
+ msgid "User ID"
398
+ msgstr ""
399
+
400
+ #: includes/i18n.php:245
401
+ msgid "Site ID"
402
+ msgstr ""
403
+
404
+ #: includes/i18n.php:247
405
+ msgid "Public Key"
406
+ msgstr ""
407
+
408
+ #: includes/i18n.php:249
409
+ msgid "Secret Key"
410
+ msgstr ""
411
+
412
+ #: includes/i18n.php:251
413
+ msgctxt "as secret encryption key missing"
414
+ msgid "No Secret"
415
+ msgstr ""
416
+
417
+ #: includes/i18n.php:253
418
+ msgid "No ID"
419
+ msgstr ""
420
+
421
+ #: includes/i18n.php:255
422
+ msgctxt "as synchronize license"
423
+ msgid "Sync License"
424
+ msgstr ""
425
+
426
+ #: includes/i18n.php:257
427
+ msgctxt "as synchronize"
428
+ msgid "Sync"
429
+ msgstr ""
430
+
431
+ #: includes/i18n.php:259
432
+ msgid "Activate License"
433
+ msgstr ""
434
+
435
+ #: includes/i18n.php:261
436
+ msgid "Activate Free Version"
437
+ msgstr ""
438
+
439
+ #: includes/i18n.php:263
440
+ msgid "Please enter the license key that you received in the email right after the purchase:"
441
+ msgstr ""
442
+
443
+ #: includes/i18n.php:265
444
+ msgid "Activating license..."
445
+ msgstr ""
446
+
447
+ #: includes/i18n.php:267
448
+ msgid "Change License"
449
+ msgstr ""
450
+
451
+ #: includes/i18n.php:269
452
+ msgid "Update License"
453
+ msgstr ""
454
+
455
+ #: includes/i18n.php:271
456
+ msgid "Deactivate License"
457
+ msgstr ""
458
+
459
+ #: includes/i18n.php:273
460
+ msgid "Activate"
461
+ msgstr ""
462
+
463
+ #: includes/i18n.php:275
464
+ msgid "Deactivate"
465
+ msgstr ""
466
+
467
+ #: includes/i18n.php:277
468
+ msgid "Skip & Deactivate"
469
+ msgstr ""
470
+
471
+ #: includes/i18n.php:279
472
+ msgid "No - just deactivate"
473
+ msgstr ""
474
+
475
+ #: includes/i18n.php:281
476
+ msgid "Yes - do your thing"
477
+ msgstr ""
478
+
479
+ #: includes/i18n.php:283
480
+ msgctxt "active mode"
481
+ msgid "Active"
482
+ msgstr ""
483
+
484
+ #: includes/i18n.php:285
485
+ msgctxt "is active mode?"
486
+ msgid "Is Active"
487
+ msgstr ""
488
+
489
+ #: includes/i18n.php:287
490
+ msgid "Install Now"
491
+ msgstr ""
492
+
493
+ #: includes/i18n.php:289
494
+ msgid "Install Update Now"
495
+ msgstr ""
496
+
497
+ #: includes/i18n.php:291
498
+ msgid "More information about %s"
499
+ msgstr ""
500
+
501
+ #: includes/i18n.php:293
502
+ msgid "Localhost"
503
+ msgstr ""
504
+
505
+ #: includes/i18n.php:295
506
+ msgctxt "as activate Professional plan"
507
+ msgid "Activate %s Plan"
508
+ msgstr ""
509
+
510
+ #: includes/i18n.php:297
511
+ msgctxt "as 5 licenses left"
512
+ msgid "%s left"
513
+ msgstr ""
514
+
515
+ #: includes/i18n.php:299
516
+ msgid "Last license"
517
+ msgstr ""
518
+
519
+ #: includes/i18n.php:301
520
+ msgid "What is your %s?"
521
+ msgstr ""
522
+
523
+ #: includes/i18n.php:303
524
+ msgid "Activate this add-on"
525
+ msgstr ""
526
+
527
+ #: includes/i18n.php:305
528
+ msgid "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?"
529
+ msgstr ""
530
+
531
+ #: includes/i18n.php:307
532
+ msgid "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?"
533
+ msgstr ""
534
+
535
+ #: includes/i18n.php:309
536
+ msgid "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?"
537
+ msgstr ""
538
+
539
+ #: includes/i18n.php:311
540
+ msgid "Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s."
541
+ msgstr ""
542
+
543
+ #: includes/i18n.php:313
544
+ msgid "Cancelling the trial will immediately block access to all premium features. Are you sure?"
545
+ msgstr ""
546
+
547
+ #: includes/i18n.php:315
548
+ msgid "You can still enjoy all %s features but you will not have access to plugin updates and support."
549
+ msgstr ""
550
+
551
+ #: includes/i18n.php:317
552
+ msgid "Once your license expire you can still use the Free version but you will NOT have access to the %s features."
553
+ msgstr ""
554
+
555
+ #: includes/i18n.php:319
556
+ msgid "Are you sure you want to proceed?"
557
+ msgstr ""
558
+
559
+ #: includes/i18n.php:325
560
+ msgid "Add Ons for %s"
561
+ msgstr ""
562
+
563
+ #: includes/i18n.php:327
564
+ msgid "We could'nt load the add-ons list. It's probably an issue on our side, please try to come back in few minutes."
565
+ msgstr ""
566
+
567
+ #: includes/i18n.php:331
568
+ msgid "Anonymous feedback"
569
+ msgstr ""
570
+
571
+ #: includes/i18n.php:333
572
+ msgid "Quick feedback"
573
+ msgstr ""
574
+
575
+ #: includes/i18n.php:335
576
+ msgid "If you have a moment, please let us know why you are deactivating"
577
+ msgstr ""
578
+
579
+ #: includes/i18n.php:337
580
+ msgid "Yes - Deactivate"
581
+ msgstr ""
582
+
583
+ #: includes/i18n.php:339
584
+ msgid "Submit & Deactivate"
585
+ msgstr ""
586
+
587
+ #: includes/i18n.php:341
588
+ msgctxt "the text of the cancel button of the plugin deactivation dialog box."
589
+ msgid "Cancel"
590
+ msgstr ""
591
+
592
+ #: includes/i18n.php:343
593
+ msgid "I no longer need the plugin"
594
+ msgstr ""
595
+
596
+ #: includes/i18n.php:345
597
+ msgid "I found a better plugin"
598
+ msgstr ""
599
+
600
+ #: includes/i18n.php:347
601
+ msgid "I only needed the plugin for a short period"
602
+ msgstr ""
603
+
604
+ #: includes/i18n.php:349
605
+ msgid "The plugin broke my site"
606
+ msgstr ""
607
+
608
+ #: includes/i18n.php:351
609
+ msgid "The plugin suddenly stopped working"
610
+ msgstr ""
611
+
612
+ #: includes/i18n.php:353
613
+ msgid "I can't pay for it anymore"
614
+ msgstr ""
615
+
616
+ #: includes/i18n.php:355
617
+ msgid "It's a temporary deactivation. I'm just debugging an issue."
618
+ msgstr ""
619
+
620
+ #: includes/i18n.php:357
621
+ msgctxt "the text of the \"other\" reason for deactivating the plugin that is shown in the modal box."
622
+ msgid "Other"
623
+ msgstr ""
624
+
625
+ #: includes/i18n.php:359
626
+ msgid "Kindly tell us the reason so we can improve."
627
+ msgstr ""
628
+
629
+ #: includes/i18n.php:361
630
+ msgid "What's the plugin's name?"
631
+ msgstr ""
632
+
633
+ #: includes/i18n.php:363
634
+ msgid "What price would you feel comfortable paying?"
635
+ msgstr ""
636
+
637
+ #: includes/i18n.php:365
638
+ msgid "I couldn't understand how to make it work"
639
+ msgstr ""
640
+
641
+ #: includes/i18n.php:367
642
+ msgid "The plugin is great, but I need specific feature that you don't support"
643
+ msgstr ""
644
+
645
+ #: includes/i18n.php:369
646
+ msgid "The plugin is not working"
647
+ msgstr ""
648
+
649
+ #: includes/i18n.php:371
650
+ msgid "It's not what I was looking for"
651
+ msgstr ""
652
+
653
+ #: includes/i18n.php:373
654
+ msgid "The plugin didn't work as expected"
655
+ msgstr ""
656
+
657
+ #: includes/i18n.php:375
658
+ msgid "What feature?"
659
+ msgstr ""
660
+
661
+ #: includes/i18n.php:377
662
+ msgid "Kindly share what didn't work so we can fix it for future users..."
663
+ msgstr ""
664
+
665
+ #: includes/i18n.php:379
666
+ msgid "What you've been looking for?"
667
+ msgstr ""
668
+
669
+ #: includes/i18n.php:381
670
+ msgid "What did you expect?"
671
+ msgstr ""
672
+
673
+ #: includes/i18n.php:383
674
+ msgid "The plugin didn't work"
675
+ msgstr ""
676
+
677
+ #: includes/i18n.php:385
678
+ msgid "I don't like to share my information with you"
679
+ msgstr ""
680
+
681
+ #: includes/i18n.php:387
682
+ msgid "You might have missed it, but you don't have to share any data and can just %s the opt-in."
683
+ msgstr ""
684
+
685
+ #: includes/i18n.php:395
686
+ msgctxt "greeting"
687
+ msgid "Hey %s,"
688
+ msgstr ""
689
+
690
+ #: includes/i18n.php:397
691
+ msgctxt "a greeting. E.g. Thanks John!"
692
+ msgid "Thanks %s!"
693
+ msgstr ""
694
+
695
+ #: includes/i18n.php:399
696
+ msgid "In order to enjoy all our features and functionality, %s needs to connect your user, %s at %s, to %s"
697
+ msgstr ""
698
+
699
+ #: includes/i18n.php:401
700
+ msgid "Please help us improve %2$s! If you opt-in, some data about your usage of %2$s will be sent to %5$s. If you skip this, that's okay! %2$s will still work just fine."
701
+ msgstr ""
702
+
703
+ #: includes/i18n.php:403
704
+ msgid "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."
705
+ msgstr ""
706
+
707
+ #: includes/i18n.php:405
708
+ msgid "Thanks for purchasing %s! To get started, please enter your license key:"
709
+ msgstr ""
710
+
711
+ #: includes/i18n.php:407
712
+ msgid "The plugin will be periodically sending data to %s to check for plugin updates and verify the validity of your license."
713
+ msgstr ""
714
+
715
+ #: includes/i18n.php:409
716
+ msgid "What permissions are being granted?"
717
+ msgstr ""
718
+
719
+ #: includes/i18n.php:411
720
+ msgid "Your Profile Overview"
721
+ msgstr ""
722
+
723
+ #: includes/i18n.php:413
724
+ msgid "Name and email address"
725
+ msgstr ""
726
+
727
+ #: includes/i18n.php:415
728
+ msgid "Your Site Overview"
729
+ msgstr ""
730
+
731
+ #: includes/i18n.php:417
732
+ msgid "Site URL, WP version, PHP info, plugins & themes"
733
+ msgstr ""
734
+
735
+ #: includes/i18n.php:419
736
+ msgid "Current Plugin Events"
737
+ msgstr ""
738
+
739
+ #: includes/i18n.php:421
740
+ msgid "Activation, deactivation and uninstall"
741
+ msgstr ""
742
+
743
+ #: includes/i18n.php:423
744
+ msgid "Plugins & Themes"
745
+ msgstr ""
746
+
747
+ #: includes/i18n.php:425
748
+ msgid "Titles, versions and state."
749
+ msgstr ""
750
+
751
+ #: includes/i18n.php:427
752
+ msgid "Newsletter"
753
+ msgstr ""
754
+
755
+ #: includes/i18n.php:429
756
+ msgid "Updates, announcements, marketing, no spam"
757
+ msgstr ""
758
+
759
+ #: includes/i18n.php:431
760
+ msgid "Privacy Policy"
761
+ msgstr ""
762
+
763
+ #: includes/i18n.php:433
764
+ msgid "Terms of Service"
765
+ msgstr ""
766
+
767
+ #: includes/i18n.php:435
768
+ msgctxt "as activating plugin"
769
+ msgid "Activating"
770
+ msgstr ""
771
+
772
+ #: includes/i18n.php:437
773
+ msgctxt "as in the process of sending an email"
774
+ msgid "Sending email"
775
+ msgstr ""
776
+
777
+ #: includes/i18n.php:439
778
+ msgctxt "button label"
779
+ msgid "Allow & Continue"
780
+ msgstr ""
781
+
782
+ #: includes/i18n.php:441
783
+ msgctxt "button label"
784
+ msgid "Agree & Activate License"
785
+ msgstr ""
786
+
787
+ #: includes/i18n.php:443
788
+ msgctxt "verb"
789
+ msgid "Skip"
790
+ msgstr ""
791
+
792
+ #: includes/i18n.php:445
793
+ msgid "Click here to use the plugin anonymously"
794
+ msgstr ""
795
+
796
+ #: includes/i18n.php:447
797
+ msgid "Re-send activation email"
798
+ msgstr ""
799
+
800
+ #: includes/i18n.php:449
801
+ msgid "License key"
802
+ msgstr ""
803
+
804
+ #: includes/i18n.php:451
805
+ msgid "Send License Key"
806
+ msgstr ""
807
+
808
+ #: includes/i18n.php:453
809
+ msgid "Sending license key"
810
+ msgstr ""
811
+
812
+ #: includes/i18n.php:455
813
+ msgid "Have a license key?"
814
+ msgstr ""
815
+
816
+ #: includes/i18n.php:457
817
+ msgid "Don't have a license key?"
818
+ msgstr ""
819
+
820
+ #: includes/i18n.php:459
821
+ msgid "Can't find your license key?"
822
+ msgstr ""
823
+
824
+ #: includes/i18n.php:471
825
+ msgid "Screenshots"
826
+ msgstr ""
827
+
828
+ #: includes/i18n.php:473
829
+ msgid "Click to view full-size screenshot %d"
830
+ msgstr ""
831
+
832
+ #: includes/i18n.php:481
833
+ msgid "Freemius Debug"
834
+ msgstr ""
835
+
836
+ #: includes/i18n.php:483
837
+ msgctxt "as turned on"
838
+ msgid "On"
839
+ msgstr ""
840
+
841
+ #: includes/i18n.php:485
842
+ msgctxt "as turned off"
843
+ msgid "Off"
844
+ msgstr ""
845
+
846
+ #: includes/i18n.php:487
847
+ msgctxt "as code debugging"
848
+ msgid "Debugging"
849
+ msgstr ""
850
+
851
+ #: includes/i18n.php:489
852
+ msgid "Freemius State"
853
+ msgstr ""
854
+
855
+ #: includes/i18n.php:491
856
+ msgctxt "as connection was successful"
857
+ msgid "Connected"
858
+ msgstr ""
859
+
860
+ #: includes/i18n.php:493
861
+ msgctxt "as connection blocked"
862
+ msgid "Blocked"
863
+ msgstr ""
864
+
865
+ #: includes/i18n.php:495
866
+ msgctxt "as application program interface"
867
+ msgid "API"
868
+ msgstr ""
869
+
870
+ #: includes/i18n.php:497
871
+ msgctxt "as software development kit versions"
872
+ msgid "SDK"
873
+ msgstr ""
874
+
875
+ #: includes/i18n.php:499
876
+ msgctxt "as software development kit versions"
877
+ msgid "SDK Versions"
878
+ msgstr ""
879
+
880
+ #: includes/i18n.php:501
881
+ msgctxt "as plugin folder path"
882
+ msgid "Plugin Path"
883
+ msgstr ""
884
+
885
+ #: includes/i18n.php:503
886
+ msgctxt "as sdk path"
887
+ msgid "SDK Path"
888
+ msgstr ""
889
+
890
+ #: includes/i18n.php:505
891
+ msgid "Add Ons of Plugin %s"
892
+ msgstr ""
893
+
894
+ #: includes/i18n.php:507
895
+ msgid "Are you sure you want to delete all Freemius data?"
896
+ msgstr ""
897
+
898
+ #: includes/i18n.php:509
899
+ msgid "Actions"
900
+ msgstr ""
901
+
902
+ #: includes/i18n.php:511
903
+ msgid "Delete All Accounts"
904
+ msgstr ""
905
+
906
+ #: includes/i18n.php:513
907
+ msgid "Start Fresh"
908
+ msgstr ""
909
+
910
+ #: includes/i18n.php:515
911
+ msgid "Clear API Cache"
912
+ msgstr ""
913
+
914
+ #: includes/i18n.php:517
915
+ msgid "Sync Data From Server"
916
+ msgstr ""
917
+
918
+ #: includes/i18n.php:519
919
+ msgid "Scheduled Crons"
920
+ msgstr ""
921
+
922
+ #: includes/i18n.php:521
923
+ msgid "Plugins & Themes Sync"
924
+ msgstr ""
925
+
926
+ #: includes/i18n.php:529
927
+ msgctxt "as congratulations"
928
+ msgid "Congrats"
929
+ msgstr ""
930
+
931
+ #: includes/i18n.php:531
932
+ msgctxt "exclamation"
933
+ msgid "Oops"
934
+ msgstr ""
935
+
936
+ #: includes/i18n.php:533
937
+ msgctxt "interjection expressing joy or exuberance"
938
+ msgid "Yee-haw"
939
+ msgstr ""
940
+
941
+ #: includes/i18n.php:535
942
+ msgctxt "(especially in electronic communication) used to express elation, enthusiasm, or triumph."
943
+ msgid "W00t"
944
+ msgstr ""
945
+
946
+ #: includes/i18n.php:537
947
+ msgctxt "a positive response"
948
+ msgid "Right on"
949
+ msgstr ""
950
+
951
+ #: includes/i18n.php:539
952
+ msgctxt "something somebody says when they are thinking about what you have just said. "
953
+ msgid "Hmm"
954
+ msgstr ""
955
+
956
+ #: includes/i18n.php:541
957
+ msgid "O.K"
958
+ msgstr ""
959
+
960
+ #: includes/i18n.php:543
961
+ msgctxt "exclamation"
962
+ msgid "Hey"
963
+ msgstr ""
964
+
965
+ #: includes/i18n.php:545
966
+ msgctxt "advance notice of something that will need attention."
967
+ msgid "Heads up"
968
+ msgstr ""
969
+
970
+ #: includes/i18n.php:553
971
+ msgid "Seems like you got the latest release."
972
+ msgstr ""
973
+
974
+ #: includes/i18n.php:555
975
+ msgid "You are all good!"
976
+ msgstr ""
977
+
978
+ #: includes/i18n.php:557
979
+ msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
980
+ msgstr ""
981
+
982
+ #: includes/i18n.php:559
983
+ msgid "If you would like to give up the ownership of the plugin's account to %s click the Change Ownership button."
984
+ msgstr ""
985
+
986
+ #: includes/i18n.php:561
987
+ msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
988
+ msgstr ""
989
+
990
+ #: includes/i18n.php:563
991
+ msgid "Your name was successfully updated."
992
+ msgstr ""
993
+
994
+ #: includes/i18n.php:565
995
+ msgid "You have successfully updated your %s."
996
+ msgstr ""
997
+
998
+ #: includes/i18n.php:567
999
+ msgid "Please provide your full name."
1000
+ msgstr ""
1001
+
1002
+ #: includes/i18n.php:569
1003
+ msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
1004
+ msgstr ""
1005
+
1006
+ #: includes/i18n.php:571
1007
+ msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
1008
+ msgstr ""
1009
+
1010
+ #: includes/i18n.php:573
1011
+ msgid "No credit card required"
1012
+ msgstr ""
1013
+
1014
+ #: includes/i18n.php:575
1015
+ msgid "Premium plugin version was successfully activated."
1016
+ msgstr ""
1017
+
1018
+ #: includes/i18n.php:577
1019
+ msgid "The upgrade of %s was successfully completed."
1020
+ msgstr ""
1021
+
1022
+ #: includes/i18n.php:579
1023
+ msgid "Your account was successfully activated with the %s plan."
1024
+ msgstr ""
1025
+
1026
+ #: includes/i18n.php:581
1027
+ msgid "Download the latest %s version now"
1028
+ msgstr ""
1029
+
1030
+ #: includes/i18n.php:583
1031
+ msgid "Please follow these steps to complete the upgrade"
1032
+ msgstr ""
1033
+
1034
+ #: includes/i18n.php:585
1035
+ msgid "Download the latest %s version"
1036
+ msgstr ""
1037
+
1038
+ #: includes/i18n.php:587
1039
+ msgid "Deactivate the free version"
1040
+ msgstr ""
1041
+
1042
+ #: includes/i18n.php:589
1043
+ msgid "Upload and activate the downloaded version"
1044
+ msgstr ""
1045
+
1046
+ #: includes/i18n.php:591
1047
+ msgid "How to upload and activate?"
1048
+ msgstr ""
1049
+
1050
+ #: includes/i18n.php:593
1051
+ msgctxt "%s - product name, e.g. Facebook add-on was successfully..."
1052
+ msgid "%s Add-on was successfully purchased."
1053
+ msgstr ""
1054
+
1055
+ #: includes/i18n.php:595
1056
+ msgid "Your %s Add-on plan was successfully upgraded."
1057
+ msgstr ""
1058
+
1059
+ #: includes/i18n.php:597
1060
+ msgid "Your email has been successfully verified - you are AWESOME!"
1061
+ msgstr ""
1062
+
1063
+ #: includes/i18n.php:599
1064
+ msgid "Your plan was successfully upgraded."
1065
+ msgstr ""
1066
+
1067
+ #: includes/i18n.php:601
1068
+ msgid "Your plan was successfully changed to %s."
1069
+ msgstr ""
1070
+
1071
+ #: includes/i18n.php:603
1072
+ msgid "Your license has expired. You can still continue using the free plugin forever."
1073
+ msgstr ""
1074
+
1075
+ #: includes/i18n.php:605
1076
+ msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
1077
+ msgstr ""
1078
+
1079
+ #: includes/i18n.php:607
1080
+ msgid "Your trial has been successfully started."
1081
+ msgstr ""
1082
+
1083
+ #: includes/i18n.php:609
1084
+ msgid "Your license was successfully activated."
1085
+ msgstr ""
1086
+
1087
+ #: includes/i18n.php:611
1088
+ msgid "It looks like your site currently doesn't have an active license."
1089
+ msgstr ""
1090
+
1091
+ #: includes/i18n.php:613
1092
+ msgid "Your license was successfully deactivated, you are back to the %s plan."
1093
+ msgstr ""
1094
+
1095
+ #: includes/i18n.php:615
1096
+ msgid "It looks like the license deactivation failed."
1097
+ msgstr ""
1098
+
1099
+ #: includes/i18n.php:617
1100
+ msgid "It looks like the license could not be activated."
1101
+ msgstr ""
1102
+
1103
+ #: includes/i18n.php:619
1104
+ msgid "Error received from the server:"
1105
+ msgstr ""
1106
+
1107
+ #: includes/i18n.php:621
1108
+ msgid "Your trial has expired. You can still continue using all our free features."
1109
+ msgstr ""
1110
+
1111
+ #: includes/i18n.php:623
1112
+ msgid "Your plan was successfully downgraded. Your %s plan license will expire in %s."
1113
+ msgstr ""
1114
+
1115
+ #: includes/i18n.php:625
1116
+ msgid "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
1117
+ msgstr ""
1118
+
1119
+ #: includes/i18n.php:627
1120
+ msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
1121
+ msgstr ""
1122
+
1123
+ #: includes/i18n.php:629
1124
+ msgid "Your %s free trial was successfully cancelled."
1125
+ msgstr ""
1126
+
1127
+ #: includes/i18n.php:631
1128
+ msgctxt "%s - numeric version number"
1129
+ msgid "Version %s was released."
1130
+ msgstr ""
1131
+
1132
+ #: includes/i18n.php:633
1133
+ msgid "Please download %s."
1134
+ msgstr ""
1135
+
1136
+ #: includes/i18n.php:635
1137
+ msgctxt "%s - plan name, as the latest professional version here"
1138
+ msgid "the latest %s version here"
1139
+ msgstr ""
1140
+
1141
+ #: includes/i18n.php:637
1142
+ msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
1143
+ msgstr ""
1144
+
1145
+ #: includes/i18n.php:639
1146
+ msgctxt "call to action"
1147
+ msgid "Start free trial"
1148
+ msgstr ""
1149
+
1150
+ #: includes/i18n.php:641
1151
+ msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
1152
+ msgstr ""
1153
+
1154
+ #: includes/i18n.php:643
1155
+ msgid "You already utilized a trial before."
1156
+ msgstr ""
1157
+
1158
+ #: includes/i18n.php:645
1159
+ msgid "You are already running the plugin in a trial mode."
1160
+ msgstr ""
1161
+
1162
+ #: includes/i18n.php:647
1163
+ msgid "Plan %s do not exist, therefore, can't start a trial."
1164
+ msgstr ""
1165
+
1166
+ #: includes/i18n.php:649
1167
+ msgid "Plan %s does not support a trial period."
1168
+ msgstr ""
1169
+
1170
+ #: includes/i18n.php:651
1171
+ msgid "None of the plugin's plans supports a trial period."
1172
+ msgstr ""
1173
+
1174
+ #: includes/i18n.php:653
1175
+ msgid "Unexpected API error. Please contact the plugin's author with the following error."
1176
+ msgstr ""
1177
+
1178
+ #: includes/i18n.php:655
1179
+ msgid "No commitment for %s days - cancel anytime!"
1180
+ msgstr ""
1181
+
1182
+ #: includes/i18n.php:657
1183
+ msgid "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."
1184
+ msgstr ""
1185
+
1186
+ #: includes/i18n.php:659
1187
+ msgid "Couldn't activate %s."
1188
+ msgstr ""
1189
+
1190
+ #: includes/i18n.php:661
1191
+ msgid "Please contact us with the following message:"
1192
+ msgstr ""
1193
+
1194
+ #: includes/i18n.php:663
1195
+ msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
1196
+ msgstr ""
1197
+
1198
+ #: includes/i18n.php:665
1199
+ msgid "Please contact us here"
1200
+ msgstr ""
1201
+
1202
+ #: includes/i18n.php:667
1203
+ msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
1204
+ msgstr ""
1205
+
1206
+ #: includes/i18n.php:673
1207
+ msgid "From unknown reason, the API connectivity test failed."
1208
+ msgstr ""
1209
+
1210
+ #: includes/i18n.php:675
1211
+ msgid "It's probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?"
1212
+ msgstr ""
1213
+
1214
+ #: includes/i18n.php:677
1215
+ msgid "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."
1216
+ msgstr ""
1217
+
1218
+ #: includes/i18n.php:679
1219
+ msgid "From unknown reason, CloudFlare, the firewall we use, blocks the connection."
1220
+ msgstr ""
1221
+
1222
+ #: includes/i18n.php:681
1223
+ msgctxt "as pluginX requires an access to our API"
1224
+ msgid "%s requires an access to our API."
1225
+ msgstr ""
1226
+
1227
+ #: includes/i18n.php:683
1228
+ msgid "It looks like your server is using Squid ACL (access control lists), which blocks the connection."
1229
+ msgstr ""
1230
+
1231
+ #: includes/i18n.php:685
1232
+ msgid "I don't know what is Squid or ACL, help me!"
1233
+ msgstr ""
1234
+
1235
+ #: includes/i18n.php:687, includes/i18n.php:695
1236
+ msgid "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."
1237
+ msgstr ""
1238
+
1239
+ #: includes/i18n.php:689
1240
+ msgid "I'm a system administrator"
1241
+ msgstr ""
1242
+
1243
+ #: includes/i18n.php:691
1244
+ msgid "Great, please whitelist the following domains: %s. Once you done, deactivate the plugin and activate it again."
1245
+ msgstr ""
1246
+
1247
+ #: includes/i18n.php:693
1248
+ msgid "I don't know what is cURL or how to install it, help me!"
1249
+ msgstr ""
1250
+
1251
+ #: includes/i18n.php:697
1252
+ msgid "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."
1253
+ msgstr ""
1254
+
1255
+ #: includes/i18n.php:699
1256
+ msgid "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."
1257
+ msgstr ""
1258
+
1259
+ #: includes/i18n.php:701
1260
+ msgid "Sorry for the inconvenience and we are here to help if you give us a chance."
1261
+ msgstr ""
1262
+
1263
+ #: includes/i18n.php:703
1264
+ msgid "Yes - I'm giving you a chance to fix it"
1265
+ msgstr ""
1266
+
1267
+ #: includes/i18n.php:705
1268
+ msgid "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."
1269
+ msgstr ""
1270
+
1271
+ #: includes/i18n.php:707
1272
+ msgid "Let's try your previous version"
1273
+ msgstr ""
1274
+
1275
+ #: includes/i18n.php:709
1276
+ msgid "Uninstall this version and install the previous one."
1277
+ msgstr ""
1278
+
1279
+ #: includes/i18n.php:711
1280
+ msgid "That's exhausting, please deactivate"
1281
+ msgstr ""
1282
+
1283
+ #: includes/i18n.php:713
1284
+ msgid "We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future."
1285
+ msgstr ""
1286
+
1287
+ #: includes/i18n.php:715
1288
+ msgid "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."
1289
+ msgstr ""
1290
+
1291
+ #: includes/i18n.php:717
1292
+ msgctxt "%1s - plugin title, %2s - API domain"
1293
+ msgid "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
1294
+ msgstr ""
1295
+
1296
+ #: includes/i18n.php:719
1297
+ msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
1298
+ msgstr ""
1299
+
1300
+ #: includes/i18n.php:725
1301
+ msgid "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."
1302
+ msgstr ""
1303
+
1304
+ #: includes/i18n.php:727
1305
+ msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
1306
+ msgstr ""
1307
+
1308
+ #: includes/i18n.php:729
1309
+ msgid "%s is the new owner of the account."
1310
+ msgstr ""
1311
+
1312
+ #: includes/i18n.php:733
1313
+ msgctxt "addonX cannot run without pluginY"
1314
+ msgid "%s cannot run without %s."
1315
+ msgstr ""
1316
+
1317
+ #: includes/i18n.php:735
1318
+ msgctxt "addonX cannot run..."
1319
+ msgid "%s cannot run without the plugin."
1320
+ msgstr ""
1321
+
1322
+ #: includes/i18n.php:737
1323
+ msgctxt "pluginX activation was successfully..."
1324
+ msgid "%s activation was successfully completed."
1325
+ msgstr ""
1326
+
1327
+ #: includes/i18n.php:739
1328
+ msgctxt "Plugin installer section title"
1329
+ msgid "Features & Pricing"
1330
+ msgstr ""
1331
+
1332
+ #: includes/i18n.php:741
1333
+ msgid "Add-on must be deployed to WordPress.org or Freemius."
1334
+ msgstr ""
1335
+
1336
+ #: includes/i18n.php:743
1337
+ msgid "Paid add-on must be deployed to Freemius."
1338
+ msgstr ""
1339
+
1340
+ #: includes/i18n.php:747
1341
+ msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
1342
+ msgstr ""
1343
+
1344
+ #: includes/i18n.php:749
1345
+ msgid "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
1346
+ msgstr ""
1347
+
1348
+ #: includes/i18n.php:755
1349
+ msgctxt "as every month"
1350
+ msgid "Monthly"
1351
+ msgstr ""
1352
+
1353
+ #: includes/i18n.php:757
1354
+ msgctxt "as monthly period"
1355
+ msgid "mo"
1356
+ msgstr ""
1357
+
1358
+ #: includes/i18n.php:759
1359
+ msgctxt "as once a year"
1360
+ msgid "Annual"
1361
+ msgstr ""
1362
+
1363
+ #: includes/i18n.php:761
1364
+ msgctxt "as once a year"
1365
+ msgid "Annually"
1366
+ msgstr ""
1367
+
1368
+ #: includes/i18n.php:763
1369
+ msgctxt "as once a year"
1370
+ msgid "Once"
1371
+ msgstr ""
1372
+
1373
+ #: includes/i18n.php:765
1374
+ msgctxt "as annual period"
1375
+ msgid "year"
1376
+ msgstr ""
1377
+
1378
+ #: includes/i18n.php:767
1379
+ msgid "Lifetime"
1380
+ msgstr ""
1381
+
1382
+ #: includes/i18n.php:769
1383
+ msgctxt "e.g. the best product"
1384
+ msgid "Best"
1385
+ msgstr ""
1386
+
1387
+ #: includes/i18n.php:771
1388
+ msgctxt "e.g. billed monthly"
1389
+ msgid "Billed %s"
1390
+ msgstr ""
1391
+
1392
+ #: includes/i18n.php:773
1393
+ msgctxt "as a discount of $5 or 10%"
1394
+ msgid "Save %s"
1395
+ msgstr ""
1396
+
1397
+ #: includes/i18n.php:777
1398
+ msgid "View details"
1399
+ msgstr ""
freemius/package.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "freemius-wordpress-sdk",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "gulpfile.js",
6
+ "dependencies": {
7
+ "gulp": "^3.9.1",
8
+ "gulp-gettext": "^0.3.0",
9
+ "gulp-pofill": "^1.0.0",
10
+ "gulp-rename": "^1.2.2",
11
+ "gulp-sort": "^2.0.0",
12
+ "gulp-wp-pot": "^1.3.1"
13
+ },
14
+ "scripts": {
15
+ "test": "echo \"Error: no test specified\" && exit 1"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/Freemius/wordpress-sdk.git"
20
+ },
21
+ "author": "Vova Feldman",
22
+ "license": "GPL-2.0",
23
+ "homepage": "https://freemius.com",
24
+ "devDependencies": {
25
+ "gulp": "^3.9.1",
26
+ "gulp-gettext": "^0.3.0",
27
+ "gulp-pofill": "^1.0.0",
28
+ "gulp-rename": "^1.2.2",
29
+ "gulp-sort": "^2.0.0",
30
+ "gulp-wp-pot": "^1.3.1"
31
+ }
32
+ }
freemius/require.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2016, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.1.9
7
+ */
8
+
9
+ // Configuration should be loaded first.
10
+ require_once dirname( __FILE__ ) . '/config.php';
11
+
12
+ // Logger must be loaded before any other.
13
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-logger.php';
14
+ require_once WP_FS__DIR_INCLUDES . '/debug/debug-bar-start.php';
15
+
16
+ require_once WP_FS__DIR_INCLUDES . '/fs-core-functions.php';
17
+ // require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';
18
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';
19
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php';
20
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';
21
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';
22
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-key-value-storage.php';
23
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-license-manager.php';
24
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plan-manager.php';
25
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plugin-manager.php';
26
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-entity.php';
27
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-scope-entity.php';
28
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-user.php';
29
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-site.php';
30
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin.php';
31
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-info.php';
32
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-tag.php';
33
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-plan.php';
34
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-pricing.php';
35
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-payment.php';
36
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-license.php';
37
+ require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-subscription.php';
38
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-api.php';
39
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-plugin-updater.php';
40
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-security.php';
41
+ require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php';
42
+ require_once WP_FS__DIR_INCLUDES . '/sdk/Exceptions/Exception.php';
43
+ require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';
freemius/start.php CHANGED
@@ -1,332 +1,312 @@
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
- $this_sdk_version = '1.1.7.1';
14
-
15
- #region SDK Selection Logic --------------------------------------------------------------------
16
-
17
- /**
18
- * Special logic added on 1.1.6 to make sure that every Freemius powered plugin
19
- * will ALWAYS be loaded with the newest SDK from the active Freemius powered plugins.
20
- *
21
- * Since Freemius SDK is backward compatible, this will make sure that all Freemius powered
22
- * plugins will run correctly.
23
- *
24
- * @since 1.1.6
25
- */
26
-
27
- global $fs_active_plugins;
28
-
29
- $this_sdk_relative_path = plugin_basename( dirname( __FILE__ ) );
30
-
31
- if ( ! isset( $fs_active_plugins ) ) {
32
- // Require SDK essentials.
33
- require_once dirname( __FILE__ ) . '/includes/fs-essential-functions.php';
34
-
35
- // Load all Freemius powered active plugins.
36
- $fs_active_plugins = get_option( 'fs_active_plugins', new stdClass() );
37
-
38
- if ( ! isset( $fs_active_plugins->plugins ) ) {
39
- $fs_active_plugins->plugins = array();
40
- }
41
- }
42
-
43
- if ( ! function_exists( 'fs_find_direct_caller_plugin_file' ) ) {
44
- require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-1.1.7.1.php';
45
- }
46
-
47
- // Update current SDK info based on the SDK path.
48
- if ( ! isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) ||
49
- $this_sdk_version != $fs_active_plugins->plugins[ $this_sdk_relative_path ]->version
50
- ) {
51
- $fs_active_plugins->plugins[ $this_sdk_relative_path ] = (object) array(
52
- 'version' => $this_sdk_version,
53
- 'timestamp' => time(),
54
- 'plugin_path' => plugin_basename( fs_find_direct_caller_plugin_file( __FILE__ ) ),
55
- );
56
- }
57
-
58
- $is_current_sdk_newest = isset( $fs_active_plugins->newest ) && ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path );
59
-
60
- if ( ! isset( $fs_active_plugins->newest ) ) {
61
- /**
62
- * This will be executed only once, for the first time a Freemius powered plugin is activated.
63
- */
64
- fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );
65
-
66
- $is_current_sdk_newest = true;
67
- } else if ( version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '<' ) ) {
68
- /**
69
- * Current SDK is newer than the newest stored SDK.
70
- */
71
- fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );
72
-
73
- if ( class_exists( 'Freemius' ) ) {
74
- // Older SDK version was already loaded.
75
-
76
- if ( ! $fs_active_plugins->newest->in_activation ) {
77
- // Re-order plugins to load this plugin first.
78
- fs_newest_sdk_plugin_first();
79
- }
80
-
81
- // Refresh page.
82
- if ( fs_redirect( $_SERVER['REQUEST_URI'] ) ) {
83
- exit();
84
- }
85
- }
86
- } else {
87
- if ( ! function_exists( 'get_plugins' ) ) {
88
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
89
- }
90
-
91
- $is_newest_sdk_plugin_activate = is_plugin_active( $fs_active_plugins->newest->plugin_path );
92
-
93
- if ( $is_current_sdk_newest &&
94
- ! $is_newest_sdk_plugin_activate &&
95
- ! $fs_active_plugins->newest->in_activation
96
- ) {
97
- // If current SDK is the newest and the plugin is NOT active, it means
98
- // that the current plugin in activation mode.
99
- $fs_active_plugins->newest->in_activation = true;
100
- update_option( 'fs_active_plugins', $fs_active_plugins );
101
- }
102
-
103
- $is_newest_sdk_path_valid = ( $is_newest_sdk_plugin_activate || $fs_active_plugins->newest->in_activation ) && file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this_sdk_relative_path . '/start.php' ) );
104
-
105
- if ( ! $is_newest_sdk_path_valid && ! $is_current_sdk_newest ) {
106
- // Plugin with newest SDK is no longer active, or SDK was moved to a different location.
107
- unset( $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ] );
108
- }
109
-
110
- if ( ! ( $is_newest_sdk_plugin_activate || $fs_active_plugins->newest->in_activation ) ||
111
- ! $is_newest_sdk_path_valid ||
112
- // Is newest SDK downgraded.
113
- ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
114
- version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '>' ) )
115
- ) {
116
- /**
117
- * Plugin with newest SDK is no longer active.
118
- * OR
119
- * The newest SDK was in the current plugin. BUT, seems like the version of
120
- * the SDK was downgraded to a lower SDK.
121
- */
122
- // Find the active plugin with the newest SDK version and update the newest reference.
123
- fs_fallback_to_newest_active_sdk();
124
- } else {
125
- if ( $is_newest_sdk_plugin_activate &&
126
- $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
127
- ( $fs_active_plugins->newest->in_activation ||
128
- ( class_exists( 'Freemius' ) && ( ! defined( 'WP_FS__SDK_VERSION' ) || version_compare( WP_FS__SDK_VERSION, $this_sdk_version, '<' ) ) )
129
- )
130
-
131
- ) {
132
- if ( $fs_active_plugins->newest->in_activation ) {
133
- // Plugin no more in activation.
134
- $fs_active_plugins->newest->in_activation = false;
135
- update_option( 'fs_active_plugins', $fs_active_plugins );
136
- }
137
-
138
- // Reorder plugins to load plugin with newest SDK first.
139
- if ( fs_newest_sdk_plugin_first() ) {
140
- // Refresh page after re-order to make sure activated plugin loads newest SDK.
141
- if ( class_exists( 'Freemius' ) ) {
142
- if ( fs_redirect( $_SERVER['REQUEST_URI'] ) ) {
143
- exit();
144
- }
145
- }
146
- }
147
- }
148
- }
149
- }
150
-
151
- if ( class_exists( 'Freemius' ) ) {
152
- // SDK was already loaded.
153
- return;
154
- }
155
-
156
- if ( version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) {
157
- $newest_sdk_starter = fs_normalize_path( WP_PLUGIN_DIR . '/' . $fs_active_plugins->newest->sdk_path . '/start.php' );
158
-
159
- if ( file_exists( $newest_sdk_starter ) ) {
160
- // Reorder plugins to load plugin with newest SDK first.
161
- fs_newest_sdk_plugin_first();
162
-
163
- // There's a newer SDK version, load it instead of the current one!
164
- require_once $newest_sdk_starter;
165
-
166
- return;
167
- }
168
- }
169
-
170
- #endregion SDK Selection Logic --------------------------------------------------------------------
171
-
172
- #region Hooks & Filters Collection --------------------------------------------------------------------
173
-
174
- /**
175
- * Freemius hooks (actions & filters) tags structure:
176
- *
177
- * fs_{filter/action_name}_{plugin_slug}
178
- *
179
- * --------------------------------------------------------
180
- *
181
- * Usage with WordPress' add_action() / add_filter():
182
- *
183
- * add_action('fs_{filter/action_name}_{plugin_slug}', $callable);
184
- *
185
- * --------------------------------------------------------
186
- *
187
- * Usage with Freemius' instance add_action() / add_filter():
188
- *
189
- * // No need to add 'fs_' prefix nor '_{plugin_slug}' suffix.
190
- * my_freemius()->add_action('{action_name}', $callable);
191
- *
192
- * --------------------------------------------------------
193
- *
194
- * Freemius filters collection:
195
- *
196
- * fs_connect_url_{plugin_slug}
197
- * fs_trial_promotion_message_{plugin_slug}
198
- * fs_is_long_term_user_{plugin_slug}
199
- * fs_uninstall_reasons_{plugin_slug}
200
- * fs_is_plugin_update_{plugin_slug}
201
- * fs_api_domains_{plugin_slug}
202
- * fs_email_template_sections_{plugin_slug}
203
- * fs_support_forum_submenu_{plugin_slug}
204
- * fs_support_forum_url_{plugin_slug}
205
- * fs_connect_message_{plugin_slug}
206
- * fs_connect_message_on_update_{plugin_slug}
207
- * fs_uninstall_confirmation_message_{plugin_slug}
208
- * fs_pending_activation_message_{plugin_slug}
209
- * fs_is_submenu_visible_{plugin_slug}
210
- *
211
- * --------------------------------------------------------
212
- *
213
- * Freemius actions collection:
214
- *
215
- * fs_after_license_loaded_{plugin_slug}
216
- * fs_after_license_change_{plugin_slug}
217
- * fs_after_plans_sync_{plugin_slug}
218
- *
219
- * fs_after_account_details_{plugin_slug}
220
- * fs_after_account_user_sync_{plugin_slug}
221
- * fs_after_account_plan_sync_{plugin_slug}
222
- * fs_before_account_load_{plugin_slug}
223
- * fs_after_account_connection_{plugin_slug}
224
- * fs_account_property_edit_{plugin_slug}
225
- * fs_account_email_verified_{plugin_slug}
226
- * fs_account_page_load_before_departure_{plugin_slug}
227
- * fs_before_account_delete_{plugin_slug}
228
- * fs_after_account_delete_{plugin_slug}
229
- *
230
- * fs_sdk_version_update_{plugin_slug}
231
- * fs_plugin_version_update_{plugin_slug}
232
- *
233
- * fs_initiated_{plugin_slug}
234
- * fs_after_init_plugin_registered_{plugin_slug}
235
- * fs_after_init_plugin_anonymous_{plugin_slug}
236
- * fs_after_init_plugin_pending_activations_{plugin_slug}
237
- * fs_after_init_addon_registered_{plugin_slug}
238
- * fs_after_init_addon_anonymous_{plugin_slug}
239
- * fs_after_init_addon_pending_activations_{plugin_slug}
240
- *
241
- * fs_after_premium_version_activation_{plugin_slug}
242
- * fs_after_free_version_reactivation_{plugin_slug}
243
- *
244
- * fs_after_uninstall_{plugin_slug}
245
- * fs_before_admin_menu_init_{plugin_slug}
246
- */
247
-
248
- #endregion Hooks & Filters Collection --------------------------------------------------------------------
249
-
250
- if ( ! class_exists( 'Freemius' ) ) {
251
-
252
- if ( ! defined( 'WP_FS__SDK_VERSION' ) ) {
253
- define( 'WP_FS__SDK_VERSION', $this_sdk_version );
254
- }
255
-
256
- // Configuration should be loaded first.
257
- require_once dirname( __FILE__ ) . '/config.php';
258
-
259
- // Logger must be loaded before any other.
260
- require_once WP_FS__DIR_INCLUDES . '/class-fs-logger.php';
261
-
262
- require_once WP_FS__DIR_INCLUDES . '/fs-core-functions.php';
263
- // require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';
264
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';
265
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php';
266
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';
267
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';
268
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-key-value-storage.php';
269
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-license-manager.php';
270
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plan-manager.php';
271
- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plugin-manager.php';
272
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-entity.php';
273
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-scope-entity.php';
274
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-user.php';
275
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-site.php';
276
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin.php';
277
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-info.php';
278
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-tag.php';
279
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-plan.php';
280
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-license.php';
281
- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-subscription.php';
282
- require_once WP_FS__DIR_INCLUDES . '/class-fs-api.php';
283
- require_once WP_FS__DIR_INCLUDES . '/class-fs-plugin-updater.php';
284
- require_once WP_FS__DIR_INCLUDES . '/class-fs-security.php';
285
- require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php';
286
- require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';
287
-
288
- /**
289
- * Quick shortcut to get Freemius for specified plugin.
290
- * Used by various templates.
291
- *
292
- * @param string $slug
293
- *
294
- * @return Freemius
295
- */
296
- function freemius( $slug ) {
297
- return Freemius::instance( $slug );
298
- }
299
-
300
- /**
301
- * @param string $slug
302
- * @param number $plugin_id
303
- * @param string $public_key
304
- * @param bool $is_live Is live or test plugin.
305
- * @param bool $is_premium Hints freemius if running the premium plugin or not.
306
- *
307
- * @return Freemius
308
- */
309
- function fs_init( $slug, $plugin_id, $public_key, $is_live = true, $is_premium = true ) {
310
- $fs = Freemius::instance( $slug );
311
- $fs->init( $plugin_id, $public_key, $is_live, $is_premium );
312
-
313
- return $fs;
314
- }
315
-
316
- /**
317
- * @param array [string]string $plugin
318
- *
319
- * @return Freemius
320
- * @throws Freemius_Exception
321
- */
322
- function fs_dynamic_init( $plugin ) {
323
- $fs = Freemius::instance( $plugin['slug'] );
324
- $fs->dynamic_init( $plugin );
325
-
326
- return $fs;
327
- }
328
-
329
- function fs_dump_log() {
330
- FS_Logger::dump();
331
- }
332
  }
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 SDK Version.
15
+ *
16
+ * @var string
17
+ */
18
+ $this_sdk_version = '1.2.1';
19
+
20
+ #region SDK Selection Logic --------------------------------------------------------------------
21
+
22
+ /**
23
+ * Special logic added on 1.1.6 to make sure that every Freemius powered plugin
24
+ * will ALWAYS be loaded with the newest SDK from the active Freemius powered plugins.
25
+ *
26
+ * Since Freemius SDK is backward compatible, this will make sure that all Freemius powered
27
+ * plugins will run correctly.
28
+ *
29
+ * @since 1.1.6
30
+ */
31
+
32
+ global $fs_active_plugins;
33
+
34
+ $this_sdk_relative_path = plugin_basename( dirname( __FILE__ ) );
35
+
36
+ if ( ! isset( $fs_active_plugins ) ) {
37
+ // Require SDK essentials.
38
+ require_once dirname( __FILE__ ) . '/includes/fs-essential-functions.php';
39
+
40
+ // Load all Freemius powered active plugins.
41
+ $fs_active_plugins = get_option( 'fs_active_plugins', new stdClass() );
42
+
43
+ if ( ! isset( $fs_active_plugins->plugins ) ) {
44
+ $fs_active_plugins->plugins = array();
45
+ }
46
+ }
47
+
48
+ if ( ! function_exists( 'fs_find_direct_caller_plugin_file' ) ) {
49
+ require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-1.1.7.1.php';
50
+ }
51
+
52
+ // Update current SDK info based on the SDK path.
53
+ if ( ! isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) ||
54
+ $this_sdk_version != $fs_active_plugins->plugins[ $this_sdk_relative_path ]->version
55
+ ) {
56
+ $fs_active_plugins->plugins[ $this_sdk_relative_path ] = (object) array(
57
+ 'version' => $this_sdk_version,
58
+ 'timestamp' => time(),
59
+ 'plugin_path' => plugin_basename( fs_find_direct_caller_plugin_file( __FILE__ ) ),
60
+ );
61
+ }
62
+
63
+ $is_current_sdk_newest = isset( $fs_active_plugins->newest ) && ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path );
64
+
65
+ if ( ! isset( $fs_active_plugins->newest ) ) {
66
+ /**
67
+ * This will be executed only once, for the first time a Freemius powered plugin is activated.
68
+ */
69
+ fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );
70
+
71
+ $is_current_sdk_newest = true;
72
+ } else if ( version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '<' ) ) {
73
+ /**
74
+ * Current SDK is newer than the newest stored SDK.
75
+ */
76
+ fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );
77
+
78
+ if ( class_exists( 'Freemius' ) ) {
79
+ // Older SDK version was already loaded.
80
+
81
+ if ( ! $fs_active_plugins->newest->in_activation ) {
82
+ // Re-order plugins to load this plugin first.
83
+ fs_newest_sdk_plugin_first();
84
+ }
85
+
86
+ // Refresh page.
87
+ if ( fs_redirect( $_SERVER['REQUEST_URI'] ) ) {
88
+ exit();
89
+ }
90
+ }
91
+ } else {
92
+ if ( ! function_exists( 'get_plugins' ) ) {
93
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
94
+ }
95
+
96
+ $is_newest_sdk_plugin_activate = is_plugin_active( $fs_active_plugins->newest->plugin_path );
97
+
98
+ if ( $is_current_sdk_newest &&
99
+ ! $is_newest_sdk_plugin_activate &&
100
+ ! $fs_active_plugins->newest->in_activation
101
+ ) {
102
+ // If current SDK is the newest and the plugin is NOT active, it means
103
+ // that the current plugin in activation mode.
104
+ $fs_active_plugins->newest->in_activation = true;
105
+ update_option( 'fs_active_plugins', $fs_active_plugins );
106
+ }
107
+
108
+ $is_newest_sdk_path_valid = ( $is_newest_sdk_plugin_activate || $fs_active_plugins->newest->in_activation ) && file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this_sdk_relative_path . '/start.php' ) );
109
+
110
+ if ( ! $is_newest_sdk_path_valid && ! $is_current_sdk_newest ) {
111
+ // Plugin with newest SDK is no longer active, or SDK was moved to a different location.
112
+ unset( $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ] );
113
+ }
114
+
115
+ if ( ! ( $is_newest_sdk_plugin_activate || $fs_active_plugins->newest->in_activation ) ||
116
+ ! $is_newest_sdk_path_valid ||
117
+ // Is newest SDK downgraded.
118
+ ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
119
+ version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '>' ) )
120
+ ) {
121
+ /**
122
+ * Plugin with newest SDK is no longer active.
123
+ * OR
124
+ * The newest SDK was in the current plugin. BUT, seems like the version of
125
+ * the SDK was downgraded to a lower SDK.
126
+ */
127
+ // Find the active plugin with the newest SDK version and update the newest reference.
128
+ fs_fallback_to_newest_active_sdk();
129
+ } else {
130
+ if ( $is_newest_sdk_plugin_activate &&
131
+ $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
132
+ ( $fs_active_plugins->newest->in_activation ||
133
+ ( class_exists( 'Freemius' ) && ( ! defined( 'WP_FS__SDK_VERSION' ) || version_compare( WP_FS__SDK_VERSION, $this_sdk_version, '<' ) ) )
134
+ )
135
+
136
+ ) {
137
+ if ( $fs_active_plugins->newest->in_activation ) {
138
+ // Plugin no more in activation.
139
+ $fs_active_plugins->newest->in_activation = false;
140
+ update_option( 'fs_active_plugins', $fs_active_plugins );
141
+ }
142
+
143
+ // Reorder plugins to load plugin with newest SDK first.
144
+ if ( fs_newest_sdk_plugin_first() ) {
145
+ // Refresh page after re-order to make sure activated plugin loads newest SDK.
146
+ if ( class_exists( 'Freemius' ) ) {
147
+ if ( fs_redirect( $_SERVER['REQUEST_URI'] ) ) {
148
+ exit();
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ if ( class_exists( 'Freemius' ) ) {
157
+ // SDK was already loaded.
158
+ return;
159
+ }
160
+
161
+ if ( version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) {
162
+ $newest_sdk_starter = fs_normalize_path( WP_PLUGIN_DIR . '/' . $fs_active_plugins->newest->sdk_path . '/start.php' );
163
+
164
+ if ( file_exists( $newest_sdk_starter ) ) {
165
+ // Reorder plugins to load plugin with newest SDK first.
166
+ fs_newest_sdk_plugin_first();
167
+
168
+ // There's a newer SDK version, load it instead of the current one!
169
+ require_once $newest_sdk_starter;
170
+
171
+ return;
172
+ }
173
+ }
174
+
175
+ #endregion SDK Selection Logic --------------------------------------------------------------------
176
+
177
+ #region Hooks & Filters Collection --------------------------------------------------------------------
178
+
179
+ /**
180
+ * Freemius hooks (actions & filters) tags structure:
181
+ *
182
+ * fs_{filter/action_name}_{plugin_slug}
183
+ *
184
+ * --------------------------------------------------------
185
+ *
186
+ * Usage with WordPress' add_action() / add_filter():
187
+ *
188
+ * add_action('fs_{filter/action_name}_{plugin_slug}', $callable);
189
+ *
190
+ * --------------------------------------------------------
191
+ *
192
+ * Usage with Freemius' instance add_action() / add_filter():
193
+ *
194
+ * // No need to add 'fs_' prefix nor '_{plugin_slug}' suffix.
195
+ * my_freemius()->add_action('{action_name}', $callable);
196
+ *
197
+ * --------------------------------------------------------
198
+ *
199
+ * Freemius filters collection:
200
+ *
201
+ * fs_connect_url_{plugin_slug}
202
+ * fs_trial_promotion_message_{plugin_slug}
203
+ * fs_is_long_term_user_{plugin_slug}
204
+ * fs_uninstall_reasons_{plugin_slug}
205
+ * fs_is_plugin_update_{plugin_slug}
206
+ * fs_api_domains_{plugin_slug}
207
+ * fs_email_template_sections_{plugin_slug}
208
+ * fs_support_forum_submenu_{plugin_slug}
209
+ * fs_support_forum_url_{plugin_slug}
210
+ * fs_connect_message_{plugin_slug}
211
+ * fs_connect_message_on_update_{plugin_slug}
212
+ * fs_uninstall_confirmation_message_{plugin_slug}
213
+ * fs_pending_activation_message_{plugin_slug}
214
+ * fs_is_submenu_visible_{plugin_slug}
215
+ * fs_plugin_icon_{plugin_slug}
216
+ * fs_show_trial_{plugin_slug}
217
+ *
218
+ * --------------------------------------------------------
219
+ *
220
+ * Freemius actions collection:
221
+ *
222
+ * fs_after_license_loaded_{plugin_slug}
223
+ * fs_after_license_change_{plugin_slug}
224
+ * fs_after_plans_sync_{plugin_slug}
225
+ *
226
+ * fs_after_account_details_{plugin_slug}
227
+ * fs_after_account_user_sync_{plugin_slug}
228
+ * fs_after_account_plan_sync_{plugin_slug}
229
+ * fs_before_account_load_{plugin_slug}
230
+ * fs_after_account_connection_{plugin_slug}
231
+ * fs_account_property_edit_{plugin_slug}
232
+ * fs_account_email_verified_{plugin_slug}
233
+ * fs_account_page_load_before_departure_{plugin_slug}
234
+ * fs_before_account_delete_{plugin_slug}
235
+ * fs_after_account_delete_{plugin_slug}
236
+ *
237
+ * fs_sdk_version_update_{plugin_slug}
238
+ * fs_plugin_version_update_{plugin_slug}
239
+ *
240
+ * fs_initiated_{plugin_slug}
241
+ * fs_after_init_plugin_registered_{plugin_slug}
242
+ * fs_after_init_plugin_anonymous_{plugin_slug}
243
+ * fs_after_init_plugin_pending_activations_{plugin_slug}
244
+ * fs_after_init_addon_registered_{plugin_slug}
245
+ * fs_after_init_addon_anonymous_{plugin_slug}
246
+ * fs_after_init_addon_pending_activations_{plugin_slug}
247
+ *
248
+ * fs_after_premium_version_activation_{plugin_slug}
249
+ * fs_after_free_version_reactivation_{plugin_slug}
250
+ *
251
+ * fs_after_uninstall_{plugin_slug}
252
+ * fs_before_admin_menu_init_{plugin_slug}
253
+ */
254
+
255
+ #endregion Hooks & Filters Collection --------------------------------------------------------------------
256
+
257
+ if ( ! class_exists( 'Freemius' ) ) {
258
+
259
+ if ( ! defined( 'WP_FS__SDK_VERSION' ) ) {
260
+ define( 'WP_FS__SDK_VERSION', $this_sdk_version );
261
+ }
262
+
263
+ // Load SDK files.
264
+ require_once dirname( __FILE__ ) . '/require.php';
265
+
266
+ /**
267
+ * Quick shortcut to get Freemius for specified plugin.
268
+ * Used by various templates.
269
+ *
270
+ * @param string $slug
271
+ *
272
+ * @return Freemius
273
+ */
274
+ function freemius( $slug ) {
275
+ return Freemius::instance( $slug );
276
+ }
277
+
278
+ /**
279
+ * @param string $slug
280
+ * @param number $plugin_id
281
+ * @param string $public_key
282
+ * @param bool $is_live Is live or test plugin.
283
+ * @param bool $is_premium Hints freemius if running the premium plugin or not.
284
+ *
285
+ * @return Freemius
286
+ *
287
+ * @deprecated Please use fs_dynamic_init().
288
+ */
289
+ function fs_init( $slug, $plugin_id, $public_key, $is_live = true, $is_premium = true ) {
290
+ $fs = Freemius::instance( $slug, true );
291
+ $fs->init( $plugin_id, $public_key, $is_live, $is_premium );
292
+
293
+ return $fs;
294
+ }
295
+
296
+ /**
297
+ * @param array<string,string> $module Plugin or Theme details.
298
+ *
299
+ * @return Freemius
300
+ * @throws Freemius_Exception
301
+ */
302
+ function fs_dynamic_init( $module ) {
303
+ $fs = Freemius::instance( $module['slug'], true );
304
+ $fs->dynamic_init( $module );
305
+
306
+ return $fs;
307
+ }
308
+
309
+ function fs_dump_log() {
310
+ FS_Logger::dump();
311
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  }
freemius/templates/account.php CHANGED
@@ -10,6 +10,9 @@
10
  exit;
11
  }
12
 
 
 
 
13
  $slug = $VARS['slug'];
14
  /**
15
  * @var Freemius $fs
@@ -19,7 +22,7 @@
19
  /**
20
  * @var FS_Plugin_Tag $update
21
  */
22
- $update = $fs->get_update();
23
 
24
  $is_paying = $fs->is_paying();
25
  $user = $fs->get_user();
@@ -29,21 +32,31 @@
29
  $subscription = $fs->_get_subscription();
30
  $plan = $fs->get_plan();
31
  $is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
32
- ?>
 
33
 
 
 
 
 
34
  <div class="wrap">
35
  <h2 class="nav-tab-wrapper">
36
- <a href="<?php $fs->get_account_url() ?>" class="nav-tab nav-tab-active"><?php _efs( 'account', $slug ) ?></a>
37
- <?php if ( $fs->_has_addons() ) : ?>
 
38
  <a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>"
39
  class="nav-tab"><?php _efs( 'add-ons', $slug ) ?></a>
40
  <?php endif ?>
41
- <?php if ( $fs->is_not_paying() && $fs->has_paid_plan() ) : ?>
42
  <a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php _efs( 'upgrade', $slug ) ?></a>
43
- <?php if ( ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
44
  <a href="<?php echo $fs->get_trial_url() ?>" class="nav-tab"><?php _efs( 'free-trial', $slug ) ?></a>
45
  <?php endif ?>
46
  <?php endif ?>
 
 
 
 
47
  </h2>
48
 
49
  <div id="poststuff">
@@ -65,15 +78,8 @@
65
  } else {
66
  _efs( 'delete-account-confirm', $slug );
67
  }
68
- ?>')) this.parentNode.submit(); return false;"><i class="dashicons dashicons-no"></i> <?php _efs( 'delete-account', $slug ) ?></a>
69
- </form>
70
- </li>
71
- <li>
72
- &nbsp;•&nbsp;
73
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
74
- <input type="hidden" name="fs_action" value="<?php echo $slug ?>_sync_license">
75
- <?php wp_nonce_field( $slug . '_sync_license' ) ?>
76
- <a href="#" onclick="this.parentNode.submit(); return false;"><i class="dashicons dashicons-image-rotate"></i> <?php _efs( 'sync', $slug ) ?></a>
77
  </form>
78
  </li>
79
  <?php if ( $is_paying ) : ?>
@@ -83,7 +89,9 @@
83
  <input type="hidden" name="fs_action" value="deactivate_license">
84
  <?php wp_nonce_field( 'deactivate_license' ) ?>
85
  <a href="#"
86
- onclick="if (confirm('<?php _efs( 'deactivate-license-confirm', $slug ) ?>')) this.parentNode.submit(); return false;"><i class="dashicons dashicons-admin-network"></i> <?php _efs( 'deactivate-license', $slug ) ?></a>
 
 
87
  </form>
88
  </li>
89
  <?php if ( ! $license->is_lifetime() &&
@@ -99,200 +107,292 @@
99
  printf( __fs( 'after-downgrade-non-blocking', $slug ), $plan->title );
100
  } else {
101
  printf( __fs( 'after-downgrade-blocking', $slug ), $plan->title );
102
- }?> <?php _efs( 'proceed-confirmation', $slug ) ?>')) this.parentNode.submit(); return false;"><i class="dashicons dashicons-download"></i> <?php _efs( 'downgrade', $slug ) ?></a>
 
103
  </form>
104
  </li>
105
  <?php endif ?>
106
  <li>
107
  &nbsp;•&nbsp;
108
- <a href="<?php echo $fs->get_upgrade_url() ?>"><i class="dashicons dashicons-grid-view"></i> <?php _efs( 'change-plan', $slug ) ?></a>
 
 
 
 
 
 
 
 
 
 
 
 
109
  </li>
110
  <?php endif ?>
 
 
 
 
 
 
 
 
 
 
111
  </ul>
112
  </div>
113
  <div class="inside">
114
- <table id="fs_account_details" cellspacing="0" class="fs-key-value-table">
115
- <?php
116
- $profile = array();
117
- $profile[] = array(
118
- 'id' => 'user_name',
119
- 'title' => __fs( 'name', $slug ),
120
- 'value' => $name
121
- );
122
- // if (isset($user->email) && false !== strpos($user->email, '@'))
123
- $profile[] = array(
124
- 'id' => 'email',
125
- 'title' => __fs( 'email', $slug ),
126
- 'value' => $user->email
127
- );
128
- if ( is_numeric( $user->id ) ) {
129
- $profile[] = array(
130
- 'id' => 'user_id',
131
- 'title' => __fs( 'user-id', $slug ),
132
- 'value' => $user->id
133
- );
134
- }
135
 
136
- $profile[] = array(
137
- 'id' => 'site_id',
138
- 'title' => __fs( 'site-id', $slug ),
139
- 'value' => is_string( $site->id ) ?
140
- $site->id :
141
- __fs( 'no-id', $slug )
142
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
  $profile[] = array(
145
- 'id' => 'site_public_key',
146
- 'title' => __fs( 'public-key', $slug ),
147
- 'value' => $site->public_key
 
 
148
  );
149
-
150
  $profile[] = array(
151
- 'id' => 'site_secret_key',
152
- 'title' => __fs( 'secret-key', $slug ),
153
- 'value' => ( ( is_string( $site->secret_key ) ) ?
154
- $site->secret_key :
155
- __fs( 'no-secret', $slug )
156
- )
157
  );
158
 
159
- if ( $fs->is_trial() ) {
160
- $trial_plan = $fs->get_trial_plan();
161
-
162
- $profile[] = array(
163
- 'id' => 'plan',
164
- 'title' => __fs( 'plan', $slug ),
165
- 'value' => ( is_string( $trial_plan->name ) ?
166
- strtoupper( $trial_plan->title ) . ' ' :
167
- '' ) . strtoupper( __fs( 'trial', $slug ) )
168
- );
169
- } else {
170
  $profile[] = array(
171
- 'id' => 'plan',
172
- 'title' => __fs( 'plan', $slug ),
173
- 'value' => is_string( $site->plan->name ) ?
174
- strtoupper( $site->plan->title ) :
175
- strtoupper( __fs( 'free', $slug ) )
176
  );
177
  }
178
-
179
- $profile[] = array(
180
- 'id' => 'version',
181
- 'title' => __fs( 'version', $slug ),
182
- 'value' => $fs->get_plugin_version()
183
- );
 
 
 
 
 
184
  ?>
185
- <?php $odd = true;
186
- foreach ( $profile as $p ) : ?>
187
- <?php
188
- if ( 'plan' === $p['id'] && ! $fs->has_paid_plan() ) {
189
- // If plugin don't have any paid plans, there's no reason
190
- // to show current plan.
191
- continue;
192
- }
193
- ?>
194
- <tr class="fs-field-<?php echo $p['id'] ?><?php if ( $odd ) : ?> alternate<?php endif ?>">
195
- <td>
196
- <nobr><?php echo $p['title'] ?>:</nobr>
197
- </td>
198
- <td>
199
- <code><?php echo htmlspecialchars( $p['value'] ) ?></code>
200
- <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
201
- <label><?php _efs( 'not-verified', $slug ) ?></label>
202
- <?php endif ?>
203
- <?php if ( 'plan' === $p['id'] ) : ?>
204
- <?php if ( $fs->is_trial() ) : ?>
205
- <label><?php printf( __fs( 'expires-in', $slug ), human_time_diff( time(), strtotime( $site->trial_ends ) ) ) ?></label>
206
- <?php elseif ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
207
- <?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
208
- <label><?php printf( __fs( 'expires-in', $slug ), human_time_diff( time(), strtotime( $license->expiration ) ) ) ?></label>
209
- <?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
210
- <label><?php printf( __fs( 'renews-in', $slug ), human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ?></label>
211
- <?php endif ?>
212
- <?php endif ?>
213
- <?php endif ?>
214
-
215
- </td>
216
- <td class="fs-right">
217
- <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
218
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
219
- <input type="hidden" name="fs_action" value="verify_email">
220
- <?php wp_nonce_field( 'verify_email' ) ?>
221
- <input type="submit" class="button button-small"
222
- value="<?php _efs( 'verify-email', $slug ) ?>">
223
- </form>
224
  <?php endif ?>
225
- <?php if ( 'plan' === $p['id'] ) : ?>
226
- <div class="button-group">
227
- <?php $license = $fs->is_not_paying() ? $fs->_get_available_premium_license() : false ?>
228
- <?php if ( false !== $license && ( $license->left() > 0 || ( $site->is_localhost() && $license->is_free_localhost ) ) ) : ?>
229
- <?php $premium_plan = $fs->_get_plan_by_id( $license->plan_id ) ?>
230
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
231
- method="POST">
232
- <input type="hidden" name="fs_action" value="activate_license">
233
- <?php wp_nonce_field( 'activate_license' ) ?>
234
- <input type="submit" class="button button-primary"
235
- value="<?php printf(
236
- __fs( 'activate-x-plan', $slug ),
237
- $premium_plan->title,
238
- ( $site->is_localhost() && $license->is_free_localhost ) ?
239
- '[' . __fs( 'localhost', $slug ) . ']' :
240
- ( 1 < $license->left() ? $license->left() . ' left' : '' )
241
- ) ?> ">
242
- </form>
243
- <?php else : ?>
244
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
245
- method="POST" class="button-group">
246
- <input type="submit" class="button"
247
- value="<?php _efs( 'sync-license', $slug ) ?>">
248
- <input type="hidden" name="fs_action"
249
- value="<?php echo $slug ?>_sync_license">
250
- <?php wp_nonce_field( $slug . '_sync_license' ) ?>
251
- <a href="<?php echo $fs->get_upgrade_url() ?>"
252
- class="button<?php if ( ! $is_paying ) {
253
- echo ' button-primary';
254
- } ?> button-upgrade"><?php ( ! $is_paying ) ?
255
- _efs( 'upgrade', $slug ) :
256
- _efs( 'change-plan', $slug )
257
- ?></a>
258
- </form>
259
- <?php endif ?>
260
- </div>
261
- <?php elseif ( 'version' === $p['id'] ) : ?>
262
- <div class="button-group">
263
- <?php if ( $is_paying || $fs->is_trial() ) : ?>
264
- <?php if ( ! $fs->is_allowed_to_install() ) : ?>
265
- <a target="_blank" class="button button-primary"
266
- href="<?php echo $fs->_get_latest_download_local_url() ?>"><?php echo sprintf( __fs( 'download-x-version', $slug ), $site->plan->title ) . ( is_object( $update ) ? ' [' . $update->version . ']' : '' ) ?></a>
267
- <?php elseif ( is_object( $update ) ) : ?>
268
- <a class="button button-primary"
269
- 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', $slug ) . ' [' . $update->version . ']' ?></a>
270
  <?php endif ?>
271
- <?php endif; ?>
272
- </div>
273
- <?php
274
- elseif (/*in_array($p['id'], array('site_secret_key', 'site_id', 'site_public_key')) ||*/
275
- ( is_string( $user->secret_key ) && in_array( $p['id'], array(
276
- 'email',
277
- 'user_name'
278
- ) ) )
279
- ) : ?>
280
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"
281
- onsubmit="var val = prompt('<?php printf( __fs( 'what-is-your-x', $slug ), $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;">
282
- <input type="hidden" name="fs_action" value="update_<?php echo $p['id'] ?>">
283
- <input type="hidden" name="fs_<?php echo $p['id'] ?>_<?php echo $slug ?>"
284
- value="">
285
- <?php wp_nonce_field( 'update_' . $p['id'] ) ?>
286
- <input type="submit" class="button button-small"
287
- value="<?php _ex( 'Edit', 'verb', 'freemius' ) ?>">
288
- </form>
289
- <?php endif ?>
290
- </td>
291
- </tr>
292
- <?php $odd = ! $odd; endforeach ?>
293
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  </div>
295
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  <?php
297
  $account_addons = $fs->get_account_addons();
298
  if ( ! is_array( $account_addons ) ) {
@@ -308,141 +408,269 @@
308
  $addons_to_show = array_unique( array_merge( $installed_addons_ids, $account_addons ) );
309
  ?>
310
  <?php if ( 0 < count( $addons_to_show ) ) : ?>
 
311
  <div class="postbox">
312
- <table id="fs_addons" class="widefat">
313
- <thead>
314
- <tr>
315
- <th></th>
316
- <th><?php _efs( 'version', $slug ) ?></th>
317
- <th><?php _efs( 'plan', $slug ) ?></th>
318
- <th><?php _efs( 'expiration', $slug ) ?></th>
319
- <th></th>
320
- <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
321
- <th></th>
322
- <?php endif ?>
323
- </tr>
324
- </thead>
325
- <tbody>
326
- <?php foreach ( $addons_to_show as $addon_id ) : ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  <?php
328
- $addon = $fs->get_addon( $addon_id );
329
- $is_addon_activated = $fs->is_addon_activated( $addon->slug );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
- $fs_addon = $is_addon_activated ? freemius( $addon->slug ) : false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  ?>
333
- <tr>
334
- <td>
335
- <?php echo $addon->title ?>
336
- </td>
337
- <?php if ( $is_addon_activated ) : ?>
338
- <?php // Add-on Installed ?>
339
- <?php $addon_site = $fs_addon->get_site(); ?>
340
- <td><?php echo $fs_addon->get_plugin_version() ?></td>
341
- <td><?php echo is_string( $addon_site->plan->name ) ? strtoupper( $addon_site->plan->title ) : 'FREE' ?></td>
342
- <?php
343
- $current_license = $fs_addon->_get_license();
344
- $is_current_license_expired = is_object( $current_license ) && $current_license->is_expired();
345
- ?>
346
- <?php if ( $fs_addon->is_not_paying() ) : ?>
347
- <?php if ( $is_current_license_expired ) : ?>
348
- <td><?php _efs( 'expired', $slug ) ?></td>
349
- <?php endif ?>
350
- <?php $premium_license = $fs_addon->_get_available_premium_license() ?>
351
- <td<?php if ( ! $is_current_license_expired ) {
352
- echo ' colspan="2"';
353
- } ?>>
354
- <?php if ( is_object( $premium_license ) && ! $premium_license->is_utilized() ) : ?>
355
- <?php $site = $fs_addon->get_site() ?>
356
- <?php fs_ui_action_button(
357
- $slug, 'account',
358
- 'activate_license',
359
- sprintf( __fs( 'activate-x-plan', $slug ), $fs_addon->get_plan_title(), ( $site->is_localhost() && $premium_license->is_free_localhost ) ? '[localhost]' : ( 1 < $premium_license->left() ? $premium_license->left() . ' left' : '' ) ),
360
- array( 'plugin_id' => $addon_id )
361
- ) ?>
362
- <?php else : ?>
363
- <div class="button-group">
364
- <?php fs_ui_action_button(
365
- $slug, 'account',
366
- $slug . '_sync_license',
367
- __fs( 'sync-license', $slug ),
368
- array( 'plugin_id' => $addon_id ),
369
- false
370
- ) ?>
371
- <?php echo sprintf( '<a href="%s" class="thickbox button button-primary" aria-label="%s" data-title="%s">%s</a>',
372
- esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
373
- '&TB_iframe=true&width=600&height=550' ) ),
374
- esc_attr( sprintf( __fs( 'more-information-about-x', $slug ), $addon->title ) ),
375
- esc_attr( $addon->title ),
376
- __fs( 'upgrade', $slug )
377
- ) ?>
378
- </div>
379
- <?php endif ?>
380
- </td>
381
- <?php else : ?>
382
- <?php if ( is_object( $current_license ) ) : ?>
383
- <td><?php
384
- if ( $current_license->is_lifetime() ) {
385
- _efs( 'no-expiration', $slug );
386
- } else if ( $current_license->is_expired() ) {
387
- _efs( 'expired', $slug );
388
- } else {
389
- echo sprintf(
390
- __fs( 'in-x', $slug ),
391
- human_time_diff( time(), strtotime( $current_license->expiration ) )
392
- );
393
- }
394
- ?></td>
395
- <td>
396
- <?php fs_ui_action_button(
397
- $slug, 'account',
398
- 'deactivate_license',
399
- __fs( 'deactivate-license', $slug ),
400
- array( 'plugin_id' => $addon_id ),
401
- false
402
- ) ?>
403
- </td>
404
- <?php endif ?>
405
  <?php endif ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  <?php else : ?>
407
- <?php // Add-on NOT Installed
408
- ?>
409
- <td colspan="4">
410
- <?php if ( $fs->is_addon_installed( $addon->slug ) ) : ?>
411
- <?php $addon_file = $fs->get_addon_basename( $addon->slug ) ?>
412
- <a class="button button-primary"
413
- href="<?php echo wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $addon_file, 'activate-plugin_' . $addon_file ) ?>"
414
- title="<?php esc_attr( __fs( 'activate-this-addon', $slug ) ) ?>"
415
- class="edit"><?php _efs( 'activate', $slug ) ?></a>
416
- <?php else : ?>
417
- <?php if ( $fs->is_allowed_to_install() ) : ?>
418
- <a class="button button-primary"
419
- 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', $slug ) ?></a>
420
- <?php else : ?>
421
- <a target="_blank" class="button button-primary"
422
- href="<?php echo $fs->_get_latest_download_local_url( $addon_id ) ?>"><?php _efs( 'download-latest', $slug ) ?></a>
423
- <?php endif ?>
424
- <?php endif ?>
425
- </td>
426
- <?php endif ?>
427
- <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
428
- <td>
429
- <?php
430
- if ( $is_addon_activated ) {
431
- fs_ui_action_button(
432
- $slug, 'account',
433
- 'delete_account',
434
- __fs( 'delete', $slug ),
435
- array( 'plugin_id' => $addon_id ),
436
- false
437
- );
438
- }
439
- ?>
440
- </td>
441
  <?php endif ?>
442
- </tr>
443
- <?php endforeach ?>
444
- </tbody>
445
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  </div>
447
  <?php endif ?>
448
 
@@ -452,4 +680,12 @@
452
  </div>
453
  </div>
454
  </div>
455
- <?php fs_require_template( 'powered-by.php' ) ?>
 
 
 
 
 
 
 
 
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @var array $VARS
15
+ */
16
  $slug = $VARS['slug'];
17
  /**
18
  * @var Freemius $fs
22
  /**
23
  * @var FS_Plugin_Tag $update
24
  */
25
+ $update = $fs->get_update( false, false );
26
 
27
  $is_paying = $fs->is_paying();
28
  $user = $fs->get_user();
32
  $subscription = $fs->_get_subscription();
33
  $plan = $fs->get_plan();
34
  $is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
35
+ $is_paid_trial = $fs->is_paid_trial();
36
+ $show_upgrade = ( $fs->has_paid_plan() && ! $is_paying && ! $is_paid_trial );
37
 
38
+ if ( $show_upgrade ) {
39
+ $fs->_require_license_activation_dialog();
40
+ }
41
+ ?>
42
  <div class="wrap">
43
  <h2 class="nav-tab-wrapper">
44
+ <a href="<?php echo $fs->get_account_url() ?>"
45
+ class="nav-tab nav-tab-active"><?php _efs( 'account', $slug ) ?></a>
46
+ <?php if ( $fs->has_addons() ) : ?>
47
  <a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>"
48
  class="nav-tab"><?php _efs( 'add-ons', $slug ) ?></a>
49
  <?php endif ?>
50
+ <?php if ( $show_upgrade ) : ?>
51
  <a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php _efs( 'upgrade', $slug ) ?></a>
52
+ <?php if ( $fs->apply_filters( 'show_trial', true ) && ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
53
  <a href="<?php echo $fs->get_trial_url() ?>" class="nav-tab"><?php _efs( 'free-trial', $slug ) ?></a>
54
  <?php endif ?>
55
  <?php endif ?>
56
+ <?php if ( ! $plan->is_free() ) : ?>
57
+ <a href="<?php echo $fs->get_account_tab_url( 'billing' ) ?>"
58
+ class="nav-tab"><?php _efs( 'billing', $slug ) ?></a>
59
+ <?php endif ?>
60
  </h2>
61
 
62
  <div id="poststuff">
78
  } else {
79
  _efs( 'delete-account-confirm', $slug );
80
  }
81
+ ?>')) this.parentNode.submit(); return false;"><i
82
+ class="dashicons dashicons-no"></i> <?php _efs( 'delete-account', $slug ) ?></a>
 
 
 
 
 
 
 
83
  </form>
84
  </li>
85
  <?php if ( $is_paying ) : ?>
89
  <input type="hidden" name="fs_action" value="deactivate_license">
90
  <?php wp_nonce_field( 'deactivate_license' ) ?>
91
  <a href="#"
92
+ onclick="if (confirm('<?php _efs( 'deactivate-license-confirm', $slug ) ?>')) this.parentNode.submit(); return false;"><i
93
+ class="dashicons dashicons-admin-network"></i> <?php _efs( 'deactivate-license', $slug ) ?>
94
+ </a>
95
  </form>
96
  </li>
97
  <?php if ( ! $license->is_lifetime() &&
107
  printf( __fs( 'after-downgrade-non-blocking', $slug ), $plan->title );
108
  } else {
109
  printf( __fs( 'after-downgrade-blocking', $slug ), $plan->title );
110
+ }?> <?php _efs( 'proceed-confirmation', $slug ) ?>')) this.parentNode.submit(); return false;"><i
111
+ class="dashicons dashicons-download"></i> <?php _efs( 'downgrade', $slug ) ?></a>
112
  </form>
113
  </li>
114
  <?php endif ?>
115
  <li>
116
  &nbsp;•&nbsp;
117
+ <a href="<?php echo $fs->get_upgrade_url() ?>"><i
118
+ class="dashicons dashicons-grid-view"></i> <?php _efs( 'change-plan', $slug ) ?></a>
119
+ </li>
120
+ <?php elseif ( $is_paid_trial ) : ?>
121
+ <li>
122
+ &nbsp;•&nbsp;
123
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
124
+ <input type="hidden" name="fs_action" value="cancel_trial">
125
+ <?php wp_nonce_field( 'cancel_trial' ) ?>
126
+ <a href="#"
127
+ onclick="if (confirm('<?php _efs( 'cancel-trial-confirm' ) ?>')) this.parentNode.submit(); return false;"><i
128
+ class="dashicons dashicons-download"></i> <?php _efs( 'cancel-trial', $slug ) ?></a>
129
+ </form>
130
  </li>
131
  <?php endif ?>
132
+ <li>
133
+ &nbsp;•&nbsp;
134
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
135
+ <input type="hidden" name="fs_action" value="<?php echo $slug ?>_sync_license">
136
+ <?php wp_nonce_field( $slug . '_sync_license' ) ?>
137
+ <a href="#" onclick="this.parentNode.submit(); return false;"><i
138
+ class="dashicons dashicons-image-rotate"></i> <?php _efs( 'sync', $slug ) ?></a>
139
+ </form>
140
+ </li>
141
+
142
  </ul>
143
  </div>
144
  <div class="inside">
145
+ <table id="fs_account_details" cellspacing="0" class="fs-key-value-table">
146
+ <?php
147
+ $profile = array();
148
+ $profile[] = array(
149
+ 'id' => 'user_name',
150
+ 'title' => __fs( 'name', $slug ),
151
+ 'value' => $name
152
+ );
153
+ // if (isset($user->email) && false !== strpos($user->email, '@'))
154
+ $profile[] = array(
155
+ 'id' => 'email',
156
+ 'title' => __fs( 'email', $slug ),
157
+ 'value' => $user->email
158
+ );
 
 
 
 
 
 
 
159
 
160
+ if ( is_numeric( $user->id ) ) {
161
+ $profile[] = array(
162
+ 'id' => 'user_id',
163
+ 'title' => __fs( 'user-id', $slug ),
164
+ 'value' => $user->id
165
+ );
166
+ }
167
+
168
+ $profile[] = array(
169
+ 'id' => 'site_id',
170
+ 'title' => __fs( 'site-id', $slug ),
171
+ 'value' => is_string( $site->id ) ?
172
+ $site->id :
173
+ __fs( 'no-id', $slug )
174
+ );
175
+
176
+ $profile[] = array(
177
+ 'id' => 'site_public_key',
178
+ 'title' => __fs( 'public-key', $slug ),
179
+ 'value' => $site->public_key
180
+ );
181
+
182
+ $profile[] = array(
183
+ 'id' => 'site_secret_key',
184
+ 'title' => __fs( 'secret-key', $slug ),
185
+ 'value' => ( ( is_string( $site->secret_key ) ) ?
186
+ $site->secret_key :
187
+ __fs( 'no-secret', $slug )
188
+ )
189
+ );
190
+
191
+ $profile[] = array(
192
+ 'id' => 'version',
193
+ 'title' => __fs( 'version', $slug ),
194
+ 'value' => $fs->get_plugin_version()
195
+ );
196
+
197
+ if ( $fs->has_paid_plan() ) {
198
+ if ( $fs->is_trial() ) {
199
+ $trial_plan = $fs->get_trial_plan();
200
 
201
  $profile[] = array(
202
+ 'id' => 'plan',
203
+ 'title' => __fs( 'plan', $slug ),
204
+ 'value' => ( is_string( $trial_plan->name ) ?
205
+ strtoupper( $trial_plan->title ) :
206
+ __fs( 'trial', $slug ) )
207
  );
208
+ } else {
209
  $profile[] = array(
210
+ 'id' => 'plan',
211
+ 'title' => __fs( 'plan', $slug ),
212
+ 'value' => is_string( $site->plan->name ) ?
213
+ strtoupper( $site->plan->title ) :
214
+ strtoupper( __fs( 'free', $slug ) )
 
215
  );
216
 
217
+ if ( is_object( $license ) ) {
 
 
 
 
 
 
 
 
 
 
218
  $profile[] = array(
219
+ 'id' => 'license_key',
220
+ 'title' => __fs( 'License Key', $slug ),
221
+ 'value' => $license->secret_key,
 
 
222
  );
223
  }
224
+ }
225
+ }
226
+ ?>
227
+ <?php $odd = true;
228
+ foreach ( $profile as $p ) : ?>
229
+ <?php
230
+ if ( 'plan' === $p['id'] && ! $fs->has_paid_plan() ) {
231
+ // If plugin don't have any paid plans, there's no reason
232
+ // to show current plan.
233
+ continue;
234
+ }
235
  ?>
236
+ <tr class="fs-field-<?php echo $p['id'] ?><?php if ( $odd ) : ?> alternate<?php endif ?>">
237
+ <td>
238
+ <nobr><?php echo $p['title'] ?>:</nobr>
239
+ </td>
240
+ <td<?php if ( 'plan' === $p['id'] ) { echo ' colspan="2"'; }?>>
241
+ <?php if ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
242
+ <code><?php echo htmlspecialchars( substr( $p['value'], 0, 6 ) ) . str_pad( '', 23 * 6, '&bull;' ) . htmlspecialchars( substr( $p['value'], - 3 ) ) ?></code>
243
+ <input type="text" value="<?php echo htmlspecialchars( $p['value'] ) ?>" style="display: none"
244
+ readonly/>
245
+ <?php else : ?>
246
+ <code><?php echo htmlspecialchars( $p['value'] ) ?></code>
247
+ <?php endif ?>
248
+ <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
249
+ <label class="fs-tag fs-warn"><?php _efs( 'not-verified', $slug ) ?></label>
250
+ <?php endif ?>
251
+ <?php if ( 'plan' === $p['id'] ) : ?>
252
+ <?php if ( $fs->is_trial() ) : ?>
253
+ <label class="fs-tag fs-success"><?php _efs( 'trial', $slug ) ?></label>
254
+ <?php endif ?>
255
+ <?php if ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
256
+ <?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
257
+ <label
258
+ class="fs-tag fs-warn"><?php printf( __fs( 'expires-in', $slug ), human_time_diff( time(), strtotime( $license->expiration ) ) ) ?></label>
259
+ <?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
260
+ <label
261
+ class="fs-tag fs-success"><?php printf( __fs( 'renews-in', $slug ), human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ?></label>
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  <?php endif ?>
263
+ <?php elseif ( $fs->is_trial() ) : ?>
264
+ <label
265
+ class="fs-tag fs-warn"><?php printf( __fs( 'expires-in', $slug ), human_time_diff( time(), strtotime( $site->trial_ends ) ) ) ?></label>
266
+ <?php endif ?>
267
+ <div class="button-group">
268
+ <?php $available_license = $fs->is_free_plan() ? $fs->_get_available_premium_license() : false ?>
269
+ <?php if ( false !== $available_license && ( $available_license->left() > 0 || ( $site->is_localhost() && $available_license->is_free_localhost ) ) ) : ?>
270
+ <?php $premium_plan = $fs->_get_plan_by_id( $available_license->plan_id ) ?>
271
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
272
+ method="POST">
273
+ <input type="hidden" name="fs_action" value="activate_license">
274
+ <input type="hidden" name="license_id" value="<?php echo $available_license->id ?>">
275
+ <?php wp_nonce_field( 'activate_license' ) ?>
276
+ <input type="submit" class="button button-primary"
277
+ value="<?php printf(
278
+ __fs( 'activate-x-plan', $slug ) . '%s',
279
+ $premium_plan->title,
280
+ ( $site->is_localhost() && $available_license->is_free_localhost ) ?
281
+ ' [' . __fs( 'localhost', $slug ) . ']' :
282
+ ( $available_license->is_single_site() ?
283
+ '' :
284
+ ' [' . ( 1 < $available_license->left() ?
285
+ sprintf( __fs( 'x-left', $slug ), $available_license->left() ) :
286
+ strtolower( __fs( 'last-license', $slug ) ) ) . ']'
287
+ )
288
+ ) ?> ">
289
+ </form>
290
+ <?php else : ?>
291
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
292
+ method="POST" class="button-group">
293
+ <?php if ($show_upgrade) : ?>
294
+ <a class="button activate-license-trigger <?php echo $slug ?>" href="#"><?php _efs( 'activate-license', $slug ) ?></a>
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  <?php endif ?>
296
+ <input type="submit" class="button"
297
+ value="<?php _efs( 'sync-license', $slug ) ?>">
298
+ <input type="hidden" name="fs_action"
299
+ value="<?php echo $slug ?>_sync_license">
300
+ <?php wp_nonce_field( $slug . '_sync_license' ) ?>
301
+ <a href="<?php echo $fs->get_upgrade_url() ?>"
302
+ class="button<?php if ( $show_upgrade ) {
303
+ echo ' button-primary';
304
+ } ?> button-upgrade"><i
305
+ class="dashicons dashicons-cart"></i> <?php ( $show_upgrade ) ?
306
+ _efs( 'upgrade', $slug ) :
307
+ _efs( 'change-plan', $slug )
308
+ ?></a>
309
+ </form>
310
+ <?php endif ?>
311
+ </div>
312
+ <?php elseif ( 'version' === $p['id'] && $fs->has_paid_plan() ) : ?>
313
+ <?php if ( $fs->is_premium() ) : ?>
314
+ <label
315
+ class="fs-tag fs-<?php echo $fs->can_use_premium_code() ? 'success' : 'warn' ?>"><?php _efs( 'premium-version' ) ?></label>
316
+ <?php elseif ( $fs->can_use_premium_code() ) : ?>
317
+ <label class="fs-tag fs-warn"><?php _efs( 'free-version' ) ?></label>
318
+ <?php endif ?>
319
+ <?php endif ?>
320
+ </td>
321
+ <?php if ( 'plan' !== $p['id'] ) : ?>
322
+ <td class="fs-right">
323
+ <?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
324
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
325
+ <input type="hidden" name="fs_action" value="verify_email">
326
+ <?php wp_nonce_field( 'verify_email' ) ?>
327
+ <input type="submit" class="button button-small"
328
+ value="<?php _efs( 'verify-email', $slug ) ?>">
329
+ </form>
330
+ <?php endif ?>
331
+ <?php if ( 'version' === $p['id'] ) : ?>
332
+ <div class="button-group">
333
+ <?php if ( $is_paying || $fs->is_trial() ) : ?>
334
+ <?php if ( ! $fs->is_allowed_to_install() ) : ?>
335
+ <a target="_blank" class="button button-primary"
336
+ href="<?php echo $fs->_get_latest_download_local_url() ?>"><?php echo sprintf( __fs( 'download-x-version', $slug ), ( $fs->is_trial() ? $trial_plan->title : $site->plan->title ) ) . ( is_object( $update ) ? ' [' . $update->version . ']' : '' ) ?></a>
337
+ <?php elseif ( is_object( $update ) ) : ?>
338
+ <a class="button button-primary"
339
+ 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', $slug ) . ' [' . $update->version . ']' ?></a>
340
+ <?php endif ?>
341
+ <?php endif; ?>
342
+ </div>
343
+ <?php
344
+ elseif ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
345
+ <button class="button button-small"><?php _efs( 'show', $slug ) ?></button>
346
+ <?php
347
+ elseif (/*in_array($p['id'], array('site_secret_key', 'site_id', 'site_public_key')) ||*/
348
+ ( is_string( $user->secret_key ) && in_array( $p['id'], array(
349
+ 'email',
350
+ 'user_name'
351
+ ) ) )
352
+ ) : ?>
353
+ <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"
354
+ onsubmit="var val = prompt('<?php printf( __fs( 'what-is-your-x', $slug ), $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;">
355
+ <input type="hidden" name="fs_action" value="update_<?php echo $p['id'] ?>">
356
+ <input type="hidden" name="fs_<?php echo $p['id'] ?>_<?php echo $slug ?>"
357
+ value="">
358
+ <?php wp_nonce_field( 'update_' . $p['id'] ) ?>
359
+ <input type="submit" class="button button-small"
360
+ value="<?php _efs( 'edit', $slug ) ?>">
361
+ </form>
362
+ <?php endif ?>
363
+ </td>
364
+ <?php endif ?>
365
+ </tr>
366
+ <?php $odd = ! $odd;
367
+ endforeach ?>
368
+ </table>
369
  </div>
370
  </div>
371
+ <script type="text/javascript">
372
+ (function ($) {
373
+ $('.fs-field-license_key button, .fs-field-site_secret_key button').click(function () {
374
+ var
375
+ $this = $(this),
376
+ $parent = $this.closest('tr'),
377
+ $input = $parent.find('input');
378
+
379
+ $parent.find('code').toggle();
380
+ $input.toggle();
381
+
382
+ if ($input.is(':visible')) {
383
+ $this.html('<?php _efs( 'hide', $slug ) ?>');
384
+ setTimeout(function () {
385
+ $input.select().focus();
386
+ }, 100);
387
+ }
388
+ else {
389
+ $this.html('<?php _efs( 'show', $slug ) ?>');
390
+ }
391
+ });
392
+ }(jQuery));
393
+
394
+ </script>
395
+
396
  <?php
397
  $account_addons = $fs->get_account_addons();
398
  if ( ! is_array( $account_addons ) ) {
408
  $addons_to_show = array_unique( array_merge( $installed_addons_ids, $account_addons ) );
409
  ?>
410
  <?php if ( 0 < count( $addons_to_show ) ) : ?>
411
+ <!-- Add-Ons -->
412
  <div class="postbox">
413
+ <div class="">
414
+ <!-- <div class="inside">-->
415
+ <table id="fs_addons" class="widefat">
416
+ <thead>
417
+ <tr>
418
+ <th><h3><?php _efs( 'add-ons', $slug ) ?></h3></th>
419
+ <th><?php _efs( 'id', $slug ) ?></th>
420
+ <th><?php _efs( 'version', $slug ) ?></th>
421
+ <th><?php _efs( 'plan', $slug ) ?></th>
422
+ <th><?php _efs( 'license', $slug ) ?></th>
423
+ <th></th>
424
+ <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
425
+ <th></th>
426
+ <?php endif ?>
427
+ </tr>
428
+ </thead>
429
+ <tbody>
430
+ <?php $odd = true;
431
+ foreach ( $addons_to_show as $addon_id ) : ?>
432
+ <?php
433
+ $addon = $fs->get_addon( $addon_id );
434
+ $is_addon_activated = $fs->is_addon_activated( $addon->slug );
435
+ $is_addon_connected = $fs->is_addon_connected( $addon->slug );
436
+
437
+ $fs_addon = $is_addon_connected ? freemius( $addon->slug ) : false;
438
+ if ( is_object( $fs_addon ) ) {
439
+ $is_paying = $fs_addon->is_paying();
440
+ $user = $fs_addon->get_user();
441
+ $site = $fs_addon->get_site();
442
+ $license = $fs_addon->_get_license();
443
+ $subscription = $fs_addon->_get_subscription();
444
+ $plan = $fs_addon->get_plan();
445
+ $is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
446
+ $is_paid_trial = $fs_addon->is_paid_trial();
447
+ $show_upgrade = ( ! $is_paying && ! $is_paid_trial && ! $fs_addon->_has_premium_license() );
448
+ $is_current_license_expired = is_object( $license ) && $license->is_expired();
449
+ }
450
+
451
+ // var_dump( $is_paid_trial, $license, $site, $subscription );
452
+
453
+ ?>
454
+ <tr<?php if ( $odd ) {
455
+ echo ' class="alternate"';
456
+ } ?>>
457
+ <td>
458
+ <!-- Title -->
459
+ <?php echo $addon->title ?>
460
+ </td>
461
+ <?php if ( $is_addon_connected ) : ?>
462
+ <?php // Add-on Installed ?>
463
+ <?php $addon_site = $fs_addon->get_site(); ?>
464
+ <td>
465
+ <!-- ID -->
466
+ <?php echo $addon_site->id ?>
467
+ </td>
468
+ <td>
469
+ <!-- Version -->
470
+ <?php echo $fs_addon->get_plugin_version() ?>
471
+ </td>
472
+ <td>
473
+ <!-- Plan Title -->
474
+ <?php echo is_string( $addon_site->plan->name ) ? strtoupper( $addon_site->plan->title ) : 'FREE' ?>
475
+ </td>
476
+ <td>
477
+ <!-- Expiration -->
478
+ <?php
479
+ $tags = array();
480
+
481
+ if ( $fs_addon->is_trial() ) {
482
+ $tags[] = array( 'label' => __fs( 'trial', $slug ), 'type' => 'success' );
483
+
484
+ $tags[] = array(
485
+ 'label' => sprintf( __fs( ( $is_paid_trial ? 'renews-in' : 'expires-in' ), $slug ), human_time_diff( time(), strtotime( $site->trial_ends ) ) ),
486
+ 'type' => ( $is_paid_trial ? 'success' : 'warn' )
487
+ );
488
+ } else {
489
+ if ( is_object( $license ) ) {
490
+ if ( $license->is_cancelled ) {
491
+ $tags[] = array(
492
+ 'label' => __fs( 'cancelled', $slug ),
493
+ 'type' => 'error'
494
+ );
495
+ } else if ( $license->is_expired() ) {
496
+ $tags[] = array(
497
+ 'label' => __fs( 'expired', $slug ),
498
+ 'type' => 'error'
499
+ );
500
+ } else if ( $license->is_lifetime() ) {
501
+ $tags[] = array(
502
+ 'label' => __fs( 'no-expiration', $slug ),
503
+ 'type' => 'success'
504
+ );
505
+ } else if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) {
506
+ $tags[] = array(
507
+ 'label' => sprintf( __fs( 'expires-in', $slug ), human_time_diff( time(), strtotime( $license->expiration ) ) ),
508
+ 'type' => 'warn'
509
+ );
510
+ } else if ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) {
511
+ $tags[] = array(
512
+ 'label' => sprintf( __fs( 'renews-in', $slug ), human_time_diff( time(), strtotime( $subscription->next_payment ) ) ),
513
+ 'type' => 'success'
514
+ );
515
+ }
516
+ }
517
+ }
518
+
519
+ foreach ( $tags as $t ) {
520
+ printf( '<label class="fs-tag fs-%s">%s</label>' . "\n", $t['type'], $t['label'] );
521
+ }
522
+ ?>
523
+ </td>
524
  <?php
525
+ $buttons = array();
526
+ if ( $is_addon_activated ) {
527
+ if ( $is_paying ) {
528
+ $buttons[] = fs_ui_get_action_button(
529
+ $slug,
530
+ 'account',
531
+ 'deactivate_license',
532
+ __fs( 'deactivate-license', $slug ),
533
+ array( 'plugin_id' => $addon_id ),
534
+ false
535
+ );
536
+ } else if ( $is_paid_trial ) {
537
+ $buttons[] = fs_ui_get_action_button(
538
+ $slug,
539
+ 'account',
540
+ 'cancel_trial',
541
+ __fs( 'cancel-trial', $slug ),
542
+ array( 'plugin_id' => $addon_id ),
543
+ false,
544
+ 'dashicons dashicons-download',
545
+ __fs( 'cancel-trial-confirm', $slug ),
546
+ 'POST'
547
+ );
548
+ } else {
549
+ $premium_license = $fs_addon->_get_available_premium_license();
550
+
551
+ if ( is_object( $premium_license ) ) {
552
+ $site = $fs_addon->get_site();
553
+
554
+ $buttons[] = fs_ui_get_action_button(
555
+ $slug,
556
+ 'account',
557
+ 'activate_license',
558
+ sprintf( __fs( 'activate-x-plan', $slug ), $fs_addon->get_plan_title(), ( $site->is_localhost() && $premium_license->is_free_localhost ) ? '[localhost]' : ( 1 < $premium_license->left() ? $premium_license->left() . ' left' : '' ) ),
559
+ array(
560
+ 'plugin_id' => $addon_id,
561
+ 'license_id' => $premium_license->id,
562
+ )
563
+ );
564
+ }
565
+ }
566
 
567
+ if ( 0 == count( $buttons ) ) {
568
+ // Add sync license only if non of the other CTAs are visible.
569
+ $buttons[] = fs_ui_get_action_button(
570
+ $slug,
571
+ 'account',
572
+ $slug . '_sync_license',
573
+ __fs( 'sync-license', $slug ),
574
+ array( 'plugin_id' => $addon_id ),
575
+ false
576
+ );
577
+
578
+ }
579
+ } else if ( ! $show_upgrade ) {
580
+ if ( $fs->is_addon_installed( $addon->slug ) ) {
581
+ $addon_file = $fs->get_addon_basename( $addon->slug );
582
+ $buttons[] = sprintf(
583
+ '<a class="button button-primary" href="%s" title="%s" class="edit">%s</a>',
584
+ wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $addon_file, 'activate-plugin_' . $addon_file ),
585
+ esc_attr( __fs( 'activate-this-addon', $slug ) ),
586
+ __fs( 'activate', $slug )
587
+ );
588
+ } else {
589
+ if ( $fs->is_allowed_to_install() ) {
590
+ $buttons[] = sprintf(
591
+ '<a class="button button-primary" href="%s" class="edit">%s</a>',
592
+ wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
593
+ __fs( 'install-now', $slug )
594
+ );
595
+ } else {
596
+ $buttons[] = sprintf(
597
+ '<a target="_blank" class="button button-primary" href="%s" class="edit">%s</a>',
598
+ $fs->_get_latest_download_local_url( $addon_id ),
599
+ __fs( 'download-latest', $slug )
600
+ );
601
+ }
602
+ }
603
+ }
604
+
605
+ if ( $show_upgrade ) {
606
+ $buttons[] = sprintf( '<a href="%s" class="thickbox button button-primary" aria-label="%s" data-title="%s"><i class="dashicons dashicons-cart"></i> %s</a>',
607
+ esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
608
+ '&TB_iframe=true&width=600&height=550' ) ),
609
+ esc_attr( sprintf( __fs( 'more-information-about-x', $slug ), $addon->title ) ),
610
+ esc_attr( $addon->title ),
611
+ __fs( ( $fs_addon->has_free_plan() ? 'upgrade' : 'purchase' ), $slug )
612
+ );
613
+ }
614
+
615
+ $buttons_count = count( $buttons );
616
  ?>
617
+
618
+ <td>
619
+ <!-- Actions -->
620
+ <?php if ($buttons_count > 1) : ?>
621
+ <div class="button-group">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  <?php endif ?>
623
+ <?php foreach ( $buttons as $button ) : ?>
624
+ <?php echo $button ?>
625
+ <?php endforeach ?>
626
+ <?php if ($buttons_count > 1) : ?>
627
+ </div>
628
+ <?php endif ?>
629
+ </td>
630
+ <?php else : ?>
631
+ <?php // Add-on NOT Installed or was never connected.
632
+ ?>
633
+ <td colspan="4">
634
+ <!-- Action -->
635
+ <?php if ( $fs->is_addon_installed( $addon->slug ) ) : ?>
636
+ <?php $addon_file = $fs->get_addon_basename( $addon->slug ) ?>
637
+ <a class="button button-primary"
638
+ href="<?php echo wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $addon_file, 'activate-plugin_' . $addon_file ) ?>"
639
+ title="<?php esc_attr( __fs( 'activate-this-addon', $slug ) ) ?>"
640
+ class="edit"><?php _efs( 'activate', $slug ) ?></a>
641
  <?php else : ?>
642
+ <?php if ( $fs->is_allowed_to_install() ) : ?>
643
+ <a class="button button-primary"
644
+ 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', $slug ) ?></a>
645
+ <?php else : ?>
646
+ <a target="_blank" class="button button-primary"
647
+ href="<?php echo $fs->_get_latest_download_local_url( $addon_id ) ?>"><?php _efs( 'download-latest', $slug ) ?></a>
648
+ <?php endif ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  <?php endif ?>
650
+ </td>
651
+ <?php endif ?>
652
+ <?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
653
+ <td>
654
+ <!-- Optional Delete Action -->
655
+ <?php
656
+ if ( $is_addon_activated ) {
657
+ fs_ui_action_button(
658
+ $slug, 'account',
659
+ 'delete_account',
660
+ __fs( 'delete', $slug ),
661
+ array( 'plugin_id' => $addon_id ),
662
+ false
663
+ );
664
+ }
665
+ ?>
666
+ </td>
667
+ <?php endif ?>
668
+ </tr>
669
+ <?php $odd = ! $odd;
670
+ endforeach ?>
671
+ </tbody>
672
+ </table>
673
+ </div>
674
  </div>
675
  <?php endif ?>
676
 
680
  </div>
681
  </div>
682
  </div>
683
+ <?php
684
+ $params = array(
685
+ 'page' => 'account',
686
+ 'module_id' => $fs->get_id(),
687
+ 'module_slug' => $slug,
688
+ 'module_version' => $fs->get_plugin_version(),
689
+ );
690
+ fs_require_template( 'powered-by.php', $params );
691
+ ?>
freemius/templates/add-ons.php CHANGED
@@ -10,6 +10,9 @@
10
  exit;
11
  }
12
 
 
 
 
13
  $slug = $VARS['slug'];
14
  /**
15
  * @var Freemius
@@ -24,85 +27,100 @@
24
  * @var FS_Plugin[]
25
  */
26
  $addons = $fs->get_addons();
 
 
27
  ?>
28
  <div id="fs_addons" class="wrap">
29
  <h2><?php printf( __fs( 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ?></h2>
30
 
31
  <div id="poststuff">
 
 
 
 
 
 
 
32
  <ul class="fs-cards-list">
33
- <?php foreach ( $addons as $addon ) : ?>
34
- <?php
35
- $open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
 
36
 
37
- $price = 0;
38
- $plans_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans.json" );
39
- if ( ! isset( $plans_result->error ) ) {
40
- $plans = $plans_result->plans;
41
- if ( is_array( $plans ) && 0 < count( $plans ) ) {
42
- $plan = $plans[0];
43
- $pricing_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans/{$plan->id}/pricing.json" );
44
- if ( ! isset( $pricing_result->error ) ) {
45
- // Update plan's pricing.
46
- $plan->pricing = $pricing_result->pricing;
 
47
 
48
- if ( is_array( $plan->pricing ) && 0 < count( $plan->pricing ) ) {
49
- $min_price = 999999;
50
- foreach ( $plan->pricing as $pricing ) {
51
- if ( ! is_null( $pricing->annual_price ) && $pricing->annual_price > 0 ) {
52
- $min_price = min( $min_price, $pricing->annual_price );
53
- } else if ( ! is_null( $pricing->monthly_price ) && $pricing->monthly_price > 0 ) {
54
- $min_price = min( $min_price, 12 * $pricing->monthly_price );
 
55
  }
56
- }
57
 
58
- if ( $min_price < 999999 ) {
59
- $price = $min_price;
 
60
  }
61
  }
62
  }
63
  }
64
- }
65
- ?>
66
- <li class="fs-card" data-slug="<?php echo $addon->slug ?>">
67
- <?php
68
- echo sprintf( '<a href="%s" class="thickbox fs-overlay" aria-label="%s" data-title="%s"></a>',
69
- esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
70
- '&TB_iframe=true&width=600&height=550' ) ),
71
- esc_attr( sprintf( __fs( 'more-information-about-x', $slug ), $addon->title ) ),
72
- esc_attr( $addon->title )
73
- );
74
  ?>
75
- <?php
76
- if ( is_null( $addon->info ) ) {
77
- $addon->info = new stdClass();
78
- }
79
- if ( ! isset( $addon->info->card_banner_url ) ) {
80
- $addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
81
- }
82
- if ( ! isset( $addon->info->short_description ) ) {
83
- $addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
84
- }
85
- ?>
86
- <div class="fs-inner">
87
- <ul>
88
- <li class="fs-card-banner"
89
- style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"></li>
90
- <li class="fs-title"><?php echo $addon->title ?></li>
91
- <li class="fs-offer">
 
 
 
 
 
 
 
 
 
 
92
  <span
93
- class="fs-price"><?php echo ( 0 == $price ) ? __fs( 'free', $slug ) : '$' . number_format( $price, 2 ) ?></span>
94
- </li>
95
- <li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
96
- </ul>
97
- </div>
98
- </li>
99
- <?php endforeach ?>
 
 
100
  </ul>
101
  </div>
102
  </div>
103
- <?php if ( $open_addon ) : ?>
104
  <script type="text/javascript">
105
  (function ($) {
 
 
106
  var interval = setInterval(function () {
107
  // Open add-on information page.
108
  $('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
@@ -111,7 +129,26 @@
111
  interval = null;
112
  }
113
  }, 200);
 
 
 
 
 
 
 
 
 
 
 
 
114
  })(jQuery);
115
  </script>
116
- <?php endif ?>
117
- <?php fs_require_template( 'powered-by.php' ) ?>
 
 
 
 
 
 
 
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @var array $VARS
15
+ */
16
  $slug = $VARS['slug'];
17
  /**
18
  * @var Freemius
27
  * @var FS_Plugin[]
28
  */
29
  $addons = $fs->get_addons();
30
+
31
+ $has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
32
  ?>
33
  <div id="fs_addons" class="wrap">
34
  <h2><?php printf( __fs( 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ?></h2>
35
 
36
  <div id="poststuff">
37
+ <?php if ( ! $has_addons ) : ?>
38
+ <h3><?php printf(
39
+ '%s... %s',
40
+ __fs( 'oops', $slug ),
41
+ __fs( 'add-ons-missing', $slug )
42
+ ) ?></h3>
43
+ <?php endif ?>
44
  <ul class="fs-cards-list">
45
+ <?php if ( $has_addons ) : ?>
46
+ <?php foreach ( $addons as $addon ) : ?>
47
+ <?php
48
+ $open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
49
 
50
+ $price = 0;
51
+ $plan = null;
52
+ $plans_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans.json" );
53
+ if ( ! isset( $plans_result->error ) ) {
54
+ $plans = $plans_result->plans;
55
+ if ( is_array( $plans ) && 0 < count( $plans ) ) {
56
+ $plan = new FS_Plugin_Plan( $plans[0] );
57
+ $pricing_result = $fs->get_api_site_or_plugin_scope()->get( "/addons/{$addon->id}/plans/{$plan->id}/pricing.json" );
58
+ if ( ! isset( $pricing_result->error ) ) {
59
+ // Update plan's pricing.
60
+ $plan->pricing = $pricing_result->pricing;
61
 
62
+ if ( is_array( $plan->pricing ) && 0 < count( $plan->pricing ) ) {
63
+ $min_price = 999999;
64
+ foreach ( $plan->pricing as $pricing ) {
65
+ if ( ! is_null( $pricing->annual_price ) && $pricing->annual_price > 0 ) {
66
+ $min_price = min( $min_price, $pricing->annual_price );
67
+ } else if ( ! is_null( $pricing->monthly_price ) && $pricing->monthly_price > 0 ) {
68
+ $min_price = min( $min_price, 12 * $pricing->monthly_price );
69
+ }
70
  }
 
71
 
72
+ if ( $min_price < 999999 ) {
73
+ $price = $min_price;
74
+ }
75
  }
76
  }
77
  }
78
  }
 
 
 
 
 
 
 
 
 
 
79
  ?>
80
+ <li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
81
+ <?php
82
+ echo sprintf( '<a href="%s" class="thickbox fs-overlay" aria-label="%s" data-title="%s"></a>',
83
+ esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
84
+ '&TB_iframe=true&width=600&height=550' ) ),
85
+ esc_attr( sprintf( __fs( 'more-information-about-x', $slug ), $addon->title ) ),
86
+ esc_attr( $addon->title )
87
+ );
88
+ ?>
89
+ <?php
90
+ if ( is_null( $addon->info ) ) {
91
+ $addon->info = new stdClass();
92
+ }
93
+ if ( ! isset( $addon->info->card_banner_url ) ) {
94
+ $addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
95
+ }
96
+ if ( ! isset( $addon->info->short_description ) ) {
97
+ $addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
98
+ }
99
+ ?>
100
+ <div class="fs-inner">
101
+ <ul>
102
+ <li class="fs-card-banner"
103
+ style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"></li>
104
+ <!-- <li class="fs-tag"></li>-->
105
+ <li class="fs-title"><?php echo $addon->title ?></li>
106
+ <li class="fs-offer">
107
  <span
108
+ class="fs-price"><?php echo ( 0 == $price ) ? __fs( 'free', $slug ) : ('$' . number_format( $price, 2 ) . ($plan->has_trial() ? ' - ' . __fs('trial', $slug) : '')) ?></span>
109
+ </li>
110
+ <li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
111
+ <li class="fs-cta"><a class="button"><?php _efs( 'view-details', $slug ) ?></a></li>
112
+ </ul>
113
+ </div>
114
+ </li>
115
+ <?php endforeach ?>
116
+ <?php endif ?>
117
  </ul>
118
  </div>
119
  </div>
 
120
  <script type="text/javascript">
121
  (function ($) {
122
+ <?php if ( $open_addon ) : ?>
123
+
124
  var interval = setInterval(function () {
125
  // Open add-on information page.
126
  $('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
129
  interval = null;
130
  }
131
  }, 200);
132
+
133
+ <?php else : ?>
134
+
135
+
136
+ $('.fs-card.fs-addon')
137
+ .mouseover(function () {
138
+ $(this).find('.fs-cta .button').addClass('button-primary');
139
+ }).mouseout(function () {
140
+ $(this).find('.fs-cta .button').removeClass('button-primary');
141
+ });
142
+
143
+ <?php endif ?>
144
  })(jQuery);
145
  </script>
146
+ <?php
147
+ $params = array(
148
+ 'page' => 'addons',
149
+ 'module_id' => $fs->get_id(),
150
+ 'module_slug' => $slug,
151
+ 'module_version' => $fs->get_plugin_version(),
152
+ );
153
+ fs_require_template( 'powered-by.php', $params );
154
+ ?>
freemius/templates/admin-notice.php CHANGED
@@ -10,31 +10,35 @@
10
  exit;
11
  }
12
  ?>
13
- <div data-id="<?php echo $VARS['id'] ?>" data-slug="<?php echo $VARS['slug'] ?>" class="<?php
14
- switch ( $VARS['type'] ) {
15
- case 'error':
16
- echo 'error form-invalid';
17
- break;
18
- case 'promotion':
19
- echo 'updated promotion';
20
- break;
21
- case 'update':
 
22
  // echo 'update-nag update';
23
  // break;
24
- case 'success':
25
- default:
26
- echo 'updated success';
27
- break;
28
- }
29
- ?> fs-notice<?php if ( $VARS['sticky'] ) {
30
- echo ' fs-sticky';
31
- } ?><?php if ( ! empty( $VARS['plugin'] ) ) {
32
- echo ' fs-has-title';
33
- } ?>"><?php if ( ! empty( $VARS['plugin'] ) ) : ?><label
34
- class="fs-plugin-title"><?php echo $VARS['plugin'] ?></label><?php endif ?><?php if ( $VARS['sticky'] ) : ?>
 
 
35
  <div class="fs-close"><i class="dashicons dashicons-no"
36
  title="<?php _efs( 'dismiss' ) ?>"></i> <span><?php _efs( 'dismiss' ) ?></span>
37
- </div><?php endif ?>
 
38
  <div class="fs-notice-body">
39
  <?php if ( ! empty( $VARS['title'] ) ) : ?><b><?php echo $VARS['title'] ?></b> <?php endif ?>
40
  <?php echo $VARS['message'] ?>
10
  exit;
11
  }
12
  ?>
13
+ <div<?php if ( ! empty( $VARS['id'] ) ) : ?> data-id="<?php echo $VARS['id'] ?>"<?php endif ?><?php if ( ! empty( $VARS['slug'] ) ) : ?> data-slug="<?php echo $VARS['slug'] ?>"<?php endif ?>
14
+ class="<?php
15
+ switch ( $VARS['type'] ) {
16
+ case 'error':
17
+ echo 'error form-invalid';
18
+ break;
19
+ case 'promotion':
20
+ echo 'updated promotion';
21
+ break;
22
+ case 'update':
23
  // echo 'update-nag update';
24
  // break;
25
+ case 'success':
26
+ default:
27
+ echo 'updated success';
28
+ break;
29
+ }
30
+ ?> fs-notice<?php if ( ! empty( $VARS['sticky'] ) ) {
31
+ echo ' fs-sticky';
32
+ } ?><?php if ( ! empty( $VARS['plugin'] ) ) {
33
+ echo ' fs-has-title';
34
+ } ?>"><?php if ( ! empty( $VARS['plugin'] ) ) : ?>
35
+ <label class="fs-plugin-title"><?php echo $VARS['plugin'] ?></label>
36
+ <?php endif ?>
37
+ <?php if ( ! empty( $VARS['sticky'] ) ) : ?>
38
  <div class="fs-close"><i class="dashicons dashicons-no"
39
  title="<?php _efs( 'dismiss' ) ?>"></i> <span><?php _efs( 'dismiss' ) ?></span>
40
+ </div>
41
+ <?php endif ?>
42
  <div class="fs-notice-body">
43
  <?php if ( ! empty( $VARS['title'] ) ) : ?><b><?php echo $VARS['title'] ?></b> <?php endif ?>
44
  <?php echo $VARS['message'] ?>
freemius/templates/all-admin-notice.php CHANGED
@@ -9,6 +9,10 @@
9
  if ( ! defined( 'ABSPATH' ) ) {
10
  exit;
11
  }
 
 
 
 
12
  ?>
13
  <div class="<?php
14
  switch ($VARS['type']) {
9
  if ( ! defined( 'ABSPATH' ) ) {
10
  exit;
11
  }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
  ?>
17
  <div class="<?php
18
  switch ($VARS['type']) {
freemius/templates/billing.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2016, Freemius, Inc.
5
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
+ * @since 1.2.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ /**
18
+ * @var Freemius $fs
19
+ */
20
+ $fs = freemius( $slug );
21
+
22
+ /**
23
+ * @var FS_Plugin_Tag $update
24
+ */
25
+ $update = $fs->get_update( false, false );
26
+
27
+ $is_paying = $fs->is_paying();
28
+ $user = $fs->get_user();
29
+ $site = $fs->get_site();
30
+ $name = $user->get_name();
31
+ $license = $fs->_get_license();
32
+ $subscription = $fs->_get_subscription();
33
+ $plan = $fs->get_plan();
34
+ $is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
35
+ $is_paid_trial = $fs->is_paid_trial();
36
+ $show_upgrade = ( ! $is_paying && ! $is_paid_trial );
37
+ ?>
38
+
39
+ <div id="fs_account" class="wrap">
40
+ <h2 class="nav-tab-wrapper">
41
+ <a href="<?php echo $fs->get_account_url() ?>" class="nav-tab"><?php _efs( 'account', $slug ) ?></a>
42
+ <?php if ( $fs->has_addons() ) : ?>
43
+ <a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>"
44
+ class="nav-tab"><?php _efs( 'add-ons', $slug ) ?></a>
45
+ <?php endif ?>
46
+ <?php if ( $fs->is_not_paying() && $fs->has_paid_plan() ) : ?>
47
+ <a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php _efs( 'upgrade', $slug ) ?></a>
48
+ <?php if ( $fs->apply_filters( 'show_trial', true ) && ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
49
+ <a href="<?php echo $fs->get_trial_url() ?>"
50
+ class="nav-tab"><?php _efs( 'free-trial', $slug ) ?></a>
51
+ <?php endif ?>
52
+ <?php endif ?>
53
+ <?php if ( ! $plan->is_free() ) : ?>
54
+ <a href="<?php echo $fs->get_account_tab_url( 'billing' ) ?>"
55
+ class="nav-tab nav-tab-active"><?php _efs( 'billing', $slug ) ?></a>
56
+ <?php endif ?>
57
+ </h2>
58
+
59
+ <div id="poststuff">
60
+ <div>
61
+ <div class="has-sidebar has-right-sidebar">
62
+ <div class="has-sidebar-content">
63
+ <div class="postbox">
64
+ <h3><?php _efs( 'payments', $slug ) ?></h3>
65
+
66
+ <?php
67
+ $payments = $fs->_fetch_payments();
68
+ ?>
69
+
70
+ <div class="inside">
71
+ <table class="widefat">
72
+ <thead>
73
+ <tr>
74
+ <th><?php _efs( 'id', $slug ) ?></th>
75
+ <th><?php _efs( 'date', $slug ) ?></th>
76
+ <!-- <th>--><?php //_efs( 'transaction' ) ?><!--</th>-->
77
+ <th><?php _efs( 'amount', $slug ) ?></th>
78
+ <th><?php _efs( 'invoice', $slug ) ?></th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>
82
+ <?php $odd = true ?>
83
+ <?php foreach ( $payments as $payment ) : ?>
84
+ <tr<?php echo $odd ? ' class="alternate"' : '' ?>>
85
+ <td><?php echo $payment->id ?></td>
86
+ <td><?php echo date( 'M j, Y', strtotime( $payment->created ) ) ?></td>
87
+ <td>$<?php echo $payment->gross ?></td>
88
+ <td><a href="<?php echo $fs->_get_invoice_api_url($payment->id) ?>" class="button button-small"
89
+ target="_blank"><?php _efs( 'invoice', $slug ) ?></a></td>
90
+ </tr>
91
+ <?php $odd = ! $odd; endforeach ?>
92
+ </tbody>
93
+ </table>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ <?php
102
+ $params = array(
103
+ 'page' => 'account',
104
+ 'module_id' => $fs->get_id(),
105
+ 'module_slug' => $slug,
106
+ 'module_version' => $fs->get_plugin_version(),
107
+ );
108
+ fs_require_template( 'powered-by.php', $params );
109
+ ?>
freemius/templates/checkout.php CHANGED
@@ -16,6 +16,9 @@
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
  fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
18
 
 
 
 
19
  $slug = $VARS['slug'];
20
  $fs = freemius( $slug );
21
 
@@ -29,13 +32,23 @@
29
 
30
  // Get site context secure params.
31
  if ( $fs->is_registered() ) {
 
 
 
 
 
 
 
 
 
 
32
  $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
33
- $fs->get_site(),
34
  $timestamp,
35
  'checkout'
36
  ) );
37
  } else {
38
- $current_user = wp_get_current_user();
39
 
40
  // Add site and user info to the request, this information
41
  // is NOT being stored unless the user complete the purchase
@@ -68,36 +81,35 @@
68
  }
69
  }
70
 
71
- if ( $fs->is_payments_sandbox() ) // Append plugin secure token for sandbox mode authentication.)
72
  {
 
73
  $context_params['sandbox'] = FS_Security::instance()->get_secure_token(
74
  $fs->get_plugin(),
75
  $timestamp,
76
  'checkout'
77
  );
 
 
 
 
 
 
 
78
  }
79
 
80
- $return_url = fs_nonce_url( $fs->_get_admin_page_url(
81
- 'account',
82
- array(
83
- 'fs_action' => $slug . '_sync_license',
84
- 'plugin_id' => isset( $_GET['plugin_id'] ) ? $_GET['plugin_id'] : $fs->get_id()
85
- )
86
- ), $slug . '_sync_license' );
87
 
88
  $query_params = array_merge( $context_params, $_GET, array(
89
  // Current plugin version.
90
  'plugin_version' => $fs->get_plugin_version(),
 
91
  'return_url' => $return_url,
92
  // Admin CSS URL for style/design competability.
93
  // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
94
  ) );
95
  ?>
96
- <div class="fs-secure-notice">
97
- <i class="dashicons dashicons-lock"></i>
98
- <span><b>Secure HTTPS Checkout</b> - PCI compliant, running via iframe from external domain</span>
99
- </div>
100
- <div id="fs_contact" class="wrap" style="margin: 40px 0 -65px -20px;">
101
  <div id="iframe"></div>
102
  <script type="text/javascript">
103
  // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax
@@ -161,12 +173,14 @@
161
  iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
162
  .appendTo('#iframe');
163
 
164
- FS.PostMessage.init(base_url);
165
  FS.PostMessage.receiveOnce('height', function (data) {
166
  var h = data.height;
167
  if (!isNaN(h) && h > 0 && h != iframe_height) {
168
  iframe_height = h;
169
- $("#iframe iframe").height(iframe_height + 'px');
 
 
170
  }
171
  });
172
 
@@ -203,11 +217,7 @@
203
  // and then click the purchase button, the context information
204
  // of the user will be shared with Freemius in order to complete the
205
  // purchase workflow and activate the license for the right user.
206
- <?php $current_user = wp_get_current_user() ?>
207
  FS.PostMessage.post('context', {
208
- // user_firstname: '<?php //echo $current_user->user_firstname ?>//',
209
- // user_lastname: '<?php //echo $current_user->user_lastname ?>//',
210
- // user_email: '<?php //echo $current_user->user_email ?>//'
211
  plugin_id : '<?php echo $fs->get_id() ?>',
212
  plugin_public_key: '<?php echo $fs->get_public_key() ?>',
213
  plugin_version : '<?php echo $fs->get_plugin_version() ?>',
@@ -243,4 +253,12 @@
243
  })(jQuery);
244
  </script>
245
  </div>
246
- <?php fs_require_template( 'powered-by.php' ) ?>
 
 
 
 
 
 
 
 
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
  fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
18
 
19
+ /**
20
+ * @var array $VARS
21
+ */
22
  $slug = $VARS['slug'];
23
  $fs = freemius( $slug );
24
 
32
 
33
  // Get site context secure params.
34
  if ( $fs->is_registered() ) {
35
+ $site = $fs->get_site();
36
+ $plugin_id = fs_request_get( 'plugin_id', $fs->get_id() );
37
+
38
+ if ($plugin_id != $fs->get_id()) {
39
+ if ( $fs->is_addon_activated( $plugin_id ) ) {
40
+ $fs_addon = Freemius::get_instance_by_id( $plugin_id );
41
+ $site = $fs_addon->get_site();
42
+ }
43
+ }
44
+
45
  $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
46
+ $site,
47
  $timestamp,
48
  'checkout'
49
  ) );
50
  } else {
51
+ $current_user = Freemius::_get_current_wp_user();
52
 
53
  // Add site and user info to the request, this information
54
  // is NOT being stored unless the user complete the purchase
81
  }
82
  }
83
 
84
+ if ( $fs->is_payments_sandbox() )
85
  {
86
+ // Append plugin secure token for sandbox mode authentication.
87
  $context_params['sandbox'] = FS_Security::instance()->get_secure_token(
88
  $fs->get_plugin(),
89
  $timestamp,
90
  'checkout'
91
  );
92
+
93
+ /**
94
+ * @since 1.1.7.3 Add security timestamp for sandbox even for anonymous user.
95
+ */
96
+ if ( empty( $context_params['s_ctx_ts'] ) ) {
97
+ $context_params['s_ctx_ts'] = $timestamp;
98
+ }
99
  }
100
 
101
+ $return_url = $fs->_get_sync_license_url( isset( $_GET['plugin_id'] ) ? $_GET['plugin_id'] : $fs->get_id() );
 
 
 
 
 
 
102
 
103
  $query_params = array_merge( $context_params, $_GET, array(
104
  // Current plugin version.
105
  'plugin_version' => $fs->get_plugin_version(),
106
+ 'sdk_version' => WP_FS__SDK_VERSION,
107
  'return_url' => $return_url,
108
  // Admin CSS URL for style/design competability.
109
  // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
110
  ) );
111
  ?>
112
+ <div id="fs_checkout" class="wrap" style="margin: 0 0 -65px -20px;">
 
 
 
 
113
  <div id="iframe"></div>
114
  <script type="text/javascript">
115
  // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax
173
  iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
174
  .appendTo('#iframe');
175
 
176
+ FS.PostMessage.init(base_url, [iframe[0]]);
177
  FS.PostMessage.receiveOnce('height', function (data) {
178
  var h = data.height;
179
  if (!isNaN(h) && h > 0 && h != iframe_height) {
180
  iframe_height = h;
181
+ iframe.height(iframe_height + 'px');
182
+
183
+ FS.PostMessage.postScroll(iframe[0]);
184
  }
185
  });
186
 
217
  // and then click the purchase button, the context information
218
  // of the user will be shared with Freemius in order to complete the
219
  // purchase workflow and activate the license for the right user.
 
220
  FS.PostMessage.post('context', {
 
 
 
221
  plugin_id : '<?php echo $fs->get_id() ?>',
222
  plugin_public_key: '<?php echo $fs->get_public_key() ?>',
223
  plugin_version : '<?php echo $fs->get_plugin_version() ?>',
253
  })(jQuery);
254
  </script>
255
  </div>
256
+ <?php
257
+ $params = array(
258
+ 'page' => 'checkout',
259
+ 'module_id' => $fs->get_id(),
260
+ 'module_slug' => $slug,
261
+ 'module_version' => $fs->get_plugin_version(),
262
+ );
263
+ fs_require_template( 'powered-by.php', $params );
264
+ ?>
freemius/templates/connect.php CHANGED
@@ -1,242 +1,349 @@
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
- $slug = $VARS['slug'];
14
- $fs = freemius( $slug );
15
- $is_pending_activation = $fs->is_pending_activation();
16
-
17
- $fs->_enqueue_connect_essentials();
18
-
19
- $current_user = wp_get_current_user();
20
-
21
- $first_name = $current_user->user_firstname;
22
- if ( empty( $first_name ) ) {
23
- $first_name = $current_user->nickname;
24
- }
25
-
26
- $site_url = get_site_url();
27
- $protocol_pos = strpos( $site_url, '://' );
28
- if ( false !== $protocol_pos ) {
29
- $site_url = substr( $site_url, $protocol_pos + 3 );
30
- }
31
-
32
- $freemius_site_url = $fs->has_paid_plan() ?
33
- 'https://freemius.com/wordpress/' :
34
- // Insights platform information.
35
- 'https://freemius.com/wordpress/insights/';
36
- ?>
37
- <div id="fs_connect" class="wrap<?php if ( ! $fs->enable_anonymous() || $is_pending_activation ) {
38
- echo ' fs-anonymous-disabled';
39
- } ?>">
40
- <div class="fs-visual">
41
- <b class="fs-site-icon"><i class="dashicons dashicons-wordpress"></i></b>
42
- <i class="dashicons dashicons-plus fs-first"></i>
43
- <?php
44
- $vars = array( 'slug' => $slug );
45
- fs_require_once_template( 'plugin-icon.php', $vars );
46
- ?>
47
- <i class="dashicons dashicons-plus fs-second"></i>
48
- <img class="fs-connect-logo" width="80" height="80" src="//img.freemius.com/connect-logo.png"/>
49
- </div>
50
- <div class="fs-content">
51
- <p><?php
52
- if ( $is_pending_activation ) {
53
- echo $fs->apply_filters( 'pending_activation_message', sprintf(
54
- __fs( 'thanks-x', $slug ) . '<br>' .
55
- __fs( 'pending-activation-message', $slug ),
56
- $first_name,
57
- '<b>' . $fs->get_plugin_name() . '</b>',
58
- '<b>' . $current_user->user_email . '</b>'
59
- ) );
60
- } else {
61
- $filter = 'connect_message';
62
- $default_optin_message = 'connect-message';
63
-
64
- if ( $fs->is_plugin_update() ) {
65
- // If Freemius was added on a plugin update, set different
66
- // opt-in message.
67
- $default_optin_message = 'connect-message_on-update';
68
-
69
- // If user customized the opt-in message on update, use
70
- // that message. Otherwise, fallback to regular opt-in
71
- // custom message if exist.
72
- if ( $fs->has_filter( 'connect_message_on_update' ) ) {
73
- $filter = 'connect_message_on_update';
74
- }
75
- }
76
-
77
- echo $fs->apply_filters( $filter,
78
- sprintf(
79
- __fs( 'hey-x', $slug ) . '<br>' .
80
- __fs( $default_optin_message, $slug ),
81
- $first_name,
82
- '<b>' . $fs->get_plugin_name() . '</b>',
83
- '<b>' . $current_user->user_login . '</b>',
84
- '<a href="' . $site_url . '" target="_blank">' . $site_url . '</a>',
85
- '<a href="' . $freemius_site_url . '" target="_blank">freemius.com</a>'
86
- ),
87
- $first_name,
88
- $fs->get_plugin_name(),
89
- $current_user->user_login,
90
- '<a href="' . $site_url . '" target="_blank">' . $site_url . '</a>',
91
- '<a href="' . $freemius_site_url . '" target="_blank">freemius.com</a>'
92
- );
93
- }
94
- ?></p>
95
- </div>
96
- <div class="fs-actions">
97
- <?php if ( $fs->enable_anonymous() && ! $is_pending_activation ) : ?>
98
- <a href="<?php echo wp_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $slug . '_skip_activation' ) ), $slug . '_skip_activation' ) ?>"
99
- class="button button-secondary" tabindex="2"><?php _efs( 'skip', $slug ) ?></a>
100
- <?php endif ?>
101
-
102
- <?php $fs_user = Freemius::_get_user_by_email( $current_user->user_email ) ?>
103
- <?php if ( is_object( $fs_user ) && ! $is_pending_activation ) : ?>
104
- <form action="" method="POST">
105
- <input type="hidden" name="fs_action" value="<?php echo $slug ?>_activate_existing">
106
- <?php wp_nonce_field( 'activate_existing_' . $fs->get_public_key() ) ?>
107
- <button class="button button-primary" tabindex="1"
108
- type="submit"><?php _efs( 'opt-in-connect', $slug ) ?></button>
109
- </form>
110
- <?php else : ?>
111
- <form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
112
- <?php
113
- $params = array(
114
- 'user_firstname' => $current_user->user_firstname,
115
- 'user_lastname' => $current_user->user_lastname,
116
- 'user_nickname' => $current_user->user_nicename,
117
- 'user_email' => $current_user->user_email,
118
- 'user_ip' => WP_FS__REMOTE_ADDR,
119
- 'plugin_slug' => $slug,
120
- 'plugin_id' => $fs->get_id(),
121
- 'plugin_public_key' => $fs->get_public_key(),
122
- 'plugin_version' => $fs->get_plugin_version(),
123
- 'return_url' => wp_nonce_url( $fs->_get_admin_page_url(
124
- '',
125
- array( 'fs_action' => $slug . '_activate_new' )
126
- ), $slug . '_activate_new' ),
127
- 'account_url' => wp_nonce_url( $fs->_get_admin_page_url(
128
- 'account',
129
- array( 'fs_action' => 'sync_user' )
130
- ), 'sync_user' ),
131
- 'site_uid' => $fs->get_anonymous_id(),
132
- 'site_url' => get_site_url(),
133
- 'site_name' => get_bloginfo( 'name' ),
134
- 'platform_version' => get_bloginfo( 'version' ),
135
- 'php_version' => phpversion(),
136
- 'language' => get_bloginfo( 'language' ),
137
- 'charset' => get_bloginfo( 'charset' ),
138
- );
139
-
140
- if ( WP_FS__SKIP_EMAIL_ACTIVATION && $fs->has_secret_key() ) {
141
- // Even though rand() is known for its security issues,
142
- // the timestamp adds another layer of protection.
143
- // It would be very hard for an attacker to get the secret key form here.
144
- // Plus, this should never run in production since the secret should never
145
- // be included in the production version.
146
- $params['ts'] = WP_FS__SCRIPT_START_TIME;
147
- $params['salt'] = md5( uniqid( rand() ) );
148
- $params['secure'] = md5(
149
- $params['ts'] .
150
- $params['salt'] .
151
- $fs->get_secret_key()
152
- );
153
- }
154
- ?>
155
- <?php foreach ( $params as $name => $value ) : ?>
156
- <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
157
- <?php endforeach ?>
158
- <button class="button button-primary" tabindex="1"
159
- type="submit"><?php _efs( $is_pending_activation ? 'resend-activation-email' : 'opt-in-connect', $slug ) ?></button>
160
- </form>
161
- <?php endif ?>
162
- </div><?php
163
-
164
- // Set core permission list items.
165
- $permissions = array(
166
- 'profile' => array(
167
- 'icon-class' => 'dashicons dashicons-admin-users',
168
- 'label' => __fs( 'permissions-profile' ),
169
- 'desc' => __fs( 'permissions-profile_desc' ),
170
- 'priority' => 5,
171
- ),
172
- 'site' => array(
173
- 'icon-class' => 'dashicons dashicons-wordpress',
174
- 'label' => __fs( 'permissions-site' ),
175
- 'desc' => __fs( 'permissions-site_desc' ),
176
- 'priority' => 10,
177
- ),
178
- 'events' => array(
179
- 'icon-class' => 'dashicons dashicons-admin-plugins',
180
- 'label' => __fs( 'permissions-events' ),
181
- 'desc' => __fs( 'permissions-events_desc' ),
182
- 'priority' => 20,
183
- ),
184
- );
185
-
186
- // Add newsletter permissions if enabled.
187
- if ( $fs->is_permission_requested( 'newsletter' ) ) {
188
- $permissions['newsletter'] = array(
189
- 'icon-class' => 'dashicons dashicons-email-alt',
190
- 'label' => __fs( 'permissions-newsletter' ),
191
- 'desc' => __fs( 'permissions-newsletter_desc' ),
192
- 'priority' => 15,
193
- );
194
- }
195
-
196
- // Allow filtering of the permissions list.
197
- $permissions = $fs->apply_filters( 'permission_list', $permissions );
198
-
199
- // Sort by priority.
200
- uasort( $permissions, 'fs_sort_by_priority' );
201
-
202
- if ( ! empty( $permissions ) ) : ?>
203
- <div class="fs-permissions">
204
- <a class="fs-trigger" href="#"><?php _efs( 'what-permissions', $slug ) ?></a>
205
- <ul><?php
206
- foreach ( $permissions as $id => $permission ) : ?>
207
- <li id="fs-permission-<?php esc_attr_e( $id ); ?>"
208
- class="fs-permission fs-<?php esc_attr_e( $id ); ?>">
209
- <i class="<?php esc_attr_e( $permission['icon-class'] ); ?>"></i>
210
-
211
- <div>
212
- <span><?php esc_html_e( $permission['label'] ); ?></span>
213
-
214
- <p><?php esc_html_e( $permission['desc'] ); ?></p>
215
- </div>
216
- </li>
217
- <?php endforeach; ?>
218
- </ul>
219
- </div>
220
- <?php endif; ?>
221
-
222
- <div class="fs-terms">
223
- <a href="https://freemius.com/privacy/" target="_blank"><?php _efs( 'privacy-policy', $slug ) ?></a>
224
- &nbsp;&nbsp;-&nbsp;&nbsp;
225
- <a href="https://freemius.com/terms/" target="_blank"><?php _efs( 'tos', $slug ) ?></a>
226
- </div>
227
- </div>
228
- <script type="text/javascript">
229
- (function ($) {
230
- $('.button').on('click', function () {
231
- // Set loading mode.
232
- $(document.body).css({'cursor': 'wait'});
233
- });
234
- $('.button.button-primary').on('click', function () {
235
- $(this).addClass('fs-loading');
236
- $(this).html('<?php _efs( $is_pending_activation ? 'sending-email' : 'activating' , $slug ) ?>...').css({'cursor': 'wait'});
237
- });
238
- $('.fs-permissions .fs-trigger').on('click', function () {
239
- $('.fs-permissions').toggleClass('fs-open');
240
- });
241
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  </script>
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
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+ $is_pending_activation = $fs->is_pending_activation();
19
+ $is_premium_only = $fs->is_only_premium();
20
+ $has_paid_plans = $fs->has_paid_plan();
21
+ $is_premium_code = $fs->is_premium();
22
+ $is_freemium = $fs->is_freemium();
23
+
24
+ $fs->_enqueue_connect_essentials();
25
+
26
+ $current_user = Freemius::_get_current_wp_user();
27
+
28
+ $first_name = $current_user->user_firstname;
29
+ if ( empty( $first_name ) ) {
30
+ $first_name = $current_user->nickname;
31
+ }
32
+
33
+ $site_url = get_site_url();
34
+ $protocol_pos = strpos( $site_url, '://' );
35
+ if ( false !== $protocol_pos ) {
36
+ $site_url = substr( $site_url, $protocol_pos + 3 );
37
+ }
38
+
39
+ $freemius_site_url = $fs->has_paid_plan() ?
40
+ 'https://freemius.com/wordpress/' :
41
+ // Insights platform information.
42
+ 'https://freemius.com/wordpress/usage-tracking/';
43
+
44
+ $freemius_site_url .= '?' . http_build_query( array(
45
+ 'id' => $fs->get_id(),
46
+ 'slug' => $slug,
47
+ ) );
48
+
49
+ $freemius_link = '<a href="' . $freemius_site_url . '" target="_blank" tabindex="1">freemius.com</a>';
50
+
51
+ $error = fs_request_get( 'error' );
52
+
53
+ $require_license_key = $is_premium_only ||
54
+ ( $is_freemium && $is_premium_code && fs_request_get_bool( 'require_license', true ) );
55
+
56
+ if ( $is_pending_activation ) {
57
+ $require_license_key = false;
58
+ }
59
+
60
+ if ( $require_license_key ) {
61
+ $fs->_require_license_activation_dialog();
62
+ }
63
+ ?>
64
+ <div id="fs_connect"
65
+ class="wrap<?php if ( ! $fs->is_enable_anonymous() || $is_pending_activation || $require_license_key ) {
66
+ echo ' fs-anonymous-disabled';
67
+ } ?>">
68
+ <div class="fs-visual">
69
+ <b class="fs-site-icon"><i class="dashicons dashicons-wordpress"></i></b>
70
+ <i class="dashicons dashicons-plus fs-first"></i>
71
+ <?php
72
+ $vars = array( 'slug' => $slug );
73
+ fs_require_once_template( 'plugin-icon.php', $vars );
74
+ ?>
75
+ <i class="dashicons dashicons-plus fs-second"></i>
76
+ <img class="fs-connect-logo" width="80" height="80" src="//img.freemius.com/connect-logo.png"/>
77
+ </div>
78
+ <div class="fs-content">
79
+ <?php if ( ! empty( $error ) ) : ?>
80
+ <p class="fs-error"><?php echo $error ?></p>
81
+ <?php endif ?>
82
+ <p><?php
83
+ $button_label = 'opt-in-connect';
84
+
85
+ if ( $is_pending_activation ) {
86
+ $button_label = 'resend-activation-email';
87
+
88
+ echo $fs->apply_filters( 'pending_activation_message', sprintf(
89
+ __fs( 'thanks-x', $slug ) . '<br>' .
90
+ __fs( 'pending-activation-message', $slug ),
91
+ $first_name,
92
+ '<b>' . $fs->get_plugin_name() . '</b>',
93
+ '<b>' . $current_user->user_email . '</b>'
94
+ ) );
95
+ } else if ( $require_license_key ) {
96
+ $button_label = 'agree-activate-license';
97
+
98
+ echo $fs->apply_filters( 'connect-message_on-premium',
99
+ sprintf( __fs( 'hey-x', $slug ), $first_name ) . '<br>' .
100
+ sprintf( __fs( 'thanks-for-purchasing', $slug ), '<b>' . $fs->get_plugin_name() . '</b>' ),
101
+ $first_name,
102
+ $fs->get_plugin_name()
103
+ );
104
+ } else {
105
+ $filter = 'connect_message';
106
+ $default_optin_message = 'connect-message';
107
+
108
+ if ( $fs->is_plugin_update() ) {
109
+ // If Freemius was added on a plugin update, set different
110
+ // opt-in message.
111
+ $default_optin_message = 'connect-message_on-update';
112
+
113
+ // If user customized the opt-in message on update, use
114
+ // that message. Otherwise, fallback to regular opt-in
115
+ // custom message if exist.
116
+ if ( $fs->has_filter( 'connect_message_on_update' ) ) {
117
+ $filter = 'connect_message_on_update';
118
+ }
119
+ }
120
+
121
+ echo $fs->apply_filters( $filter,
122
+ sprintf(
123
+ __fs( 'hey-x', $slug ) . '<br>' .
124
+ __fs( $default_optin_message, $slug ),
125
+ $first_name,
126
+ '<b>' . $fs->get_plugin_name() . '</b>',
127
+ '<b>' . $current_user->user_login . '</b>',
128
+ '<a href="' . $site_url . '" target="_blank">' . $site_url . '</a>',
129
+ $freemius_link
130
+ ),
131
+ $first_name,
132
+ $fs->get_plugin_name(),
133
+ $current_user->user_login,
134
+ '<a href="' . $site_url . '" target="_blank">' . $site_url . '</a>',
135
+ $freemius_link
136
+ );
137
+ }
138
+ ?></p>
139
+ <?php if ( $require_license_key ) : ?>
140
+ <div class="fs-license-key-container">
141
+ <input id="fs_license_key" name="fs_key" type="text" required maxlength="32"
142
+ placeholder="<?php _efs( 'license-key', $slug ) ?>" tabindex="1"/>
143
+ <i class="dashicons dashicons-admin-network"></i>
144
+ <a class="show-license-resend-modal show-license-resend-modal-<?php echo $slug; ?>"
145
+ href="#"><?php _efs( 'cant-find-license-key' ); ?></a>
146
+ </div>
147
+ <?php endif ?>
148
+ </div>
149
+ <div class="fs-actions">
150
+ <?php if ( $fs->is_enable_anonymous() && ! $is_pending_activation && ! $require_license_key ) : ?>
151
+ <a href="<?php echo wp_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $slug . '_skip_activation' ) ), $slug . '_skip_activation' ) ?>"
152
+ class="button button-secondary" tabindex="2"><?php _efs( 'skip', $slug ) ?></a>
153
+ <?php endif ?>
154
+
155
+ <?php $fs_user = Freemius::_get_user_by_email( $current_user->user_email ) ?>
156
+ <?php if ( is_object( $fs_user ) && ! $is_pending_activation ) : ?>
157
+ <form action="" method="POST">
158
+ <input type="hidden" name="fs_action" value="<?php echo $slug ?>_activate_existing">
159
+ <?php wp_nonce_field( 'activate_existing_' . $fs->get_public_key() ) ?>
160
+ <button class="button button-primary" tabindex="1"
161
+ type="submit"<?php if ( $require_license_key ) {
162
+ echo ' disabled="disabled"';
163
+ } ?>><?php _efs( $button_label, $slug ) ?></button>
164
+ </form>
165
+ <?php else : ?>
166
+ <form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
167
+ <?php $params = $fs->get_opt_in_params() ?>
168
+ <?php foreach ( $params as $name => $value ) : ?>
169
+ <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
170
+ <?php endforeach ?>
171
+ <button class="button button-primary" tabindex="1"
172
+ type="submit"<?php if ( $require_license_key ) {
173
+ echo ' disabled="disabled"';
174
+ } ?>><?php _efs( $button_label, $slug ) ?></button>
175
+ </form>
176
+ <?php endif ?>
177
+ </div><?php
178
+
179
+ // Set core permission list items.
180
+ $permissions = array(
181
+ 'profile' => array(
182
+ 'icon-class' => 'dashicons dashicons-admin-users',
183
+ 'label' => __fs( 'permissions-profile' ),
184
+ 'desc' => __fs( 'permissions-profile_desc' ),
185
+ 'priority' => 5,
186
+ ),
187
+ 'site' => array(
188
+ 'icon-class' => 'dashicons dashicons-admin-settings',
189
+ 'label' => __fs( 'permissions-site' ),
190
+ 'desc' => __fs( 'permissions-site_desc' ),
191
+ 'priority' => 10,
192
+ ),
193
+ 'events' => array(
194
+ 'icon-class' => 'dashicons dashicons-admin-plugins',
195
+ 'label' => __fs( 'permissions-events' ),
196
+ 'desc' => __fs( 'permissions-events_desc' ),
197
+ 'priority' => 20,
198
+ ),
199
+ // 'plugins_themes' => array(
200
+ // 'icon-class' => 'dashicons dashicons-admin-settings',
201
+ // 'label' => __fs( 'permissions-plugins_themes' ),
202
+ // 'desc' => __fs( 'permissions-plugins_themes_desc' ),
203
+ // 'priority' => 30,
204
+ // ),
205
+ );
206
+
207
+ // Add newsletter permissions if enabled.
208
+ if ( $fs->is_permission_requested( 'newsletter' ) ) {
209
+ $permissions['newsletter'] = array(
210
+ 'icon-class' => 'dashicons dashicons-email-alt',
211
+ 'label' => __fs( 'permissions-newsletter' ),
212
+ 'desc' => __fs( 'permissions-newsletter_desc' ),
213
+ 'priority' => 15,
214
+ );
215
+ }
216
+
217
+ // Allow filtering of the permissions list.
218
+ $permissions = $fs->apply_filters( 'permission_list', $permissions );
219
+
220
+ // Sort by priority.
221
+ uasort( $permissions, 'fs_sort_by_priority' );
222
+
223
+ if ( ! empty( $permissions ) ) : ?>
224
+ <div class="fs-permissions">
225
+ <?php if ( $require_license_key ) : ?>
226
+ <p class="fs-license-sync-disclaimer"><?php printf( __fs( 'license-sync-disclaimer', $slug ), $freemius_link ) ?></p>
227
+ <?php endif ?>
228
+ <a class="fs-trigger" href="#" tabindex="1"><?php _efs( 'what-permissions', $slug ) ?></a>
229
+ <ul><?php
230
+ foreach ( $permissions as $id => $permission ) : ?>
231
+ <li id="fs-permission-<?php esc_attr_e( $id ); ?>"
232
+ class="fs-permission fs-<?php esc_attr_e( $id ); ?>">
233
+ <i class="<?php esc_attr_e( $permission['icon-class'] ); ?>"></i>
234
+
235
+ <div>
236
+ <span><?php esc_html_e( $permission['label'] ); ?></span>
237
+
238
+ <p><?php esc_html_e( $permission['desc'] ); ?></p>
239
+ </div>
240
+ </li>
241
+ <?php endforeach; ?>
242
+ </ul>
243
+ </div>
244
+ <?php endif ?>
245
+ <?php if ( $is_premium_code && $is_freemium ) : ?>
246
+ <div class="fs-freemium-licensing">
247
+ <p>
248
+ <?php if ( $require_license_key ) : ?>
249
+ <?php _efs( 'dont-have-license-key', $slug ) ?>
250
+ <a data-require-license="false" tabindex="1"><?php _efs( 'activate-free-version', $slug ) ?></a>
251
+ <?php else : ?>
252
+ <?php _efs( 'have-license-key', $slug ) ?>
253
+ <a data-require-license="true" tabindex="1"><?php _efs( 'activate-license', $slug ) ?></a>
254
+ <?php endif ?>
255
+ </p>
256
+ </div>
257
+ <?php endif ?>
258
+ <div class="fs-terms">
259
+ <a href="https://freemius.com/privacy/" target="_blank"
260
+ tabindex="1"><?php _efs( 'privacy-policy', $slug ) ?></a>
261
+ &nbsp;&nbsp;-&nbsp;&nbsp;
262
+ <a href="https://freemius.com/terms/" target="_blank" tabindex="1"><?php _efs( 'tos', $slug ) ?></a>
263
+ </div>
264
+ </div>
265
+ <script type="text/javascript">
266
+ (function ($) {
267
+ var $primaryCta = $('.fs-actions .button.button-primary'),
268
+ $form = $('.fs-actions form'),
269
+ requireLicenseKey = <?php echo $require_license_key ? 'true' : 'false' ?>,
270
+ $licenseSecret,
271
+ $licenseKeyInput = $('#fs_license_key');
272
+
273
+ $('.fs-actions .button').on('click', function () {
274
+ // Set loading mode.
275
+ $(document.body).css({'cursor': 'wait'});
276
+ });
277
+
278
+ $form.on('submit', function () {
279
+ /**
280
+ * @author Vova Feldman (@svovaf)
281
+ * @since 1.1.9
282
+ */
283
+ if (requireLicenseKey) {
284
+ if (null == $licenseSecret) {
285
+ $licenseSecret = $('<input type="hidden" name="license_secret_key" value="" />');
286
+ $form.append($licenseSecret);
287
+ }
288
+
289
+ // Update secret key if premium only plugin.
290
+ $licenseSecret.val($licenseKeyInput.val());
291
+ }
292
+
293
+ return true;
294
+ });
295
+
296
+ $primaryCta.on('click', function () {
297
+ $(this).addClass('fs-loading');
298
+ $(this).html('<?php _efs( $is_pending_activation ? 'sending-email' : 'activating' , $slug ) ?>...').css({'cursor': 'wait'});
299
+ });
300
+
301
+ $('.fs-permissions .fs-trigger').on('click', function () {
302
+ $('.fs-permissions').toggleClass('fs-open');
303
+ });
304
+
305
+ if (requireLicenseKey) {
306
+ /**
307
+ * Submit license key on enter.
308
+ *
309
+ * @author Vova Feldman (@svovaf)
310
+ * @since 1.1.9
311
+ */
312
+ $licenseKeyInput.keypress(function (e) {
313
+ if (e.which == 13) {
314
+ if ('' !== $(this).val()) {
315
+ $primaryCta.click();
316
+ return false;
317
+ }
318
+ }
319
+ });
320
+
321
+ /**
322
+ * Disable activation button when empty license key.
323
+ *
324
+ * @author Vova Feldman (@svovaf)
325
+ * @since 1.1.9
326
+ */
327
+ $licenseKeyInput.on('keyup paste delete cut', function () {
328
+ setTimeout(function () {
329
+ if ('' === $licenseKeyInput.val()) {
330
+ $primaryCta.attr('disabled', 'disabled');
331
+ } else {
332
+ $primaryCta.prop('disabled', false);
333
+ }
334
+ }, 100);
335
+ }).focus();
336
+ }
337
+
338
+ /**
339
+ * Set license mode trigger URL.
340
+ *
341
+ * @author Vova Feldman (@svovaf)
342
+ * @since 1.1.9
343
+ */
344
+ var $connectLicenseModeTrigger = $('#fs_connect .fs-freemium-licensing a');
345
+ if ($connectLicenseModeTrigger.length > 0) {
346
+ $connectLicenseModeTrigger.attr('href', window.location.href + '&require_license=' + $connectLicenseModeTrigger.attr('data-require-license'))
347
+ }
348
+ })(jQuery);
349
  </script>
freemius/templates/contact.php CHANGED
@@ -16,6 +16,9 @@
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
  fs_enqueue_local_style( 'fs_checkout', '/admin/common.css' );
18
 
 
 
 
19
  $slug = $VARS['slug'];
20
  $fs = freemius( $slug );
21
 
@@ -74,4 +77,12 @@
74
  })(jQuery);
75
  </script>
76
  </div>
77
- <?php fs_require_template( 'powered-by.php' ) ?>
 
 
 
 
 
 
 
 
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
  fs_enqueue_local_style( 'fs_checkout', '/admin/common.css' );
18
 
19
+ /**
20
+ * @var array $VARS
21
+ */
22
  $slug = $VARS['slug'];
23
  $fs = freemius( $slug );
24
 
77
  })(jQuery);
78
  </script>
79
  </div>
80
+ <?php
81
+ $params = array(
82
+ 'page' => 'contact',
83
+ 'module_id' => $fs->get_id(),
84
+ 'module_slug' => $slug,
85
+ 'module_version' => $fs->get_plugin_version(),
86
+ );
87
+ fs_require_template( 'powered-by.php', $params );
88
+ ?>
freemius/templates/deactivation-feedback-modal.php CHANGED
@@ -10,192 +10,192 @@
10
  exit;
11
  }
12
 
13
- $slug = $VARS['slug'];
14
- $fs = freemius( $slug );
15
-
16
- $confirmation_message = $fs->apply_filters( 'uninstall_confirmation_message', '' );
17
-
18
- $reasons = $VARS['reasons'];
19
-
20
- $reasons_list_items_html = '';
21
 
22
  foreach ( $reasons as $reason ) {
23
  $list_item_classes = 'reason' . ( ! empty( $reason['input_type'] ) ? ' has-input' : '' );
24
  $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>';
25
  }
26
- ?>
27
- <script type="text/javascript">
28
- (function( $ ) {
29
- var reasonsHtml = <?php echo json_encode( $reasons_list_items_html ); ?>,
30
- modalHtml =
31
- '<div class="fs-modal<?php echo empty( $confirmation_message ) ? ' no-confirmation-message' : ''; ?>">'
32
- + ' <div class="fs-modal-dialog">'
33
- + ' <div class="fs-modal-body">'
34
- + ' <div class="fs-modal-panel" data-panel-id="confirm"><p><?php echo $confirmation_message; ?></p></div>'
35
- + ' <div class="fs-modal-panel active" data-panel-id="reasons"><h3><strong><?php printf( __fs( 'deactivation-share-reason' , $slug ) ); ?>:</strong></h3><ul id="reasons-list">' + reasonsHtml + '</ul></div>'
36
- + ' </div>'
37
- + ' <div class="fs-modal-footer">'
38
- + ' <a href="#" class="button button-secondary button-deactivate"></a>'
39
- + ' <a href="#" class="button button-primary button-close"><?php printf( __fs( 'deactivation-modal-button-cancel' , $slug ) ); ?></a>'
40
- + ' </div>'
41
- + ' </div>'
42
- + '</div>',
43
- $modal = $( modalHtml ),
44
- $deactivateLink = $( '#the-list .deactivate > [data-slug=<?php echo $VARS['slug']; ?>].fs-slug' ).prev();
45
-
46
- $modal.appendTo( $( 'body' ) );
47
-
48
- registerEventHandlers();
49
-
50
- function registerEventHandlers() {
51
- $deactivateLink.click(function ( evt ) {
52
- evt.preventDefault();
53
-
54
- showModal();
55
- });
56
-
57
- $modal.on( 'click', '.button', function( evt ) {
58
- evt.preventDefault();
59
-
60
- if ( $( this ).hasClass( 'disabled' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
61
  return;
62
  }
63
-
64
- var _parent = $( this ).parents( '.fs-modal:first' );
65
- var _this = $( this );
66
-
67
- if ( _this.hasClass( 'allow-deactivate' ) ) {
68
- var $radio = $( 'input[type="radio"]:checked' );
69
-
70
- if ( 0 === $radio.length ) {
71
- // If no selected reason, just deactivate the plugin.
72
- window.location.href = $deactivateLink.attr( 'href' );
73
- return;
 
 
 
 
 
 
 
 
74
  }
75
-
76
- var $selected_reason = $radio.parents( 'li:first' ),
77
- $input = $selected_reason.find( 'textarea, input[type="text"]' );
78
-
79
- $.ajax({
80
- url: ajaxurl,
81
- method: 'POST',
82
- data: {
83
- 'action' : 'submit-uninstall-reason',
84
- 'reason_id' : $radio.val(),
85
- 'reason_info' : ( 0 !== $input.length ) ? $input.val().trim() : ''
86
- },
87
- beforeSend: function() {
88
- _parent.find( '.button' ).addClass( 'disabled' );
89
- _parent.find( '.button-secondary' ).text( 'Processing...' );
90
- },
91
- complete: function() {
92
- // Do not show the dialog box, deactivate the plugin.
93
- window.location.href = $deactivateLink.attr( 'href' );
94
- }
95
- });
96
- } else if ( _this.hasClass( 'button-deactivate' ) ) {
97
- // Change the Deactivate button's text and show the reasons panel.
98
- _parent.find( '.button-deactivate').addClass( 'allow-deactivate' );
99
-
100
- showPanel( 'reasons' );
101
- }
102
- });
103
-
104
- $modal.on( 'click', 'input[type="radio"]', function() {
105
- var _parent = $( this ).parents( 'li:first' );
106
-
107
- $modal.find( '.reason-input' ).remove();
108
- $modal.find( '.button-deactivate').text( '<?php printf( __fs( 'deactivation-modal-button-submit' , $slug ) ); ?>' );
109
-
110
- if ( _parent.hasClass( 'has-input' ) ) {
111
- var inputType = _parent.data( 'input-type' ),
112
- inputPlaceholder = _parent.data( 'input-placeholder' ),
113
- reasonInputHtml = '<div class="reason-input">' + ( ( 'textfield' === inputType ) ? '<input type="text" />' : '<textarea rows="5"></textarea>' ) + '</div>';
114
-
115
- _parent.append( $( reasonInputHtml ) );
116
- _parent.find( 'input, textarea' ).attr( 'placeholder', inputPlaceholder ).focus();
117
- }
118
- });
119
-
120
- // If the user has clicked outside the window, cancel it.
121
- $modal.on( 'click', function( evt ) {
122
- var $target = $( evt.target );
123
-
124
- // If the user has clicked anywhere in the modal dialog, just return.
125
- if ( $target.hasClass( 'fs-modal-body' ) || $target.hasClass( 'fs-modal-footer' ) ) {
126
- return;
127
- }
128
-
129
- // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return.
130
- if ( ! $target.hasClass( 'button-close' ) && ( $target.parents( '.fs-modal-body').length > 0 || $target.parents( '.fs-modal-footer').length > 0 ) ) {
131
- return;
132
- }
133
-
134
- closeModal();
135
- });
136
- }
137
-
138
- function showModal() {
139
- resetModal();
140
-
141
- // Display the dialog box.
142
- $modal.addClass( 'active' );
143
-
144
- $( 'body' ).addClass( 'has-fs-modal' );
145
- }
146
-
147
- function closeModal() {
148
- $modal.removeClass( 'active' );
149
-
150
- $( 'body' ).removeClass( 'has-fs-modal' );
151
- }
152
-
153
- function resetModal() {
154
- $modal.find( '.button' ).removeClass( 'disabled' );
155
-
156
- // Uncheck all radio buttons.
157
- $modal.find( 'input[type="radio"]' ).prop( 'checked', false );
158
-
159
- // Remove all input fields ( textfield, textarea ).
160
- $modal.find( '.reason-input' ).remove();
161
-
162
- var $deactivateButton = $modal.find( '.button-deactivate' );
163
-
164
- /*
165
- * If the modal dialog has no confirmation message, that is, it has only one panel, then ensure
166
- * that clicking the deactivate button will actually deactivate the plugin.
167
- */
168
- if ( $modal.hasClass( 'no-confirmation-message' ) ) {
169
- $deactivateButton.addClass( 'allow-deactivate' );
170
-
171
- showPanel( 'reasons' );
172
- } else {
173
- $deactivateButton.removeClass( 'allow-deactivate' );
174
-
175
- showPanel( 'confirm' );
176
  }
177
- }
178
-
179
- function showPanel( panelType ) {
180
- $modal.find( '.fs-modal-panel' ).removeClass( 'active ');
181
- $modal.find( '[data-panel-id="' + panelType + '"]' ).addClass( 'active' );
182
-
183
- updateButtonLabels();
184
- }
185
-
186
- function updateButtonLabels() {
187
- var $deactivateButton = $modal.find( '.button-deactivate' );
188
-
189
- // Reset the deactivate button's text.
190
- if ( 'confirm' === getCurrentPanel() ) {
191
- $deactivateButton.text( '<?php printf( __fs( 'deactivation-modal-button-confirm' , $slug ) ); ?>' );
192
- } else {
193
- $deactivateButton.text( '<?php printf( __fs( 'deactivation-modal-button-deactivate' , $slug ) ); ?>' );
194
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
196
-
197
- function getCurrentPanel() {
198
- return $modal.find( '.fs-modal-panel.active' ).attr( 'data-panel-id' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  }
200
- })( jQuery );
201
- </script>
 
 
 
 
 
10
  exit;
11
  }
12
 
13
+ $slug = $VARS['slug'];
14
+ $fs = freemius( $slug );
15
+
16
+ $confirmation_message = $fs->apply_filters( 'uninstall_confirmation_message', '' );
17
+
18
+ $reasons = $VARS['reasons'];
19
+
20
+ $reasons_list_items_html = '';
21
 
22
  foreach ( $reasons as $reason ) {
23
  $list_item_classes = 'reason' . ( ! empty( $reason['input_type'] ) ? ' has-input' : '' );
24
  $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>';
25
  }
26
+ ?>
27
+ <script type="text/javascript">
28
+ (function ($) {
29
+ var reasonsHtml = <?php echo json_encode( $reasons_list_items_html ); ?>,
30
+ modalHtml =
31
+ '<div class="fs-modal<?php echo empty( $confirmation_message ) ? ' no-confirmation-message' : ''; ?>">'
32
+ + ' <div class="fs-modal-dialog">'
33
+ + ' <div class="fs-modal-body">'
34
+ + ' <div class="fs-modal-panel" data-panel-id="confirm"><p><?php echo $confirmation_message; ?></p></div>'
35
+ + ' <div class="fs-modal-panel active" data-panel-id="reasons"><h3><strong><?php printf( __fs( 'deactivation-share-reason' , $slug ) ); ?>:</strong></h3><ul id="reasons-list">' + reasonsHtml + '</ul></div>'
36
+ + ' </div>'
37
+ + ' <div class="fs-modal-footer">'
38
+ + ' <a href="#" class="button button-secondary button-deactivate"></a>'
39
+ + ' <a href="#" class="button button-primary button-close"><?php printf( __fs( 'deactivation-modal-button-cancel' , $slug ) ); ?></a>'
40
+ + ' </div>'
41
+ + ' </div>'
42
+ + '</div>',
43
+ $modal = $(modalHtml),
44
+ $deactivateLink = $('#the-list .deactivate > [data-slug=<?php echo $VARS['slug']; ?>].fs-slug').prev();
45
+
46
+ $modal.appendTo($('body'));
47
+
48
+ registerEventHandlers();
49
+
50
+ function registerEventHandlers() {
51
+ $deactivateLink.click(function (evt) {
52
+ evt.preventDefault();
53
+
54
+ showModal();
55
+ });
56
+
57
+ $modal.on('click', '.button', function (evt) {
58
+ evt.preventDefault();
59
+
60
+ if ($(this).hasClass('disabled')) {
61
+ return;
62
+ }
63
+
64
+ var _parent = $(this).parents('.fs-modal:first');
65
+ var _this = $(this);
66
+
67
+ if (_this.hasClass('allow-deactivate')) {
68
+ var $radio = $('input[type="radio"]:checked');
69
+
70
+ if (0 === $radio.length) {
71
+ // If no selected reason, just deactivate the plugin.
72
+ window.location.href = $deactivateLink.attr('href');
73
  return;
74
  }
75
+
76
+ var $selected_reason = $radio.parents('li:first'),
77
+ $input = $selected_reason.find('textarea, input[type="text"]');
78
+
79
+ $.ajax({
80
+ url : ajaxurl,
81
+ method : 'POST',
82
+ data : {
83
+ 'action' : 'submit-uninstall-reason',
84
+ 'reason_id' : $radio.val(),
85
+ 'reason_info': ( 0 !== $input.length ) ? $input.val().trim() : ''
86
+ },
87
+ beforeSend: function () {
88
+ _parent.find('.button').addClass('disabled');
89
+ _parent.find('.button-secondary').text('Processing...');
90
+ },
91
+ complete : function () {
92
+ // Do not show the dialog box, deactivate the plugin.
93
+ window.location.href = $deactivateLink.attr('href');
94
  }
95
+ });
96
+ } else if (_this.hasClass('button-deactivate')) {
97
+ // Change the Deactivate button's text and show the reasons panel.
98
+ _parent.find('.button-deactivate').addClass('allow-deactivate');
99
+
100
+ showPanel('reasons');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+ });
103
+
104
+ $modal.on('click', 'input[type="radio"]', function () {
105
+ var _parent = $(this).parents('li:first');
106
+
107
+ $modal.find('.reason-input').remove();
108
+ $modal.find('.button-deactivate').text('<?php printf( __fs( 'deactivation-modal-button-submit' , $slug ) ); ?>');
109
+
110
+ if (_parent.hasClass('has-input')) {
111
+ var inputType = _parent.data('input-type'),
112
+ inputPlaceholder = _parent.data('input-placeholder'),
113
+ reasonInputHtml = '<div class="reason-input">' + ( ( 'textfield' === inputType ) ? '<input type="text" />' : '<textarea rows="5"></textarea>' ) + '</div>';
114
+
115
+ _parent.append($(reasonInputHtml));
116
+ _parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
 
 
117
  }
118
+ });
119
+
120
+ // If the user has clicked outside the window, cancel it.
121
+ $modal.on('click', function (evt) {
122
+ var $target = $(evt.target);
123
+
124
+ // If the user has clicked anywhere in the modal dialog, just return.
125
+ if ($target.hasClass('fs-modal-body') || $target.hasClass('fs-modal-footer')) {
126
+ return;
127
+ }
128
+
129
+ // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return.
130
+ if (!$target.hasClass('button-close') && ( $target.parents('.fs-modal-body').length > 0 || $target.parents('.fs-modal-footer').length > 0 )) {
131
+ return;
132
+ }
133
+
134
+ closeModal();
135
+ });
136
+ }
137
+
138
+ function showModal() {
139
+ resetModal();
140
+
141
+ // Display the dialog box.
142
+ $modal.addClass('active');
143
+
144
+ $('body').addClass('has-fs-modal');
145
+ }
146
+
147
+ function closeModal() {
148
+ $modal.removeClass('active');
149
+
150
+ $('body').removeClass('has-fs-modal');
151
+ }
152
+
153
+ function resetModal() {
154
+ $modal.find('.button').removeClass('disabled');
155
+
156
+ // Uncheck all radio buttons.
157
+ $modal.find('input[type="radio"]').prop('checked', false);
158
+
159
+ // Remove all input fields ( textfield, textarea ).
160
+ $modal.find('.reason-input').remove();
161
+
162
+ var $deactivateButton = $modal.find('.button-deactivate');
163
+
164
+ /*
165
+ * If the modal dialog has no confirmation message, that is, it has only one panel, then ensure
166
+ * that clicking the deactivate button will actually deactivate the plugin.
167
+ */
168
+ if ($modal.hasClass('no-confirmation-message')) {
169
+ $deactivateButton.addClass('allow-deactivate');
170
+
171
+ showPanel('reasons');
172
+ } else {
173
+ $deactivateButton.removeClass('allow-deactivate');
174
+
175
+ showPanel('confirm');
176
  }
177
+ }
178
+
179
+ function showPanel(panelType) {
180
+ $modal.find('.fs-modal-panel').removeClass('active ');
181
+ $modal.find('[data-panel-id="' + panelType + '"]').addClass('active');
182
+
183
+ updateButtonLabels();
184
+ }
185
+
186
+ function updateButtonLabels() {
187
+ var $deactivateButton = $modal.find('.button-deactivate');
188
+
189
+ // Reset the deactivate button's text.
190
+ if ('confirm' === getCurrentPanel()) {
191
+ $deactivateButton.text('<?php printf( __fs( 'deactivation-modal-button-confirm' , $slug ) ); ?>');
192
+ } else {
193
+ $deactivateButton.text('<?php printf( __fs( 'deactivate' , $slug ) ); ?>');
194
  }
195
+ }
196
+
197
+ function getCurrentPanel() {
198
+ return $modal.find('.fs-modal-panel.active').attr('data-panel-id');
199
+ }
200
+ })(jQuery);
201
+ </script>
freemius/templates/debug.php CHANGED
@@ -15,6 +15,39 @@
15
  $fs_options = FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
16
  ?>
17
  <h1><?php echo __fs( 'Freemius Debug' ) . ' - ' . __fs( 'SDK' ) . ' v.' . $fs_active_plugins->newest->version ?></h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  <h2><?php _efs( 'actions' ) ?></h2>
19
  <table>
20
  <tbody>
@@ -22,8 +55,8 @@
22
  <td>
23
  <!-- Delete All Accounts -->
24
  <form action="" method="POST">
25
- <input type="hidden" name="fs_action" value="delete_all_accounts">
26
- <?php wp_nonce_field( 'delete_all_accounts' ) ?>
27
  <button class="button button-primary"
28
  onclick="if (confirm('<?php _efs( 'delete-all-confirm' ) ?>')) this.parentNode.submit(); return false;"><?php _efs( 'delete-all-accounts' ) ?></button>
29
  </form>
@@ -115,6 +148,7 @@
115
  <?php endif ?>
116
  <?php
117
  /**
 
118
  * @var FS_Site[] $sites
119
  */
120
  $sites = $VARS['sites'];
@@ -125,6 +159,7 @@
125
  <thead>
126
  <tr>
127
  <th><?php _efs( 'id' ) ?></th>
 
128
  <th><?php _efs( 'plan' ) ?></th>
129
  <th><?php _efs( 'public-key' ) ?></th>
130
  <th><?php _efs( 'secret-key' ) ?></th>
@@ -134,8 +169,11 @@
134
  <?php foreach ( $sites as $slug => $site ) : ?>
135
  <tr>
136
  <td><?php echo $site->id ?></td>
 
137
  <td><?php
138
- echo is_object( $site->plan ) ? $site->plan->name : ''
 
 
139
  ?></td>
140
  <td><?php echo $site->public_key ?></td>
141
  <td><?php echo $site->secret_key ?></td>
@@ -202,7 +240,7 @@
202
  <tr>
203
  <td><?php echo $user->id ?></td>
204
  <td><?php echo $user->get_name() ?></td>
205
- <td><?php echo $user->email ?></td>
206
  <td><?php echo json_encode( $user->is_verified ) ?></td>
207
  <td><?php echo $user->public_key ?></td>
208
  <td><?php echo $user->secret_key ?></td>
@@ -210,4 +248,49 @@
210
  <?php endforeach ?>
211
  </tbody>
212
  </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  <?php endif ?>
15
  $fs_options = FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
16
  ?>
17
  <h1><?php echo __fs( 'Freemius Debug' ) . ' - ' . __fs( 'SDK' ) . ' v.' . $fs_active_plugins->newest->version ?></h1>
18
+ <div>
19
+ <!-- Debugging Switch -->
20
+ <?php //$debug_mode = get_option( 'fs_debug_mode', null ) ?>
21
+ <span class="switch-label"><?php _efs( 'debugging' ) ?></span>
22
+
23
+ <div class="switch <?php echo WP_FS__DEBUG_SDK ? 'off' : 'on' ?>">
24
+ <div class="toggle"></div>
25
+ <span class="on"><?php _efs( 'on' ) ?></span>
26
+ <span class="off"><?php _efs( 'off' ) ?></span>
27
+ </div>
28
+ <script type="text/javascript">
29
+ (function ($) {
30
+ $(document).ready(function () {
31
+ // Switch toggle
32
+ $('.switch').click(function () {
33
+ $(this)
34
+ .toggleClass('on')
35
+ .toggleClass('off');
36
+
37
+ $.post(ajaxurl, {
38
+ action: 'fs_toggle_debug_mode',
39
+ is_on : ($(this).hasClass('off') ? 1 : 0)
40
+ }, function (response) {
41
+ if (1 == response) {
42
+ // Refresh page on success.
43
+ location.reload();
44
+ }
45
+ });
46
+ });
47
+ });
48
+ }(jQuery));
49
+ </script>
50
+ </div>
51
  <h2><?php _efs( 'actions' ) ?></h2>
52
  <table>
53
  <tbody>
55
  <td>
56
  <!-- Delete All Accounts -->
57
  <form action="" method="POST">
58
+ <input type="hidden" name="fs_action" value="restart_freemius">
59
+ <?php wp_nonce_field( 'restart_freemius' ) ?>
60
  <button class="button button-primary"
61
  onclick="if (confirm('<?php _efs( 'delete-all-confirm' ) ?>')) this.parentNode.submit(); return false;"><?php _efs( 'delete-all-accounts' ) ?></button>
62
  </form>
148
  <?php endif ?>
149
  <?php
150
  /**
151
+ * @var array $VARS
152
  * @var FS_Site[] $sites
153
  */
154
  $sites = $VARS['sites'];
159
  <thead>
160
  <tr>
161
  <th><?php _efs( 'id' ) ?></th>
162
+ <th><?php _efs( 'slug' ) ?></th>
163
  <th><?php _efs( 'plan' ) ?></th>
164
  <th><?php _efs( 'public-key' ) ?></th>
165
  <th><?php _efs( 'secret-key' ) ?></th>
169
  <?php foreach ( $sites as $slug => $site ) : ?>
170
  <tr>
171
  <td><?php echo $site->id ?></td>
172
+ <td><?php echo $slug ?></td>
173
  <td><?php
174
+ echo is_object( $site->plan ) ?
175
+ base64_decode( $site->plan->name ) :
176
+ ''
177
  ?></td>
178
  <td><?php echo $site->public_key ?></td>
179
  <td><?php echo $site->secret_key ?></td>
240
  <tr>
241
  <td><?php echo $user->id ?></td>
242
  <td><?php echo $user->get_name() ?></td>
243
+ <td><a href="mailto:<?php esc_attr_e( $user->email ) ?>"><?php echo $user->email ?></a></td>
244
  <td><?php echo json_encode( $user->is_verified ) ?></td>
245
  <td><?php echo $user->public_key ?></td>
246
  <td><?php echo $user->secret_key ?></td>
248
  <?php endforeach ?>
249
  </tbody>
250
  </table>
251
+ <?php endif ?>
252
+ <?php
253
+ /**
254
+ * @var FS_Plugin_License[] $licenses
255
+ */
256
+ $licenses = $VARS['licenses'];
257
+ ?>
258
+ <?php if ( is_array( $licenses ) && 0 < count( $licenses ) ) : ?>
259
+ <h2><?php _efs( 'licenses' ) ?></h2>
260
+ <table id="fs_users" class="widefat">
261
+ <thead>
262
+ <tr>
263
+ <th><?php _efs( 'id' ) ?></th>
264
+ <th><?php _efs( 'plugin-id' ) ?></th>
265
+ <th><?php _efs( 'user-id' ) ?></th>
266
+ <th><?php _efs( 'plan-id' ) ?></th>
267
+ <th><?php _efs( 'quota' ) ?></th>
268
+ <th><?php _efs( 'activated' ) ?></th>
269
+ <th><?php _efs( 'blocking' ) ?></th>
270
+ <th><?php _efs( 'license-key' ) ?></th>
271
+ <th><?php _efs( 'expiration' ) ?></th>
272
+ </tr>
273
+ </thead>
274
+ <tbody>
275
+ <?php foreach ( $licenses as $slug => $module_licenses ) : ?>
276
+ <?php foreach ( $module_licenses as $id => $licenses ) : ?>
277
+ <?php if ( is_array( $licenses ) && 0 < count( $licenses ) ) : ?>
278
+ <?php foreach ( $licenses as $license ) : ?>
279
+ <tr>
280
+ <td><?php echo $license->id ?></td>
281
+ <td><?php echo $license->plugin_id ?></td>
282
+ <td><?php echo $license->user_id ?></td>
283
+ <td><?php echo $license->plan_id ?></td>
284
+ <td><?php echo $license->is_unlimited() ? 'Unlimited' : ( $license->is_single_site() ? 'Single Site' : $license->quota ) ?></td>
285
+ <td><?php echo $license->activated ?></td>
286
+ <td><?php echo $license->is_block_features ? 'Blocking' : 'Flexible' ?></td>
287
+ <td><?php echo htmlentities( $license->secret_key ) ?></td>
288
+ <td><?php echo $license->expiration ?></td>
289
+ </tr>
290
+ <?php endforeach ?>
291
+ <?php endif ?>
292
+ <?php endforeach ?>
293
+ <?php endforeach ?>
294
+ </tbody>
295
+ </table>
296
  <?php endif ?>
freemius/templates/debug/api-calls.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ if ( class_exists( 'Freemius_Api' ) ) {
14
+ $logger = Freemius_Api::GetLogger();
15
+ } else {
16
+ $logger = array();
17
+ }
18
+
19
+ $counters = array(
20
+ 'GET' => 0,
21
+ 'POST' => 0,
22
+ 'PUT' => 0,
23
+ 'DELETE' => 0
24
+ );
25
+
26
+ $show_body = false;
27
+ foreach ( $logger as $log ) {
28
+ $counters[ $log['method'] ] ++;
29
+
30
+ if ( ! is_null( $log['body'] ) ) {
31
+ $show_body = true;
32
+ }
33
+ }
34
+
35
+ $pretty_print = $show_body && defined( 'JSON_PRETTY_PRINT' ) && version_compare( phpversion(), '5.3', '>=' );
36
+
37
+ $root_path_len = strlen( ABSPATH );
38
+ ?>
39
+ <h1><?php _efs( 'API' ) ?></h1>
40
+
41
+ <h2><span>Total Time:</span><?php echo Freemius_Debug_Bar_Panel::total_time() ?></h2>
42
+
43
+ <h2><span>Total Requests:</span><?php echo Freemius_Debug_Bar_Panel::requests_count() ?></h2>
44
+ <?php foreach ( $counters as $method => $count ) : ?>
45
+ <h2><span><?php echo $method ?>:</span><?php echo number_format( $count ) ?></h2>
46
+ <?php endforeach ?>
47
+ <table class="widefat">
48
+ <thead>
49
+ <tr>
50
+ <th>#</th>
51
+ <th><?php _efs( 'Method' ) ?></th>
52
+ <th><?php _efs( 'Code' ) ?></th>
53
+ <th><?php _efs( 'Length' ) ?></th>
54
+ <th><?php _efs( 'Path' ) ?></th>
55
+ <?php if ( $show_body ) : ?>
56
+ <th><?php _efs( 'Body' ) ?></th>
57
+ <?php endif ?>
58
+ <th><?php _efs( 'Result' ) ?></th>
59
+ <th><?php _efs( 'Start' ) ?></th>
60
+ <th><?php _efs( 'End' ) ?></th>
61
+ </tr>
62
+ </thead>
63
+ <tbody>
64
+ <?php foreach ( $logger as $log ) : ?>
65
+ <tr>
66
+ <td><?php echo $log['id'] ?>.</td>
67
+ <td><?php echo $log['method'] ?></td>
68
+ <td><?php echo $log['code'] ?></td>
69
+ <td><?php echo number_format( 100 * $log['total'], 2 ) . ' ' . __fs( 'ms' ) ?></td>
70
+ <td>
71
+ <?php
72
+ printf( '<a href="#" onclick="jQuery(this).parent().find(\'table\').toggle(); return false;">%s</a>',
73
+ $log['path']
74
+ );
75
+ ?>
76
+ <table class="widefat" style="display: none">
77
+ <tbody>
78
+ <?php for ( $i = 0, $bt = $log['backtrace'], $len = count( $bt ); $i < $len; $i ++ ) : ?>
79
+ <tr>
80
+ <td><?php echo( $len - $i ) ?></td>
81
+ <td><?php if ( isset( $bt[ $i ]['function'] ) ) {
82
+ echo ( isset( $bt[ $i ]['class'] ) ? $bt[ $i ]['class'] . $bt[ $i ]['type'] : '' ) . $bt[ $i ]['function'];
83
+ } ?></td>
84
+ <td><?php if ( isset( $bt[ $i ]['file'] ) ) {
85
+ echo substr( $bt[ $i ]['file'], $root_path_len ) . ':' . $bt[ $i ]['line'];
86
+ } ?></td>
87
+ </tr>
88
+ <?php endfor ?>
89
+ </tbody>
90
+ </table>
91
+ </td>
92
+ <?php if ( $show_body ) : ?>
93
+ <td>
94
+ <?php if ( 'GET' !== $log['method'] ) : ?>
95
+ <?php
96
+ $body = $log['body'];
97
+ printf(
98
+ '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>',
99
+ substr( $body, 0, 32 ) . ( 32 < strlen( $body ) ? '...' : '' )
100
+ );
101
+ if ( $pretty_print ) {
102
+ $body = json_encode( json_decode( $log['body'] ), JSON_PRETTY_PRINT );
103
+ }
104
+ ?>
105
+ <pre style="display: none"><code><?php echo esc_html( $body ) ?></code></pre>
106
+ <?php endif ?>
107
+ </td>
108
+ <?php endif ?>
109
+ <td>
110
+ <?php
111
+ $result = $log['result'];
112
+
113
+ $is_not_empty_result = ( is_string( $result ) && ! empty( $result ) );
114
+
115
+ if ( $is_not_empty_result ) {
116
+ printf(
117
+ '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>',
118
+ substr( $result, 0, 32 ) . ( 32 < strlen( $result ) ? '...' : '' )
119
+ );
120
+ }
121
+
122
+ if ( $is_not_empty_result && $pretty_print ) {
123
+ $decoded = json_decode( $result );
124
+ if ( ! is_null( $decoded ) ) {
125
+ $result = json_encode( $decoded, JSON_PRETTY_PRINT );
126
+ }
127
+ } else {
128
+ $result = is_string( $result ) ? $result : json_encode( $result );
129
+ }
130
+ ?>
131
+ <pre<?php if ( $is_not_empty_result ) : ?> style="display: none"<?php endif ?>><code><?php echo esc_html( $result ) ?></code></pre>
132
+ </td>
133
+ <td><?php echo number_format( 100 * ( $log['start'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . __fs( 'ms' ) ?></td>
134
+ <td><?php echo number_format( 100 * ( $log['end'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . __fs( 'ms' ) ?></td>
135
+ </tr>
136
+ <?php endforeach ?>
137
+ </tbody>
138
+ </table>
freemius/templates/debug/logger.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ $log_book = FS_Logger::get_log();
14
+ ?>
15
+ <h1><?php _efs( 'Log' ) ?></h1>
16
+
17
+ <table class="widefat" style="font-size: 11px;">
18
+ <thead>
19
+ <tr>
20
+ <th>#</th>
21
+ <th><?php _efs( 'id' ) ?></th>
22
+ <th><?php _efs( 'type' ) ?></th>
23
+ <th><?php _efs( 'function' ) ?></th>
24
+ <th><?php _efs( 'message' ) ?></th>
25
+ <th><?php _efs( 'file' ) ?></th>
26
+ <th><?php _efs( 'timestamp' ) ?></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+
31
+ <?php $i = 0;
32
+ foreach ( $log_book as $log ) : ?>
33
+ <?php
34
+ /**
35
+ * @var FS_Logger $logger
36
+ */
37
+ $logger = $log['logger'];
38
+ ?>
39
+ <tr<?php if ( $i % 2 ) {
40
+ echo ' class="alternate"';
41
+ } ?>>
42
+ <td><?php echo $log['cnt'] ?>.</td>
43
+ <td><?php echo $logger->get_id() ?></td>
44
+ <td><?php echo $log['type'] ?></td>
45
+ <td><b><code style="color: blue;"><?php echo $log['function'] ?></code></b></td>
46
+ <td>
47
+ <?php
48
+ printf(
49
+ '<a href="#" style="color: darkorange !important;" onclick="jQuery(this).parent().find(\'div\').toggle(); return false;"><nobr>%s</nobr></a>',
50
+ substr( $log['msg'], 0, 32 ) . ( 32 < strlen( $log['msg'] ) ? '...' : '' )
51
+ );
52
+ ?>
53
+ <div style="display: none;">
54
+ <b style="color: darkorange;"><?php echo $log['msg'] ?></b>
55
+ </div>
56
+ </td>
57
+ <td><?php
58
+ if ( isset( $log['file'] ) ) {
59
+ echo substr( $log['file'], $logger->get_file() ) . ':' . $log['line'] . ')';
60
+ }
61
+ ?></td>
62
+ <td><?php echo number_format( 100 * ( $log['timestamp'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . __fs( 'ms' ) ?></td>
63
+ </tr>
64
+ <?php $i ++; endforeach ?>
65
+ </tbody>
66
+ </table>
freemius/templates/debug/plugins-themes-sync.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ $fs_options = FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
14
+ $all_plugins = $fs_options->get_option( 'all_plugins' );
15
+ $all_themes = $fs_options->get_option( 'all_themes' );
16
+ ?>
17
+ <h1><?php _efs( 'plugins-themes-sync' ) ?></h1>
18
+ <table class="widefat">
19
+ <thead>
20
+ <tr>
21
+ <th></th>
22
+ <th><?php _efs( 'total' ) ?></th>
23
+ <th><?php _efs( 'Last' ) ?></th>
24
+ </tr>
25
+ </thead>
26
+ <tbody>
27
+ <?php if ( is_object( $all_plugins ) ) : ?>
28
+ <tr>
29
+ <td><?php _efs( 'plugins' ) ?></td>
30
+ <td><?php echo count( $all_plugins->plugins ) ?></td>
31
+ <td><?php
32
+ if ( isset( $all_plugins->timestamp ) && is_numeric( $all_plugins->timestamp ) ) {
33
+ $diff = abs( WP_FS__SCRIPT_START_TIME - $all_plugins->timestamp );
34
+ $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?
35
+ $diff . ' ' . __fs( 'sec' ) :
36
+ human_time_diff( WP_FS__SCRIPT_START_TIME, $all_plugins->timestamp );
37
+
38
+ if ( WP_FS__SCRIPT_START_TIME < $all_plugins->timestamp ) {
39
+ printf( __fs( 'in-x' ), $human_diff );
40
+ } else {
41
+ printf( __fs( 'x-ago' ), $human_diff );
42
+ }
43
+ }
44
+ ?></td>
45
+ </tr>
46
+ <?php endif ?>
47
+ <?php if ( is_object( $all_themes ) ) : ?>
48
+ <tr>
49
+ <td><?php _efs( 'themes' ) ?></td>
50
+ <td><?php echo count( $all_themes->themes ) ?></td>
51
+ <td><?php
52
+ if ( isset( $all_themes->timestamp ) && is_numeric( $all_themes->timestamp ) ) {
53
+ $diff = abs( WP_FS__SCRIPT_START_TIME - $all_themes->timestamp );
54
+ $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?
55
+ $diff . ' ' . __fs( 'sec' ) :
56
+ human_time_diff( WP_FS__SCRIPT_START_TIME, $all_themes->timestamp );
57
+
58
+ if ( WP_FS__SCRIPT_START_TIME < $all_themes->timestamp ) {
59
+ printf( __fs( 'in-x' ), $human_diff );
60
+ } else {
61
+ printf( __fs( 'x-ago' ), $human_diff );
62
+ }
63
+ }
64
+ ?></td>
65
+ </tr>
66
+ <?php endif ?>
67
+ </tbody>
68
+ </table>
freemius/templates/debug/scheduled-crons.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ $fs_options = FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true );
14
+ $plugins = $fs_options->get_option( 'plugins' );
15
+ $scheduled_crons = array();
16
+ if ( is_array( $plugins ) && 0 < count( $plugins ) ) {
17
+ foreach ( $plugins as $slug => $data ) {
18
+ /**
19
+ * @author Vova Feldman
20
+ *
21
+ * @since 1.2.1 Don't load data from inactive modules.
22
+ */
23
+ if ( is_plugin_active( $data->file ) ) {
24
+ $fs = freemius( $slug );
25
+
26
+ $next_execution = $fs->next_sync_cron();
27
+ $last_execution = $fs->last_sync_cron();
28
+
29
+ if ( false !== $next_execution ) {
30
+ $scheduled_crons[ $slug ][] = array(
31
+ 'name' => $fs->get_plugin_name(),
32
+ 'slug' => $slug,
33
+ 'type' => 'sync_cron',
34
+ 'last' => $last_execution,
35
+ 'next' => $next_execution,
36
+ );
37
+ }
38
+
39
+ $next_install_execution = $fs->next_install_sync();
40
+ $last_install_execution = $fs->last_install_sync();
41
+
42
+ if ( false !== $next_install_execution ||
43
+ false !== $last_install_execution
44
+ ) {
45
+ $scheduled_crons[ $slug ][] = array(
46
+ 'name' => $fs->get_plugin_name(),
47
+ 'slug' => $slug,
48
+ 'type' => 'install_sync',
49
+ 'last' => $last_install_execution,
50
+ 'next' => $next_install_execution,
51
+ );
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ?>
57
+ <h1><?php _efs( 'scheduled-crons' ) ?></h1>
58
+ <table class="widefat">
59
+ <thead>
60
+ <tr>
61
+ <th><?php _efs( 'slug' ) ?></th>
62
+ <th><?php _efs( 'plugin' ) ?></th>
63
+ <th><?php _efs( 'type' ) ?></th>
64
+ <th><?php _efs( 'Last' ) ?></th>
65
+ <th><?php _efs( 'Next' ) ?></th>
66
+ </tr>
67
+ </thead>
68
+ <tbody>
69
+ <?php foreach ( $scheduled_crons as $slug => $crons ) : ?>
70
+ <?php foreach ( $crons as $cron ) : ?>
71
+ <tr>
72
+ <td><?php echo $slug ?></td>
73
+ <td><?php echo $cron['name'] ?></td>
74
+ <td><?php echo $cron['type'] ?></td>
75
+ <td><?php
76
+ if ( is_numeric( $cron['last'] ) ) {
77
+ $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['last'] );
78
+ $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?
79
+ $diff . ' ' . __fs( 'sec' ) :
80
+ human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['last'] );
81
+
82
+ if ( WP_FS__SCRIPT_START_TIME < $cron['last'] ) {
83
+ printf( __fs( 'in-x' ), $human_diff );
84
+ } else {
85
+ printf( __fs( 'x-ago' ), $human_diff );
86
+ }
87
+
88
+ // echo ' ' . $cron['last'];
89
+ }
90
+ ?></td>
91
+ <td><?php
92
+ if ( is_numeric( $cron['next'] ) ) {
93
+ $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['next'] );
94
+ $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?
95
+ $diff . ' ' . __fs( 'sec' ) :
96
+ human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['next'] );
97
+
98
+ if ( WP_FS__SCRIPT_START_TIME < $cron['next'] ) {
99
+ printf( __fs( 'in-x' ), $human_diff );
100
+ } else {
101
+ printf( __fs( 'x-ago' ), $human_diff );
102
+ }
103
+ }
104
+ ?></td>
105
+ </tr>
106
+ <?php endforeach ?>
107
+ <?php endforeach ?>
108
+ </tbody>
109
+ </table>
freemius/templates/email.php CHANGED
@@ -10,6 +10,9 @@
10
  exit;
11
  }
12
 
 
 
 
13
  $sections = $VARS['sections'];
14
  ?>
15
  <table>
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @var array $VARS
15
+ */
16
  $sections = $VARS['sections'];
17
  ?>
18
  <table>
freemius/templates/firewall-issues-js.php CHANGED
@@ -23,7 +23,7 @@
23
  slug = notice.attr('data-slug');
24
 
25
  var data = {
26
- action : slug + '_resolve_firewall_issues',
27
  slug : slug,
28
  error_type: error_type
29
  };
@@ -39,6 +39,10 @@
39
  }
40
  }
41
 
 
 
 
 
42
  $(this).css({'cursor': 'wait'});
43
 
44
  // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
@@ -46,6 +50,9 @@
46
  if (1 == response) {
47
  // Refresh page on success.
48
  location.reload();
 
 
 
49
  }
50
  });
51
  });
23
  slug = notice.attr('data-slug');
24
 
25
  var data = {
26
+ action : 'fs_resolve_firewall_issues_' + slug,
27
  slug : slug,
28
  error_type: error_type
29
  };
39
  }
40
  }
41
 
42
+ if ('retry_ping' === error_type) {
43
+ data.action = 'fs_retry_connectivity_test_' + slug;
44
+ }
45
+
46
  $(this).css({'cursor': 'wait'});
47
 
48
  // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
50
  if (1 == response) {
51
  // Refresh page on success.
52
  location.reload();
53
+ } else if ('http' === response.substr(0, 4)) {
54
+ // Ping actually worked, redirect.
55
+ window.location = response;
56
  }
57
  });
58
  });
freemius/templates/forms/deactivation/contact.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.2.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+
19
+ echo __fs( 'contact-support-before-deactivation', $slug )
20
+ . sprintf(" <a href='%s' class='button button-small button-primary'>%s</a>",
21
+ $fs->contact_url( 'technical_support' ),
22
+ __fs( 'contact-support', $slug )
23
+ );
freemius/templates/forms/deactivation/form.php ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+
19
+ $confirmation_message = $fs->apply_filters( 'uninstall_confirmation_message', '' );
20
+
21
+ $reasons = $VARS['reasons'];
22
+
23
+ $reasons_list_items_html = '';
24
+
25
+ foreach ( $reasons as $reason ) {
26
+ $list_item_classes = 'reason' . ( ! empty( $reason['input_type'] ) ? ' has-input' : '' );
27
+
28
+ if ( isset( $reason['internal_message'] ) && ! empty( $reason['internal_message'] ) ) {
29
+ $list_item_classes .= ' has-internal-message';
30
+ $reason_internal_message = $reason['internal_message'];
31
+ } else {
32
+ $reason_internal_message = '';
33
+ }
34
+
35
+ $reason_list_item_html = <<< HTML
36
+ <li class="{$list_item_classes}"
37
+ data-input-type="{$reason['input_type']}"
38
+ data-input-placeholder="{$reason['input_placeholder']}">
39
+ <label>
40
+ <span>
41
+ <input type="radio" name="selected-reason" value="{$reason['id']}"/>
42
+ </span>
43
+ <span>{$reason['text']}</span>
44
+ </label>
45
+ <div class="internal-message">{$reason_internal_message}</div>
46
+ </li>
47
+ HTML;
48
+
49
+ $reasons_list_items_html .= $reason_list_item_html;
50
+ }
51
+
52
+ $is_anonymous = ( ! $fs->is_registered() );
53
+ if ( $is_anonymous ) {
54
+ $anonymous_feedback_checkbox_html =
55
+ '<label class="anonymous-feedback-label"><input type="checkbox" class="anonymous-feedback-checkbox"> '
56
+ . __fs( 'anonymous-feedback', $slug )
57
+ . '</label>';
58
+ } else {
59
+ $anonymous_feedback_checkbox_html = '';
60
+ }
61
+
62
+ fs_enqueue_local_style( 'dialog-boxes', '/admin/dialog-boxes.css' );
63
+ ?>
64
+ <script type="text/javascript">
65
+ (function ($) {
66
+ var reasonsHtml = <?php echo json_encode( $reasons_list_items_html ); ?>,
67
+ modalHtml =
68
+ '<div class="fs-modal fs-modal-deactivation-feedback<?php echo empty( $confirmation_message ) ? ' no-confirmation-message' : ''; ?>">'
69
+ + ' <div class="fs-modal-dialog">'
70
+ + ' <div class="fs-modal-header">'
71
+ + ' <h4><?php _efs('quick-feedback' , $slug) ?></h4>'
72
+ + ' </div>'
73
+ + ' <div class="fs-modal-body">'
74
+ + ' <div class="fs-modal-panel" data-panel-id="confirm"><p><?php echo $confirmation_message; ?></p></div>'
75
+ + ' <div class="fs-modal-panel active" data-panel-id="reasons"><h3><strong><?php printf( __fs( 'deactivation-share-reason' , $slug ) ); ?>:</strong></h3><ul id="reasons-list">' + reasonsHtml + '</ul></div>'
76
+ + ' </div>'
77
+ + ' <div class="fs-modal-footer">'
78
+ + ' <?php echo $anonymous_feedback_checkbox_html ?>'
79
+ + ' <a href="#" class="button button-secondary button-deactivate"></a>'
80
+ + ' <a href="#" class="button button-primary button-close"><?php printf( __fs( 'deactivation-modal-button-cancel' , $slug ) ) ?></a>'
81
+ + ' </div>'
82
+ + ' </div>'
83
+ + '</div>',
84
+ $modal = $(modalHtml),
85
+ $deactivateLink = $('#the-list .deactivate > [data-slug=<?php echo $VARS['slug']; ?>].fs-slug').prev(),
86
+ $anonymousFeedback = $modal.find( '.anonymous-feedback-label' ),
87
+ isAnonymous = <?php echo ( $is_anonymous ? 'true' : 'false' ); ?>,
88
+ selectedReasonID = false,
89
+ otherReasonID = <?php echo Freemius::REASON_OTHER; ?>,
90
+ dontShareDataReasonID = <?php echo Freemius::REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION; ?>;
91
+
92
+ $modal.appendTo($('body'));
93
+
94
+ registerEventHandlers();
95
+
96
+ function registerEventHandlers() {
97
+ $deactivateLink.click(function (evt) {
98
+ evt.preventDefault();
99
+
100
+ showModal();
101
+ });
102
+
103
+ $modal.on('input propertychange', '.reason-input input', function () {
104
+ if (!isOtherReasonSelected()) {
105
+ return;
106
+ }
107
+
108
+ var reason = $(this).val().trim();
109
+
110
+ /**
111
+ * If reason is not empty, remove the error-message class of the message container
112
+ * to change the message color back to default.
113
+ */
114
+ if (reason.length > 0) {
115
+ $('.message').removeClass('error-message');
116
+ enableDeactivateButton();
117
+ }
118
+ });
119
+
120
+ $modal.on('blur', '.reason-input input', function () {
121
+ var $userReason = $(this);
122
+
123
+ setTimeout(function () {
124
+ if (!isOtherReasonSelected()) {
125
+ return;
126
+ }
127
+
128
+ /**
129
+ * If reason is empty, add the error-message class to the message container
130
+ * to change the message color to red.
131
+ */
132
+ if (0 === $userReason.val().trim().length) {
133
+ $('.message').addClass('error-message');
134
+ disableDeactivateButton();
135
+ }
136
+ }, 150);
137
+ });
138
+
139
+ $modal.on('click', '.fs-modal-footer .button', function (evt) {
140
+ evt.preventDefault();
141
+
142
+ if ($(this).hasClass('disabled')) {
143
+ return;
144
+ }
145
+
146
+ var _parent = $(this).parents('.fs-modal:first');
147
+ var _this = $(this);
148
+
149
+ if (_this.hasClass('allow-deactivate')) {
150
+ var $radio = $('input[type="radio"]:checked');
151
+
152
+ if (0 === $radio.length) {
153
+ // If no selected reason, just deactivate the plugin.
154
+ window.location.href = $deactivateLink.attr('href');
155
+ return;
156
+ }
157
+
158
+ var $selected_reason = $radio.parents('li:first'),
159
+ $input = $selected_reason.find('textarea, input[type="text"]'),
160
+ userReason = ( 0 !== $input.length ) ? $input.val().trim() : '';
161
+
162
+ if (isOtherReasonSelected() && ( '' === userReason )) {
163
+ return;
164
+ }
165
+
166
+ $.ajax({
167
+ url : ajaxurl,
168
+ method : 'POST',
169
+ data : {
170
+ 'action' : '<?php echo $fs->get_action_tag( 'submit_uninstall_reason' ) ?>',
171
+ 'reason_id' : $radio.val(),
172
+ 'reason_info' : userReason,
173
+ 'is_anonymous': isAnonymousFeedback()
174
+ },
175
+ beforeSend: function () {
176
+ _parent.find('.fs-modal-footer .button').addClass('disabled');
177
+ _parent.find('.fs-modal-footer .button-secondary').text('Processing...');
178
+ },
179
+ complete : function () {
180
+ // Do not show the dialog box, deactivate the plugin.
181
+ window.location.href = $deactivateLink.attr('href');
182
+ }
183
+ });
184
+ } else if (_this.hasClass('button-deactivate')) {
185
+ // Change the Deactivate button's text and show the reasons panel.
186
+ _parent.find('.button-deactivate').addClass('allow-deactivate');
187
+
188
+ showPanel('reasons');
189
+ }
190
+ });
191
+
192
+ $modal.on('click', 'input[type="radio"]', function () {
193
+ var $selectedReasonOption = $(this);
194
+
195
+ // If the selection has not changed, do not proceed.
196
+ if (selectedReasonID === $selectedReasonOption.val())
197
+ return;
198
+
199
+ selectedReasonID = $selectedReasonOption.val();
200
+
201
+ if ( isAnonymous ) {
202
+ if ( isReasonSelected( dontShareDataReasonID ) ) {
203
+ $anonymousFeedback.hide();
204
+ } else {
205
+ $anonymousFeedback.show();
206
+ }
207
+ }
208
+
209
+ var _parent = $(this).parents('li:first');
210
+
211
+ $modal.find('.reason-input').remove();
212
+ $modal.find( '.internal-message' ).hide();
213
+ $modal.find('.button-deactivate').text('<?php printf( __fs( 'deactivation-modal-button-submit' , $slug ) ); ?>');
214
+
215
+ enableDeactivateButton();
216
+
217
+ if ( _parent.hasClass( 'has-internal-message' ) ) {
218
+ _parent.find( '.internal-message' ).show();
219
+ }
220
+
221
+ if (_parent.hasClass('has-input')) {
222
+ var inputType = _parent.data('input-type'),
223
+ inputPlaceholder = _parent.data('input-placeholder'),
224
+ reasonInputHtml = '<div class="reason-input"><span class="message"></span>' + ( ( 'textfield' === inputType ) ? '<input type="text" />' : '<textarea rows="5"></textarea>' ) + '</div>';
225
+
226
+ _parent.append($(reasonInputHtml));
227
+ _parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
228
+
229
+ if (isOtherReasonSelected()) {
230
+ showMessage('<?php printf( __fs( 'ask-for-reason-message' , $slug ) ); ?>');
231
+ disableDeactivateButton();
232
+ }
233
+ }
234
+ });
235
+
236
+ // If the user has clicked outside the window, cancel it.
237
+ $modal.on('click', function (evt) {
238
+ var $target = $(evt.target);
239
+
240
+ // If the user has clicked anywhere in the modal dialog, just return.
241
+ if ($target.hasClass('fs-modal-body') || $target.hasClass('fs-modal-footer')) {
242
+ return;
243
+ }
244
+
245
+ // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return.
246
+ if (!$target.hasClass('button-close') && ( $target.parents('.fs-modal-body').length > 0 || $target.parents('.fs-modal-footer').length > 0 )) {
247
+ return;
248
+ }
249
+
250
+ closeModal();
251
+ return false;
252
+ });
253
+ }
254
+
255
+ function isAnonymousFeedback() {
256
+ if ( ! isAnonymous ) {
257
+ return false;
258
+ }
259
+
260
+ return ( isReasonSelected( dontShareDataReasonID ) || $anonymousFeedback.find( 'input' ).prop( 'checked' ) );
261
+ }
262
+
263
+ function isReasonSelected( reasonID ) {
264
+ // Get the selected radio input element.
265
+ var $selectedReasonOption = $modal.find('input[type="radio"]:checked');
266
+
267
+ return ( reasonID == $selectedReasonOption.val() );
268
+ }
269
+
270
+ function isOtherReasonSelected() {
271
+ return isReasonSelected( otherReasonID );
272
+ }
273
+
274
+ function showModal() {
275
+ resetModal();
276
+
277
+ // Display the dialog box.
278
+ $modal.addClass('active');
279
+
280
+ $('body').addClass('has-fs-modal');
281
+ }
282
+
283
+ function closeModal() {
284
+ $modal.removeClass('active');
285
+
286
+ $('body').removeClass('has-fs-modal');
287
+ }
288
+
289
+ function resetModal() {
290
+ selectedReasonID = false;
291
+
292
+ enableDeactivateButton();
293
+
294
+ // Uncheck all radio buttons.
295
+ $modal.find('input[type="radio"]').prop('checked', false);
296
+
297
+ // Remove all input fields ( textfield, textarea ).
298
+ $modal.find('.reason-input').remove();
299
+
300
+ $modal.find('.message').hide();
301
+
302
+ if ( isAnonymous ) {
303
+ $anonymousFeedback.find( 'input' ).prop( 'checked', false );
304
+
305
+ // Hide, since by default there is no selected reason.
306
+ $anonymousFeedback.hide();
307
+ }
308
+
309
+ var $deactivateButton = $modal.find('.button-deactivate');
310
+
311
+ /*
312
+ * If the modal dialog has no confirmation message, that is, it has only one panel, then ensure
313
+ * that clicking the deactivate button will actually deactivate the plugin.
314
+ */
315
+ if ($modal.hasClass('no-confirmation-message')) {
316
+ $deactivateButton.addClass('allow-deactivate');
317
+
318
+ showPanel('reasons');
319
+ } else {
320
+ $deactivateButton.removeClass('allow-deactivate');
321
+
322
+ showPanel('confirm');
323
+ }
324
+ }
325
+
326
+ function showMessage(message) {
327
+ $modal.find('.message').text(message).show();
328
+ }
329
+
330
+ function enableDeactivateButton() {
331
+ $modal.find('.button-deactivate').removeClass('disabled');
332
+ }
333
+
334
+ function disableDeactivateButton() {
335
+ $modal.find('.button-deactivate').addClass('disabled');
336
+ }
337
+
338
+ function showPanel(panelType) {
339
+ $modal.find('.fs-modal-panel').removeClass('active ');
340
+ $modal.find('[data-panel-id="' + panelType + '"]').addClass('active');
341
+
342
+ updateButtonLabels();
343
+ }
344
+
345
+ function updateButtonLabels() {
346
+ var $deactivateButton = $modal.find('.button-deactivate');
347
+
348
+ // Reset the deactivate button's text.
349
+ if ('confirm' === getCurrentPanel()) {
350
+ $deactivateButton.text('<?php printf( __fs( 'deactivation-modal-button-confirm' , $slug ) ); ?>');
351
+ } else {
352
+ $deactivateButton.text('<?php printf( __fs( 'skip-deactivate' , $slug ) ); ?>');
353
+ }
354
+ }
355
+
356
+ function getCurrentPanel() {
357
+ return $modal.find('.fs-modal-panel.active').attr('data-panel-id');
358
+ }
359
+ })(jQuery);
360
+ </script>
freemius/templates/forms/deactivation/retry-skip.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.2.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+
19
+ $skip_url = wp_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $slug . '_skip_activation' ) ), $slug . '_skip_activation' );
20
+ $skip_text = strtolower( __fs( 'skip', $slug ) );
21
+ $use_plugin_anonymously_text = __fs( 'click-here-to-use-plugin-anonymously', $slug );
22
+
23
+ echo sprintf( __fs( 'dont-have-to-share-any-data', $slug ), "<a href='{$skip_url}'>{$skip_text}</a>" )
24
+ . " <a href='{$skip_url}' class='button button-small button-secondary'>{$use_plugin_anonymously_text}</a>";
freemius/templates/forms/license-activation.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.9
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+
19
+ if ($fs->is_registered()) {
20
+ // The URL to redirect to after successfully activating the license from the "Plugins" page.
21
+ if ( $fs->is_addon() ) {
22
+ $sync_license_url = $fs->get_parent_instance()->_get_sync_license_url( $fs->get_id(), true );
23
+ } else {
24
+ $sync_license_url = $fs->_get_sync_license_url( $fs->get_id(), true );
25
+ }
26
+
27
+ /**
28
+ * Trigger license sync after valid license activation.
29
+ */
30
+ $after_license_activation_url = $sync_license_url;
31
+ }
32
+ else
33
+ {
34
+ /**
35
+ * If user not yet registered, the license activation triggers
36
+ * an opt-in, which automatically sync the license.
37
+ */
38
+ $after_license_activation_url = $fs->get_account_url();
39
+ }
40
+
41
+ $cant_find_license_key_text = __fs( 'cant-find-license-key', $slug );
42
+ $message_above_input_field = __fs( 'activate-license-message', $slug );
43
+ $message_below_input_field = '';
44
+
45
+ $header_title = __fs( $fs->is_free_plan() ? 'activate-license' : 'update-license', $slug );
46
+
47
+ if ( $fs->is_registered() ) {
48
+ $activate_button_text = $header_title;
49
+ } else {
50
+ $freemius_site_url = $fs->has_paid_plan() ?
51
+ 'https://freemius.com/wordpress/' :
52
+ // Insights platform information.
53
+ 'https://freemius.com/wordpress/usage-tracking/';
54
+
55
+ $freemius_link = '<a href="' . $freemius_site_url . '" target="_blank" tabindex="0">freemius.com</a>';
56
+
57
+ $message_below_input_field = sprintf( __fs( 'license-sync-disclaimer', $slug ), $freemius_link );
58
+
59
+ $activate_button_text = __fs( 'agree-activate-license', $slug );
60
+ }
61
+
62
+ $license_key_text = __fs( 'license-key' , $slug );
63
+
64
+ $modal_content_html = <<< HTML
65
+ <div class="notice notice-error inline license-activation-message"><p></p></div>
66
+ <p>{$message_above_input_field}</p>
67
+ <input class="license_key" type="text" placeholder="{$license_key_text}" tabindex="1" />
68
+ <a class="show-license-resend-modal show-license-resend-modal-{$slug}" href="!#" tabindex="2">{$cant_find_license_key_text}</a>
69
+ <p>{$message_below_input_field}</p>
70
+ HTML;
71
+
72
+ fs_enqueue_local_style( 'dialog-boxes', '/admin/dialog-boxes.css' );
73
+ ?>
74
+ <script type="text/javascript">
75
+ (function( $ ) {
76
+ $( document ).ready(function() {
77
+ var modalContentHtml = <?php echo json_encode($modal_content_html); ?>,
78
+ modalHtml =
79
+ '<div class="fs-modal fs-modal-license-activation">'
80
+ + ' <div class="fs-modal-dialog">'
81
+ + ' <div class="fs-modal-header">'
82
+ + ' <h4><?php echo $header_title ?></h4>'
83
+ + ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php _efs( 'dismiss' ) ?>"></i></a>'
84
+ + ' </div>'
85
+ + ' <div class="fs-modal-body">'
86
+ + ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
87
+ + ' </div>'
88
+ + ' <div class="fs-modal-footer">'
89
+ + ' <button class="button button-secondary button-close" tabindex="4"><?php _efs('deactivation-modal-button-cancel', $slug); ?></button>'
90
+ + ' <button class="button button-primary button-activate-license" tabindex="3"><?php echo $activate_button_text; ?></button>'
91
+ + ' </div>'
92
+ + ' </div>'
93
+ + '</div>',
94
+ $modal = $(modalHtml),
95
+ $activateLicenseLink = $('span.activate-license.<?php echo $VARS['slug'] ?> a, .activate-license-trigger.<?php echo $VARS['slug'] ?>'),
96
+ $activateLicenseButton = $modal.find('.button-activate-license'),
97
+ $licenseKeyInput = $modal.find('input.license_key'),
98
+ $licenseActivationMessage = $modal.find( '.license-activation-message' ),
99
+ pluginSlug = '<?php echo $slug ?>',
100
+ afterActivationUrl = '<?php echo $after_license_activation_url ?>';
101
+
102
+ $modal.appendTo($('body'));
103
+
104
+ function registerEventHandlers() {
105
+ $activateLicenseLink.click(function (evt) {
106
+ evt.preventDefault();
107
+
108
+ showModal();
109
+ });
110
+
111
+ $modal.on('input propertychange', 'input.license_key', function () {
112
+
113
+ var licenseKey = $(this).val().trim();
114
+
115
+ /**
116
+ * If license key is not empty, enable the license activation button.
117
+ */
118
+ if (licenseKey.length > 0) {
119
+ enableActivateLicenseButton();
120
+ }
121
+ });
122
+
123
+ $modal.on('blur', 'input.license_key', function () {
124
+ var licenseKey = $(this).val().trim();
125
+
126
+ /**
127
+ * If license key is empty, disable the license activation button.
128
+ */
129
+ if (0 === licenseKey.length) {
130
+ disableActivateLicenseButton();
131
+ }
132
+ });
133
+
134
+ $modal.on('click', '.button-activate-license', function (evt) {
135
+ evt.preventDefault();
136
+
137
+ if ($(this).hasClass('disabled')) {
138
+ return;
139
+ }
140
+
141
+ var licenseKey = $licenseKeyInput.val().trim();
142
+
143
+ disableActivateLicenseButton();
144
+
145
+ if (0 === licenseKey.length) {
146
+ return;
147
+ }
148
+
149
+ $.ajax({
150
+ url: ajaxurl,
151
+ method: 'POST',
152
+ data: {
153
+ action : 'fs_activate_license_' + pluginSlug,
154
+ slug : pluginSlug,
155
+ license_key: licenseKey
156
+ },
157
+ beforeSend: function () {
158
+ $activateLicenseButton.text( '<?php _efs( 'activating-license', $slug ); ?>' );
159
+ },
160
+ success: function( result ) {
161
+ var resultObj = $.parseJSON( result );
162
+ if ( resultObj.success ) {
163
+ closeModal();
164
+
165
+ // Redirect to the "Account" page and sync the license.
166
+ window.location.href = afterActivationUrl;
167
+ } else {
168
+ showError( resultObj.error );
169
+ resetActivateLicenseButton();
170
+ }
171
+ }
172
+ });
173
+ });
174
+
175
+ // If the user has clicked outside the window, close the modal.
176
+ $modal.on('click', '.fs-close, .button-secondary', function () {
177
+ closeModal();
178
+ return false;
179
+ });
180
+ }
181
+
182
+ registerEventHandlers();
183
+
184
+ function showModal() {
185
+ resetModal();
186
+
187
+ // Display the dialog box.
188
+ $modal.addClass('active');
189
+ $('body').addClass('has-fs-modal');
190
+
191
+ $licenseKeyInput.focus();
192
+ }
193
+
194
+ function closeModal() {
195
+ $modal.removeClass('active');
196
+ $('body').removeClass('has-fs-modal');
197
+ }
198
+
199
+ function resetActivateLicenseButton() {
200
+ enableActivateLicenseButton();
201
+ $activateLicenseButton.text( '<?php echo $activate_button_text; ?>' );
202
+ }
203
+
204
+ function resetModal() {
205
+ hideError();
206
+ resetActivateLicenseButton();
207
+ $licenseKeyInput.val( '' );
208
+ }
209
+
210
+ function enableActivateLicenseButton() {
211
+ $activateLicenseButton.removeClass( 'disabled' );
212
+ }
213
+
214
+ function disableActivateLicenseButton() {
215
+ $activateLicenseButton.addClass( 'disabled' );
216
+ }
217
+
218
+ function hideError() {
219
+ $licenseActivationMessage.hide();
220
+ }
221
+
222
+ function showError( msg ) {
223
+ $licenseActivationMessage.find( ' > p' ).html( msg );
224
+ $licenseActivationMessage.show();
225
+ }
226
+ });
227
+ })( jQuery );
228
+ </script>
freemius/templates/forms/resend-key.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.2.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ */
16
+ $slug = $VARS['slug'];
17
+ $fs = freemius( $slug );
18
+
19
+ $message_above_input_field = __fs( 'ask-for-upgrade-email-address', $slug );
20
+ $send_button_text = __fs( 'send-license-key', $slug );
21
+ $cancel_button_text = __fs( 'deactivation-modal-button-cancel', $slug );
22
+ $email_address_placeholder = __fs( 'email-address', $slug );
23
+
24
+ $modal_content_html = <<< HTML
25
+ <div class="notice notice-error inline license-resend-message"><p></p></div>
26
+ <p>{$message_above_input_field}</p>
27
+ <div class="input-container">
28
+ <div class="button-container">
29
+ <a href="#" class="button button-primary button-send-license-key disabled" tabindex="2">{$send_button_text}</a>
30
+ </div>
31
+ <div class="email-address-container">
32
+ <input class="email-address" type="text" placeholder="{$email_address_placeholder}" tabindex="1">
33
+ </div>
34
+ </div>
35
+ HTML;
36
+
37
+ fs_enqueue_local_style( 'dialog-boxes', '/admin/dialog-boxes.css' );
38
+ ?>
39
+ <script type="text/javascript">
40
+ (function ($) {
41
+ $(document).ready(function () {
42
+ var modalContentHtml = <?php echo json_encode( $modal_content_html ); ?>,
43
+ modalHtml =
44
+ '<div class="fs-modal fs-modal-license-key-resend">'
45
+ + ' <div class="fs-modal-dialog">'
46
+ + ' <div class="fs-modal-header">'
47
+ + ' <h4><?php echo $send_button_text ?></h4>'
48
+ + ' <a href="#!" class="fs-close" tabindex="3" title="Close"><i class="dashicons dashicons-no" title="<?php _efs( 'dismiss' ) ?>"></i></a>'
49
+ + ' </div>'
50
+ + ' <div class="fs-modal-body">'
51
+ + ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
52
+ + ' </div>'
53
+ + ' </div>'
54
+ + '</div>',
55
+ $modal = $(modalHtml),
56
+ $sendLicenseKeyButton = $modal.find('.button-send-license-key'),
57
+ $emailAddressInput = $modal.find('input.email-address'),
58
+ $licenseResendMessage = $modal.find('.license-resend-message'),
59
+ moduleSlug = '<?php echo $slug; ?>',
60
+ isChild = false;
61
+
62
+ $modal.appendTo($('body'));
63
+
64
+ registerEventHandlers();
65
+
66
+ function registerEventHandlers() {
67
+ $('a.show-license-resend-modal-' + moduleSlug).click(function (evt) {
68
+ evt.preventDefault();
69
+
70
+ showModal();
71
+ });
72
+
73
+ $modal.on('input propertychange', 'input.email-address', function () {
74
+
75
+ var emailAddress = $(this).val().trim();
76
+
77
+ /**
78
+ * If email address is not empty, enable the send license key button.
79
+ */
80
+ if (emailAddress.length > 0) {
81
+ enableSendLicenseKeyButton();
82
+ }
83
+ });
84
+
85
+ $modal.on('blur', 'input.email-address', function () {
86
+ var emailAddress = $(this).val().trim();
87
+
88
+ /**
89
+ * If email address is empty, disable the send license key button.
90
+ */
91
+ if (0 === emailAddress.length) {
92
+ disableSendLicenseKeyButton();
93
+ }
94
+ });
95
+
96
+ $modal.on('click', '.fs-close', function (){
97
+ closeModal();
98
+ return false;
99
+ });
100
+
101
+ $modal.on('click', '.button', function (evt) {
102
+ evt.preventDefault();
103
+
104
+ if ($(this).hasClass('disabled')) {
105
+ return;
106
+ }
107
+
108
+ var emailAddress = $emailAddressInput.val().trim();
109
+
110
+ disableSendLicenseKeyButton();
111
+
112
+ if (0 === emailAddress.length) {
113
+ return;
114
+ }
115
+
116
+ $.ajax({
117
+ url : ajaxurl,
118
+ method : 'POST',
119
+ data : {
120
+ action: '<?php echo $fs->get_action_tag( 'resend_license_key' ) ?>',
121
+ slug : moduleSlug,
122
+ email : emailAddress
123
+ },
124
+ beforeSend: function () {
125
+ $sendLicenseKeyButton.text('<?php _efs( 'sending-license-key', $slug ) ?>...');
126
+ },
127
+ success : function (result) {
128
+ var resultObj = $.parseJSON(result);
129
+ if (resultObj.success) {
130
+ closeModal();
131
+ } else {
132
+ showError(resultObj.error);
133
+ resetSendLicenseKeyButton();
134
+ }
135
+ }
136
+ });
137
+ });
138
+ }
139
+
140
+ function showModal() {
141
+ resetModal();
142
+
143
+ // Display the dialog box.
144
+ $modal.addClass('active');
145
+ $emailAddressInput.focus();
146
+
147
+ var $body = $('body');
148
+
149
+ isChild = $body.hasClass('has-fs-modal');
150
+ if (isChild) {
151
+ return;
152
+ }
153
+
154
+ $body.addClass('has-fs-modal');
155
+ }
156
+
157
+ function closeModal() {
158
+ $modal.removeClass('active');
159
+
160
+ // If child modal, do not remove the "has-fs-modal" class of the <body> element to keep its scrollbars hidden.
161
+ if (isChild) {
162
+ return;
163
+ }
164
+
165
+ $('body').removeClass('has-fs-modal');
166
+ }
167
+
168
+ function resetSendLicenseKeyButton() {
169
+ enableSendLicenseKeyButton();
170
+ $sendLicenseKeyButton.text('<?php echo $send_button_text; ?>');
171
+ }
172
+
173
+ function resetModal() {
174
+ hideError();
175
+ resetSendLicenseKeyButton();
176
+ $emailAddressInput.val('');
177
+ }
178
+
179
+ function enableSendLicenseKeyButton() {
180
+ $sendLicenseKeyButton.removeClass('disabled');
181
+ }
182
+
183
+ function disableSendLicenseKeyButton() {
184
+ $sendLicenseKeyButton.addClass('disabled');
185
+ }
186
+
187
+ function hideError() {
188
+ $licenseResendMessage.hide();
189
+ }
190
+
191
+ function showError(msg) {
192
+ $licenseResendMessage.find(' > p').html(msg);
193
+ $licenseResendMessage.show();
194
+ }
195
+ });
196
+ })(jQuery);
197
+ </script>
freemius/templates/pending-activation.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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', $slug ) . '<br>' .
56
+ __fs( 'pending-activation-message', $slug ),
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', $slug ) ?></button>
96
+ </form>
97
+ </div>
98
+ <div class="fs-permissions">
99
+ <a class="fs-trigger" href="#"><?php _efs( 'what-permissions', $slug ) ?></a>
100
+ <ul>
101
+ <li>
102
+ <i class="dashicons dashicons-admin-users"></i>
103
+
104
+ <div>
105
+ <span><?php _efs( 'permissions-profile', $slug ) ?></span>
106
+
107
+ <p><?php _efs( 'permissions-profile_desc', $slug ) ?></p>
108
+ </div>
109
+ </li>
110
+ <li>
111
+ <i class="dashicons dashicons-wordpress"></i>
112
+
113
+ <div>
114
+ <span><?php _efs( 'permissions-site', $slug ) ?></span>
115
+
116
+ <p><?php _efs( 'permissions-site_desc', $slug ) ?></p>
117
+ </div>
118
+ </li>
119
+ <?php if ( $fs->is_permission_requested( 'newsletter' ) ) : ?>
120
+ <li>
121
+ <i class="dashicons dashicons-email-alt"></i>
122
+
123
+ <div>
124
+ <span><?php _efs( 'permissions-newsletter', $slug ) ?></span>
125
+
126
+ <p><?php _efs( 'permissions-newsletter_desc', $slug ) ?></p>
127
+ </div>
128
+ </li>
129
+ <?php endif ?>
130
+ <li>
131
+ <i class="dashicons dashicons-admin-plugins"></i>
132
+
133
+ <div>
134
+ <span><?php _efs( 'permissions-events', $slug ) ?></span>
135
+
136
+ <p><?php _efs( 'permissions-events_desc', $slug ) ?></p>
137
+ </div>
138
+ </li>
139
+ </ul>
140
+ </div>
141
+ <div class="fs-terms">
142
+ <a href="https://freemius.com/privacy/" target="_blank"><?php _efs( 'privacy-policy', $slug ) ?></a>
143
+ &nbsp;&nbsp;-&nbsp;&nbsp;
144
+ <a href="https://freemius.com/terms/" target="_blank"><?php _efs( 'tos', $slug ) ?></a>
145
+ </div>
146
+ </div>
147
+ <script type="text/javascript">
148
+ (function ($) {
149
+ $('.button.button-primary').on('click', function () {
150
+ $(document.body).css({'cursor': 'wait'});
151
+ $(this).html('Sending email...').css({'cursor': 'wait'});
152
+ });
153
+ $('.fs-permissions .fs-trigger').on('click', function () {
154
+ $('.fs-permissions').toggleClass('fs-open');
155
+ });
156
+ })(jQuery);
157
+ </script>
freemius/templates/plugin-icon.php CHANGED
@@ -10,67 +10,87 @@
10
  exit;
11
  }
12
 
 
 
 
13
  $slug = $VARS['slug'];
14
  $fs = freemius( $slug );
15
 
16
- global $fs_active_plugins;
 
 
 
 
 
 
 
 
17
 
18
- $img_dir = WP_FS__DIR_IMG;
19
 
20
- if ( 1 < count( $fs_active_plugins->plugins ) ) {
21
- foreach ( $fs_active_plugins->plugins as $sdk_path => &$data ) {
22
- if ( $data->plugin_path == $fs->get_plugin_basename() ) {
23
- $img_dir = WP_PLUGIN_DIR . '/' . $sdk_path . '/assets/img';
24
- break;
 
25
  }
26
  }
27
- }
28
 
29
- $icons = glob( fs_normalize_path( $img_dir . '/icon.*' ) );
30
- if ( ! is_array( $icons ) || 0 === count( $icons ) ) {
31
- $icon_found = false;
32
- $local_path = fs_normalize_path( $img_dir . '/icon.png' );
 
33
 
34
- if ( WP_FS__IS_LOCALHOST && $fs->is_org_repo_compliant() ) {
35
- /**
36
- * IMPORTANT: THIS CODE WILL NEVER RUN AFTER THE PLUGIN IS IN THE REPO.
37
- *
38
- * This code will only be executed once during the testing
39
- * of the plugin in a local environment. The plugin icon file WILL
40
- * already exist in the assets folder when the plugin is deployed to
41
- * the repository.
42
- */
43
- $suffixes = array(
44
- '-128x128.png',
45
- '-128x128.jpg',
46
- '-256x256.png',
47
- '-256x256.jpg',
48
- '.svg',
49
- );
50
 
51
- $base_url = 'https://plugins.svn.wordpress.org/' . $slug . '/assets/icon';
52
 
53
- foreach ( $suffixes as $s ) {
54
- $headers = get_headers( $base_url . $s );
55
- if ( strpos( $headers[0], '200' ) ) {
56
- $local_path = fs_normalize_path( $img_dir . '/icon.' . substr( $s, strpos( $s, '.' ) + 1 ) );
57
- fs_download_image( $base_url . $s, $local_path );
58
- $icon_found = true;
59
- break;
 
60
  }
61
  }
62
- }
63
 
64
- if ( ! $icon_found ) {
65
- // No icons found, fallback to default icon.
66
- copy( fs_normalize_path( $img_dir . '/plugin-icon.png' ), $local_path );
67
- }
 
 
 
 
 
 
68
 
69
- $icons = array( $local_path );
 
70
  }
71
 
72
- $relative_url = fs_img_url( substr( $icons[0], strlen( fs_normalize_path( $img_dir ) ) ), $img_dir );
 
73
  ?>
74
  <div class="fs-plugin-icon">
75
- <img src="<?php echo $relative_url ?>"/>
76
  </div>
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @var array $VARS
15
+ */
16
  $slug = $VARS['slug'];
17
  $fs = freemius( $slug );
18
 
19
+ /**
20
+ * @since 1.1.7.5
21
+ */
22
+ $local_path = $fs->apply_filters( 'plugin_icon', false );
23
+
24
+ if ( is_string( $local_path ) ) {
25
+ $icons = array( $local_path );
26
+ } else {
27
+ global $fs_active_plugins;
28
 
29
+ $img_dir = WP_FS__DIR_IMG;
30
 
31
+ if ( 1 < count( $fs_active_plugins->plugins ) ) {
32
+ foreach ( $fs_active_plugins->plugins as $sdk_path => &$data ) {
33
+ if ( $data->plugin_path == $fs->get_plugin_basename() ) {
34
+ $img_dir = WP_PLUGIN_DIR . '/' . $sdk_path . '/assets/img';
35
+ break;
36
+ }
37
  }
38
  }
 
39
 
40
+ $icons = glob( fs_normalize_path( $img_dir . '/' . $slug . '.*' ) );
41
+ if ( ! is_array( $icons ) || 0 === count( $icons ) ) {
42
+ $icon_found = false;
43
+ $local_path = fs_normalize_path( $img_dir . '/' . $slug . '.png' );
44
+ $have_write_permissions = is_writable( fs_normalize_path( $img_dir ) );
45
 
46
+ if ( WP_FS__IS_LOCALHOST && $fs->is_org_repo_compliant() && $have_write_permissions ) {
47
+ /**
48
+ * IMPORTANT: THIS CODE WILL NEVER RUN AFTER THE PLUGIN IS IN THE REPO.
49
+ *
50
+ * This code will only be executed once during the testing
51
+ * of the plugin in a local environment. The plugin icon file WILL
52
+ * already exist in the assets folder when the plugin is deployed to
53
+ * the repository.
54
+ */
55
+ $suffixes = array(
56
+ '-128x128.png',
57
+ '-128x128.jpg',
58
+ '-256x256.png',
59
+ '-256x256.jpg',
60
+ '.svg',
61
+ );
62
 
63
+ $base_url = 'https://plugins.svn.wordpress.org/' . $slug . '/assets/icon';
64
 
65
+ foreach ( $suffixes as $s ) {
66
+ $headers = get_headers( $base_url . $s );
67
+ if ( strpos( $headers[0], '200' ) ) {
68
+ $local_path = fs_normalize_path( $img_dir . '/' . $slug . '.' . substr( $s, strpos( $s, '.' ) + 1 ) );
69
+ fs_download_image( $base_url . $s, $local_path );
70
+ $icon_found = true;
71
+ break;
72
+ }
73
  }
74
  }
 
75
 
76
+ if ( ! $icon_found ) {
77
+ // No icons found, fallback to default icon.
78
+ if ( $have_write_permissions ) {
79
+ // If have write permissions, copy default icon.
80
+ copy( fs_normalize_path( $img_dir . '/plugin-icon.png' ), $local_path );
81
+ } else {
82
+ // If doesn't have write permissions, use default icon path.
83
+ $local_path = fs_normalize_path( $img_dir . '/plugin-icon.png' );
84
+ }
85
+ }
86
 
87
+ $icons = array( $local_path );
88
+ }
89
  }
90
 
91
+ $icon_dir = dirname( $icons[0] );
92
+ $relative_url = fs_img_url( substr( $icons[0], strlen( $icon_dir ) ), $icon_dir );
93
  ?>
94
  <div class="fs-plugin-icon">
95
+ <img src="<?php echo $relative_url ?>" width="80" height="80" />
96
  </div>
freemius/templates/plugin-info/description.php CHANGED
@@ -11,6 +11,8 @@
11
  }
12
 
13
  /**
 
 
14
  * @var FS_Plugin $plugin
15
  */
16
  $plugin = $VARS['plugin'];
11
  }
12
 
13
  /**
14
+ * @var array $VARS
15
+ *
16
  * @var FS_Plugin $plugin
17
  */
18
  $plugin = $VARS['plugin'];
freemius/templates/plugin-info/features.php CHANGED
@@ -11,6 +11,8 @@
11
  }
12
 
13
  /**
 
 
14
  * @var FS_Plugin $plugin
15
  */
16
  $plugin = $VARS['plugin'];
11
  }
12
 
13
  /**
14
+ * @var array $VARS
15
+ *
16
  * @var FS_Plugin $plugin
17
  */
18
  $plugin = $VARS['plugin'];
freemius/templates/plugin-info/screenshots.php CHANGED
@@ -11,6 +11,8 @@
11
  }
12
 
13
  /**
 
 
14
  * @var FS_Plugin $plugin
15
  */
16
  $plugin = $VARS['plugin'];
11
  }
12
 
13
  /**
14
+ * @var array $VARS
15
+ *
16
  * @var FS_Plugin $plugin
17
  */
18
  $plugin = $VARS['plugin'];
freemius/templates/powered-by.php CHANGED
@@ -10,9 +10,7 @@
10
  exit;
11
  }
12
 
13
- /**
14
- * KEEP THE POWERED BY TAB AND GET ADDITIONAL - 1% - OFF THE COMMISSION
15
- */
16
 
17
  wp_enqueue_script( 'jquery' );
18
  wp_enqueue_script( 'json2' );
@@ -26,7 +24,7 @@
26
  $(function () {
27
  var
28
  base_url = '<?php echo WP_FS__ADDRESS ?>',
29
- 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>')
30
  .appendTo('#piframe');
31
 
32
  FS.PostMessage.init(base_url);
10
  exit;
11
  }
12
 
13
+ $VARS = isset($VARS) ? $VARS : array();
 
 
14
 
15
  wp_enqueue_script( 'jquery' );
16
  wp_enqueue_script( 'json2' );
24
  $(function () {
25
  var
26
  base_url = '<?php echo WP_FS__ADDRESS ?>',
27
+ piframe = $('<iframe id="fs_promo_tab" src="' + base_url + '/promotional-tab/?<?php echo http_build_query($VARS) ?>#' + encodeURIComponent(document.location.href) + '" height="350" width="60" frameborder="0" style=" background: transparent; position: fixed; top: 20%; right: 0;" scrolling="no"></iframe>')
28
  .appendTo('#piframe');
29
 
30
  FS.PostMessage.init(base_url);
freemius/templates/pricing.php CHANGED
@@ -15,6 +15,9 @@
15
  fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
 
 
 
 
18
  $slug = $VARS['slug'];
19
  $fs = freemius( $slug );
20
  $timestamp = time();
@@ -44,7 +47,7 @@
44
  }
45
 
46
  $query_params = array_merge( $context_params, $_GET, array(
47
- 'next' => $fs->_get_admin_page_url( 'account', array( 'fs_action' => $slug . '_sync_license' ) ),
48
  'plugin_version' => $fs->get_plugin_version(),
49
  // Billing cycle.
50
  'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),
@@ -97,4 +100,12 @@
97
  })(jQuery);
98
  </script>
99
  </div>
100
- <?php fs_require_template( 'powered-by.php' ) ?>
 
 
 
 
 
 
 
 
15
  fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
16
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
 
18
+ /**
19
+ * @var array $VARS
20
+ */
21
  $slug = $VARS['slug'];
22
  $fs = freemius( $slug );
23
  $timestamp = time();
47
  }
48
 
49
  $query_params = array_merge( $context_params, $_GET, array(
50
+ 'next' => $fs->_get_sync_license_url( false, false ),
51
  'plugin_version' => $fs->get_plugin_version(),
52
  // Billing cycle.
53
  'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),
100
  })(jQuery);
101
  </script>
102
  </div>
103
+ <?php
104
+ $params = array(
105
+ 'page' => 'pricing',
106
+ 'module_id' => $fs->get_id(),
107
+ 'module_slug' => $slug,
108
+ 'module_version' => $fs->get_plugin_version(),
109
+ );
110
+ fs_require_template( 'powered-by.php', $params );
111
+ ?>
freemius/templates/sticky-admin-notice-js.php CHANGED
@@ -23,7 +23,7 @@
23
 
24
  notice.fadeOut('fast', function(){
25
  var data = {
26
- action: slug + '_dismiss_notice_action',
27
  slug: slug,
28
  message_id: id
29
  };
23
 
24
  notice.fadeOut('fast', function(){
25
  var data = {
26
+ action: 'fs_dismiss_notice_action_' + slug,
27
  slug: slug,
28
  message_id: id
29
  };
js/ajax.js CHANGED
@@ -14,11 +14,17 @@
14
  }
15
  );
16
  $('button.tweet').on('click', function (e) {
 
 
 
 
17
  e.preventDefault();
18
- var text = $('#jtw').val();
19
- var date = $('#jts .date').val();
20
- var time = $('#jts .time').val();
21
- var auth = $('#jts #wpt_authorized_users').val();
 
 
22
  var tweet_action = ( $(this).attr('data-action') === 'tweet' ) ? 'tweet' : 'schedule'
23
  var data = {
24
  'action': wpt_data.action,
@@ -27,6 +33,7 @@
27
  'tweet_schedule': date + ' ' + time,
28
  'tweet_action': tweet_action,
29
  'tweet_auth': auth,
 
30
  'security': wpt_data.security
31
  };
32
  $.post(ajaxurl, data, function (response) {
14
  }
15
  );
16
  $('button.tweet').on('click', function (e) {
17
+ visible = $( '.wpt_log' ).is( ':visible' );
18
+ if ( visible ) {
19
+ $( '.wpt_log' ).hide( 200 );
20
+ }
21
  e.preventDefault();
22
+ var text = $('#jtw').val();
23
+ var date = $('#jts .date').val();
24
+ var time = $('#jts .time').val();
25
+ var auth = $('#wpt_authorized_users').val();
26
+
27
+ var upload = $('input:radio[name=_wpt_image]:checked').val();
28
  var tweet_action = ( $(this).attr('data-action') === 'tweet' ) ? 'tweet' : 'schedule'
29
  var data = {
30
  'action': wpt_data.action,
33
  'tweet_schedule': date + ' ' + time,
34
  'tweet_action': tweet_action,
35
  'tweet_auth': auth,
36
+ 'tweet_upload': upload,
37
  'security': wpt_data.security
38
  };
39
  $.post(ajaxurl, data, function (response) {
lang/wp-to-twitter-en_AU.mo DELETED
Binary file
readme.txt CHANGED
@@ -2,11 +2,11 @@
2
  Contributors: joedolson
3
  Donate link: http://www.joedolson.com/donate/
4
  Tags: twitter, microblogging, su.pr, bitly, yourls, redirect, shortener, post, links, social, sharing, media, tweet
5
- Requires at least: 4.1
6
- Tested up to: 4.4.2
7
  License: GPLv2 or later
8
  Text Domain: wp-to-twitter
9
- Stable tag: 3.1.9
10
 
11
  Posts a Twitter update when you update your WordPress blog or add a link, with your chosen URL shortening service.
12
 
@@ -40,7 +40,7 @@ WP to Twitter uses a customizable Tweet template for Tweets sent when updating o
40
  Upgrade to [WP Tweets Pro](http://www.joedolson.com/wp-tweets-pro/) for extra features, including:
41
 
42
  * Authors can set up their own Twitter accounts in their profiles
43
- * Time delayed Tweeting
44
  * Scheduled Tweet management
45
  * Simultaneously Tweet to site and author Twitter accounts
46
  * Preview and Tweet comments
@@ -60,12 +60,115 @@ Translating my plug-ins is always appreciated. Work on WP to Twitter translation
60
 
61
  == Changelog ==
62
 
63
- = Future =
64
 
65
- * Use apply_filters( 'wpt_tweet_sentence', $tweet, $post_ID ) to pass custom taxonomy Tweet formats - Pending WordPress support for taxonomy meta.
66
- * Add regex filter to detect URLs typed into Tweet fields for counting/shortening purposes. [todo]
67
- * 4.2 added compat function for mb_substr; drop mine when I drop support for 4.1
68
- * WP to Twitter timing bug with images?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  = 3.2.0 =
71
 
@@ -239,7 +342,7 @@ Right here: [WP to Twitter FAQ](http://www.joedolson.com/wp-to-twitter/support-2
239
 
240
  = How can I help you make WP to Twitter a better plug-in? =
241
 
242
- Writing and maintaining a plug-in is a lot of work. You can help me by providing detailed support requests (which saves me time), or by providing financial support, either via my [plug-in donations page](https://www.joedolson.com/donate/) or by [upgrading to WP Tweets Pro](https://www.joedolson.com/wp-tweets-pro/). Believe me, your donation really makes a difference!
243
 
244
  == Screenshots ==
245
 
@@ -252,4 +355,4 @@ Writing and maintaining a plug-in is a lot of work. You can help me by providing
252
 
253
  == Upgrade Notice ==
254
 
255
- * 3.1.6 - Rewritten Tweet truncating functions; minor bug fixes.
2
  Contributors: joedolson
3
  Donate link: http://www.joedolson.com/donate/
4
  Tags: twitter, microblogging, su.pr, bitly, yourls, redirect, shortener, post, links, social, sharing, media, tweet
5
+ Requires at least: 4.4
6
+ Tested up to: 4.8
7
  License: GPLv2 or later
8
  Text Domain: wp-to-twitter
9
+ Stable tag: 3.2.19
10
 
11
  Posts a Twitter update when you update your WordPress blog or add a link, with your chosen URL shortening service.
12
 
40
  Upgrade to [WP Tweets Pro](http://www.joedolson.com/wp-tweets-pro/) for extra features, including:
41
 
42
  * Authors can set up their own Twitter accounts in their profiles
43
+ * Time delayed Tweeting
44
  * Scheduled Tweet management
45
  * Simultaneously Tweet to site and author Twitter accounts
46
  * Preview and Tweet comments
60
 
61
  == Changelog ==
62
 
63
+ * TODO: explore use of emojis in templates; they work in custom Tweets
64
 
65
+ = 3.2.19 =
66
+
67
+ * Bug fix: account for mixed return values in get_the_tags()
68
+
69
+ = 3.2.18 =
70
+
71
+ * Bug fix: Only save last Tweet if sent successfully (See https://wordpress.org/support/topic/character-count-not-updating-and-subsequent-tweets-not-going-through/#post-9338623)
72
+ * Bug fix: in truncation settings, match displayed tag names to tags used in templates.
73
+ * Text fixes: clarify YOURLS settings notices & fields
74
+ * Add option: Hash tags from categories instead of tags
75
+ * Bug fix: incorrect url
76
+
77
+ = 3.2.17 =
78
+
79
+ * Function name change in primary function.
80
+ * Early exit in wpt-feed
81
+ * Fix icon in metabox headings
82
+ * Misc. minor design tweaks
83
+
84
+ = 3.2.16 =
85
+
86
+ * Bug fix: missing check to verify array caused AJAX error
87
+
88
+ = 3.2.15 =
89
+
90
+ * Bug fix: "Tweet Now" button threw error if selecting main site account [Pro]
91
+ * New action executed when posting to Twitter
92
+ * New debugging point in media retrieval
93
+
94
+ = 3.2.14 =
95
+
96
+ * Bug fix: activation status of licenses in WP Tweets Pro misreported in support data
97
+ * Removed longurl.org expander since the service has been shut down.
98
+ * Exclude uploaded media URLs from character counting (WP Tweets Pro)
99
+ * Feature: Support adding custom templates for specific taxonomy terms (WP Tweets Pro)
100
+
101
+ = 3.2.13 =
102
+
103
+ * Bug fix: help/config should not be queried if user has not yet authenticated.
104
+
105
+ = 3.2.12 =
106
+
107
+ * Bug fix: call help/config to check t.co URL lengths and make sure length used is current value
108
+ * Parse URLs in text and send to URL shortener before Tweeting.
109
+ * Test for WordPress 4.6
110
+
111
+ = 3.2.11 =
112
+
113
+ * Two new filters in post meta box
114
+ * Add option to set your own Goo.gl API key for improved shortener reliability
115
+ * Removed my fallback functions for mb_substr and mb_strlen & support for WordPress 4.1
116
+ * Fixed a broken URL
117
+ * Updated sales copy
118
+
119
+ = 3.2.10 =
120
+
121
+ * Bug fix: extra closing `p` tag in widget output.
122
+ * Feature: pattern for getting arbitrary author meta: {{meta_field}}
123
+ * Minor security fix: ignored wpnonce verification if nonce not provided in settings admin.
124
+
125
+ = 3.2.9 =
126
+
127
+ * Bug fix: extra is_admin call in Freemius implementation
128
+ * Feature: 'Tweet Now' & dynamic scheduling recognizes currently selected users & upload media status (Pro)
129
+
130
+ = 3.2.8 =
131
+
132
+ * Bug fix: Stray debugging email in curl processing.
133
+
134
+ = 3.2.7 =
135
+
136
+ * Feature: prevent Duplicate Posts plug-in from copying WP to Twitter meta data
137
+ * Feature: add curl fallback in case WP_http doesn't function correctly.
138
+ * Feature: support for image alt attributes in widget
139
+ * Feature: support for selective refresh in customizer
140
+ * Feature: improved error messages from Twitter
141
+ * Change: added Freemius service back to plug-in
142
+ * Bug fix: disconnect Twitter account in user accounts (PRO)
143
+
144
+ = 3.2.6 =
145
+
146
+ * Bug fix: wrap Twitter follow button in div to prevent obscure Blink rendering bug.
147
+ * Bug fix: obscure bug saving incorrect short URL when saving draft
148
+
149
+ = 3.2.5 =
150
+
151
+ * Bug fix: added prefix to is_valid_url (function used by some other plug-ins)
152
+ * Bug fix: undismissable promotion for WP Tweets PRO
153
+ * Minor style changes
154
+
155
+ = 3.2.4 =
156
+
157
+ * Bug fix: functionalized uninstall, but placed in file only imported while WPT active.
158
+
159
+ = 3.2.3 =
160
+
161
+ * Remove Freemius integration due to excessive API load.
162
+
163
+ = 3.2.2 =
164
+
165
+ * Only call Freemius integration in admin.
166
+
167
+ = 3.2.1 =
168
+
169
+ * Bug fix: uninstall issue with Freemius
170
+ * Bug fix: extraneous function call with Freemius
171
+ * More style streamlining
172
 
173
  = 3.2.0 =
174
 
342
 
343
  = How can I help you make WP to Twitter a better plug-in? =
344
 
345
+ Writing and maintaining a plug-in is a lot of work. You can help me by providing detailed support requests (which saves me time), or by providing financial support, either via my [plug-in donations page](https://www.joedolson.com/donate/) or by [upgrading to WP Tweets Pro](http://www.wptweetspro.com/wp-tweets-pro). Believe me, your donation really makes a difference!
346
 
347
  == Screenshots ==
348
 
355
 
356
  == Upgrade Notice ==
357
 
358
+ * 3.2.10: Minor security fix; recommend updating immediately.
tmhOAuth/tmhOAuth.php CHANGED
@@ -731,7 +731,7 @@ class tmhOAuth {
731
  if ( isset( $this->config['prevent_request'] ) && ( true == $this->config['prevent_request'] ) ) {
732
  return 0;
733
  }
734
-
735
  // do it!
736
  $response = curl_exec( $c );
737
  $code = curl_getinfo( $c, CURLINFO_HTTP_CODE );
731
  if ( isset( $this->config['prevent_request'] ) && ( true == $this->config['prevent_request'] ) ) {
732
  return 0;
733
  }
734
+
735
  // do it!
736
  $response = curl_exec( $c );
737
  $code = curl_getinfo( $c, CURLINFO_HTTP_CODE );
uninstall.php DELETED
@@ -1,98 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) && ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
3
- exit();
4
- } else {
5
- delete_option( 'wpt_post_types' );
6
- delete_option( 'jd_twit_remote' );
7
- delete_option( 'jd_post_excerpt' );
8
-
9
- delete_option( 'comment-published-update' );
10
- delete_option( 'comment-published-text' );
11
- delete_option( 'wpt_status_message_last' );
12
- delete_option( 'wtt_twitter_username' );
13
- // Su.pr API
14
- delete_option( 'suprapi' );
15
-
16
- // Error checking
17
- delete_option( 'jd-functions-checked' );
18
- delete_option( 'wp_twitter_failure' );
19
- delete_option( 'wp_supr_failure' );
20
- delete_option( 'wp_url_failure' );
21
- delete_option( 'wp_bitly_failure' );
22
- delete_option( 'wpt_curl_error' );
23
-
24
- // Rate Limiting
25
- delete_option( 'wpt_rate_limits' );
26
- delete_option( 'wpt_default_rate_limit' );
27
- delete_option( 'wpt_rate_limit' );
28
- delete_option( 'wpt_rate_limiting' );
29
-
30
- // Blogroll options
31
- delete_option( 'jd-use-link-title' );
32
- delete_option( 'jd-use-link-description' );
33
- delete_option( 'newlink-published-text' );
34
- delete_option( 'jd_twit_blogroll' );
35
-
36
- // Default publishing options.
37
- delete_option( 'jd_tweet_default' );
38
- delete_option( 'jd_tweet_default_edit' );
39
- delete_option( 'wpt_inline_edits' );
40
-
41
- // Note that default options are set.
42
- delete_option( 'twitterInitialised' );
43
- delete_option( 'wpt_twitter_setup' );
44
- delete_option( 'wp_twitter_failure' );
45
- delete_option( 'twitterlogin' );
46
- delete_option( 'twitterpw' );
47
- delete_option( 'twitterlogin_encrypted' );
48
- delete_option( 'suprapi' );
49
- delete_option( 'jd_twit_quickpress' );
50
- delete_option( 'jd-use-supr' );
51
- delete_option( 'jd-use-none' );
52
- delete_option( 'jd-use-wp' );
53
-
54
- // Special Options
55
- delete_option( 'jd_twit_prepend' );
56
- delete_option( 'jd_twit_append' );
57
- delete_option( 'jd_twit_remote' );
58
- delete_option( 'twitter-analytics-campaign' );
59
- delete_option( 'use-twitter-analytics' );
60
- delete_option( 'jd_twit_custom_url' );
61
- delete_option( 'jd_shortener' );
62
- delete_option( 'jd_strip_nonan' );
63
-
64
- delete_option( 'jd_individual_twitter_users' );
65
- delete_option( 'use_tags_as_hashtags' );
66
- delete_option( 'jd_max_tags' );
67
- delete_option( 'jd_max_characters' );
68
- // Bitly Settings
69
- delete_option( 'bitlylogin' );
70
- delete_option( 'jd-use-bitly' );
71
- delete_option( 'bitlyapi' );
72
-
73
- // twitter compatible api
74
- delete_option( 'jd_api_post_status' );
75
- delete_option( 'app_consumer_key' );
76
- delete_option( 'app_consumer_secret' );
77
- delete_option( 'oauth_token' );
78
- delete_option( 'oauth_token_secret' );
79
-
80
- //dymamic analytics
81
- delete_option( 'jd_dynamic_analytics' );
82
- delete_option( 'use_dynamic_analytics' );
83
- //category limits
84
- delete_option( 'limit_categories' );
85
- delete_option( 'tweet_categories' );
86
- //yourls installation
87
- delete_option( 'yourlsapi' );
88
- delete_option( 'yourlspath' );
89
- delete_option( 'yourlsurl' );
90
- delete_option( 'yourlslogin' );
91
- delete_option( 'jd_replace_character' );
92
- delete_option( 'jd_date_format' );
93
- delete_option( 'jd_keyword_format' );
94
- //Version
95
- delete_option( 'wp_to_twitter_version' );
96
- delete_option( 'wpt_authentication_missing' );
97
- delete_option( 'wpt_http' );
98
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
wp-to-twitter-manager.php CHANGED
@@ -5,12 +5,14 @@ if ( ! defined( 'ABSPATH' ) ) {
5
 
6
  function wpt_updated_settings() {
7
  wpt_check_version();
8
-
9
- if ( ! empty( $_POST['_wpnonce'] ) ) {
10
- $nonce = $_REQUEST['_wpnonce'];
11
- if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
12
- die( "Security check failed" );
13
- }
 
 
14
  }
15
 
16
  if ( isset( $_POST['oauth_settings'] ) ) {
@@ -80,6 +82,8 @@ function wpt_updated_settings() {
80
  update_option( 'jd_twit_append', $_POST['jd_twit_append'] );
81
  update_option( 'jd_post_excerpt', $_POST['jd_post_excerpt'] );
82
  update_option( 'jd_max_tags', $_POST['jd_max_tags'] );
 
 
83
  update_option( 'wpt_tag_source', ( ( isset( $_POST['wpt_tag_source'] ) && $_POST['wpt_tag_source'] == 'slug' ) ? 'slug' : '' ) );
84
  update_option( 'jd_max_characters', $_POST['jd_max_characters'] );
85
  update_option( 'jd_replace_character', $_POST['jd_replace_character'] );
@@ -185,6 +189,8 @@ function wpt_update_settings() {
185
  <?php $elem = ( version_compare( '4.3', get_option( 'version' ), '>=' ) ) ? 'h1' : 'h2'; ?>
186
  <<?php echo $elem; ?>><?php _e( "WP to Twitter Options", 'wp-to-twitter' ); ?></<?php echo $elem; ?>>
187
 
 
 
188
  <div class='nav-tab-wrapper'>
189
  <?php wpt_settings_tabs(); ?>
190
  </div>
@@ -222,14 +228,15 @@ function wpt_update_settings() {
222
  <li><?php _e( 'Publish to unique Twitter accounts for each site author.','wp-to-twitter' ); ?></li>
223
  <li><?php _e( 'Schedule up to 3 re-posts of Tweets at an interval of your choice.', 'wp-to-twitter' ); ?></li>
224
  <li><?php _e( 'With a delay between publishing and Tweeting, verify your tweets before you share online.', 'wp-to-twitter' ); ?></li>
 
 
 
225
  </ul>
226
  <p>
227
- <?php
228
- _e( "Use WP Tweets PRO to keep traffic coming for every post.", 'wp-to-twitter' );
229
- ?>
230
  </p>
231
  <p class='wpt-button'>
232
- <strong class='cta'><a href="https://www.joedolson.com/wp-tweets-pro/"><?php _e( 'Upgrade to <strong>WP Tweets PRO</strong>!', 'wp-to-twitter' ); ?></a></strong>
233
  </p>
234
 
235
  <h4><?php _e( 'What else does WP Tweets PRO do?', 'wp-to-twitter' ); ?></h4>
@@ -238,11 +245,14 @@ function wpt_update_settings() {
238
  <?php _e( 'WP Tweets PRO is packed with features to help you increase engagement with your Twitter followers. Upload images, use Twitter Cards, and automated re-posting of your Tweets are just a few of the features available in the premium add-on to WP to Twitter.', 'wp-to-twitter' ); ?>
239
  </p>
240
  <p>
241
- <?php sprintf( _e( '<a href="%s">Learn more about WP Tweets PRO</a>!', 'wp-to-twitter' ), 'https://www.joedolson.com/wp-tweets-pro/?campaign=get-wpt' ); ?>
 
 
 
242
  </p>
243
 
244
  <p class='wpt-button'>
245
- <strong class='cta'><a href="https://www.joedolson.com/wp-tweets-pro/"><?php _e( 'Buy WP Tweets PRO today!', 'wp-to-twitter' ); ?></a></strong>
246
  </p>
247
 
248
  </div>
@@ -317,7 +327,7 @@ function wpt_update_settings() {
317
  }
318
  echo "</ul>";
319
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
320
- printf( __( '<a href="%s">Upgrade to WP Tweets PRO</a> to filter posts in all custom post types on any taxonomy.', 'wp-to-twitter' ), "https://www.joedolson.com/wp-tweets-pro/" );
321
  } else {
322
  _e( 'Updating the WP Tweets PRO taxonomy filters will overwrite your old category filters.', 'wp-to-twitter' );
323
  }
@@ -385,14 +395,10 @@ function wpt_update_settings() {
385
  </p>
386
  </fieldset>
387
  </div>
388
- <br class='clear'/>
389
-
390
  <div>
391
- <input type="hidden" name="submit-type" value="options"/>
392
  </div>
393
- <input type="submit" name="submit"
394
- value="<?php _e( "Save WP to Twitter Options", 'wp-to-twitter' ); ?>"
395
- class="button-primary"/>
396
  </div>
397
  </form>
398
  </div>
@@ -432,6 +438,15 @@ function wpt_update_settings() {
432
  _e( "<strong>Example:</strong> <code>[[custom_field]]</code>", 'wp-to-twitter' );
433
  ?>
434
  </p>
 
 
 
 
 
 
 
 
 
435
  </div>
436
  </div>
437
  </div>
@@ -467,7 +482,10 @@ function wpt_update_settings() {
467
  <label
468
  for="wpt_tag_source"><?php _e( "Use tag slug as hashtag value", 'wp-to-twitter' ); ?></label><br/>
469
  </p>
470
-
 
 
 
471
  <p>
472
  <label
473
  for="jd_replace_character"><?php _e( "Spaces in tags replaced with:", 'wp-to-twitter' ); ?></label>
@@ -672,7 +690,13 @@ function wpt_update_settings() {
672
  }
673
  asort( $default_order );
674
  foreach ( $default_order as $k => $v ) {
675
- $label = '<code>#' . $k . '#</code>';
 
 
 
 
 
 
676
  $inputs .= "<div class='wpt-truncate'><label for='$k-$v'>$label</label><br /><input type='number' size='3' value='$v' name='wpt_truncation_order[$k]' /></div> ";
677
  }
678
  ?>
@@ -721,7 +745,7 @@ function wpt_update_settings() {
721
  <div class='wpt-support-me'>
722
  <p>
723
  <?php printf(
724
- __( 'Please, consider a <a href="%s">purchase</a> to support WP to Twitter!', 'wp-to-twitter' ), "https://www.joedolson.com/wp-tweets-pro/" ); ?>
725
  </p>
726
  </div>
727
  <?php } ?>
@@ -753,7 +777,7 @@ function wpt_sidebar() {
753
  <?php } ?>
754
  <div class="inside resources">
755
  <?php if ( get_option( 'jd_donations' ) != 1 && ! function_exists( 'wpt_pro_exists' ) ) { ?>
756
- <p class='cta'><?php _e( '<a href="https://www.joedolson.com/wp-tweets-pro/">Get WP Tweets Pro</a>', 'wp-to-twitter' ); ?></p>
757
  <?php } ?>
758
  <p>
759
  <a href="https://twitter.com/intent/follow?screen_name=joedolson" class="twitter-follow-button"
@@ -802,14 +826,12 @@ function wpt_sidebar() {
802
  <?php _e( 'Check whether WP to Twitter is setup correctly for Twitter and your URL Shortener. The test sends a status update to Twitter and shortens a URL using your chosen shortener.', 'wp-to-twitter' ); ?>
803
  </p>
804
  <form method="post" action="">
805
- <fieldset>
806
- <input type="hidden" name="submit-type" value="check-support"/>
807
- <?php $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
808
- echo "<div>$nonce</div>"; ?>
809
- <p>
810
- <input type="submit" name="submit" value="<?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?>" class="button-primary" />
811
- </p>
812
- </fieldset>
813
  </form>
814
  </div>
815
  </div>
5
 
6
  function wpt_updated_settings() {
7
  wpt_check_version();
8
+
9
+ if ( empty( $_POST ) ) {
10
+ return;
11
+ }
12
+
13
+ $nonce = $_REQUEST['_wpnonce'];
14
+ if ( ! wp_verify_nonce( $nonce, 'wp-to-twitter-nonce' ) ) {
15
+ die( "Security check failed" );
16
  }
17
 
18
  if ( isset( $_POST['oauth_settings'] ) ) {
82
  update_option( 'jd_twit_append', $_POST['jd_twit_append'] );
83
  update_option( 'jd_post_excerpt', $_POST['jd_post_excerpt'] );
84
  update_option( 'jd_max_tags', $_POST['jd_max_tags'] );
85
+ $use_cats = ( isset( $_POST['wpt_use_cats'] ) ) ? $_POST['wpt_use_cats'] : 0;
86
+ update_option( 'wpt_use_cats', $use_cats );
87
  update_option( 'wpt_tag_source', ( ( isset( $_POST['wpt_tag_source'] ) && $_POST['wpt_tag_source'] == 'slug' ) ? 'slug' : '' ) );
88
  update_option( 'jd_max_characters', $_POST['jd_max_characters'] );
89
  update_option( 'jd_replace_character', $_POST['jd_replace_character'] );
189
  <?php $elem = ( version_compare( '4.3', get_option( 'version' ), '>=' ) ) ? 'h1' : 'h2'; ?>
190
  <<?php echo $elem; ?>><?php _e( "WP to Twitter Options", 'wp-to-twitter' ); ?></<?php echo $elem; ?>>
191
 
192
+ <?php wpt_max_length(); ?>
193
+
194
  <div class='nav-tab-wrapper'>
195
  <?php wpt_settings_tabs(); ?>
196
  </div>
228
  <li><?php _e( 'Publish to unique Twitter accounts for each site author.','wp-to-twitter' ); ?></li>
229
  <li><?php _e( 'Schedule up to 3 re-posts of Tweets at an interval of your choice.', 'wp-to-twitter' ); ?></li>
230
  <li><?php _e( 'With a delay between publishing and Tweeting, verify your tweets before you share online.', 'wp-to-twitter' ); ?></li>
231
+ <li><?php _e( 'Automatically your great old posts every few hours, days, or weeks!', 'wp-to-twitter' ); ?></li>
232
+ <li><?php _e( 'Upload your featured images to Twitter with each Tweet', 'wp-to-twitter' ); ?></li>
233
+ <li><?php printf( __( 'Take a look at the <a href="%s">complete feature list</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' ); ?></li>
234
  </ul>
235
  <p>
236
+ <strong><?php _e( "Use WP Tweets PRO to keep traffic coming for every post.", 'wp-to-twitter' ); ?></strong>
 
 
237
  </p>
238
  <p class='wpt-button'>
239
+ <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Upgrade to <strong>WP Tweets PRO</strong>!', 'wp-to-twitter' ); ?></a></strong>
240
  </p>
241
 
242
  <h4><?php _e( 'What else does WP Tweets PRO do?', 'wp-to-twitter' ); ?></h4>
245
  <?php _e( 'WP Tweets PRO is packed with features to help you increase engagement with your Twitter followers. Upload images, use Twitter Cards, and automated re-posting of your Tweets are just a few of the features available in the premium add-on to WP to Twitter.', 'wp-to-twitter' ); ?>
246
  </p>
247
  <p>
248
+ <?php printf( __( 'Is there something that WP Tweets PRO <em>doesn\'t already do for you</em>? No problem! Take a look at the extensive <a href="%s">library of plug-in extensions</a> - you can try out or modify any of these code samples to extend and customize WP Tweets PRO.', 'wp-to-twitter' ), 'https://github.com/joedolson/plugin-extensions/tree/master/wp-to-twitter' ); ?>
249
+ </p>
250
+ <p>
251
+ <?php printf( __( '<a href="%s">Learn more about WP Tweets PRO</a>!', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro?campaign=get-wpt' ); ?>
252
  </p>
253
 
254
  <p class='wpt-button'>
255
+ <strong class='cta'><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Buy WP Tweets PRO today!', 'wp-to-twitter' ); ?></a></strong>
256
  </p>
257
 
258
  </div>
327
  }
328
  echo "</ul>";
329
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
330
+ printf( __( '<a href="%s">Upgrade to WP Tweets PRO</a> to filter posts in all custom post types on any taxonomy.', 'wp-to-twitter' ), "http://www.wptweetspro.com/wp-tweets-pro" );
331
  } else {
332
  _e( 'Updating the WP Tweets PRO taxonomy filters will overwrite your old category filters.', 'wp-to-twitter' );
333
  }
395
  </p>
396
  </fieldset>
397
  </div>
 
 
398
  <div>
399
+ <input type="hidden" name="submit-type" value="options" />
400
  </div>
401
+ <input type="submit" name="submit" value="<?php _e( "Save WP to Twitter Options", 'wp-to-twitter' ); ?>" class="button-primary"/>
 
 
402
  </div>
403
  </form>
404
  </div>
438
  _e( "<strong>Example:</strong> <code>[[custom_field]]</code>", 'wp-to-twitter' );
439
  ?>
440
  </p>
441
+ <p>
442
+ <?php
443
+ _e( "Create custom shortcodes and access the post author's custom user meta fields by using curly brackets and the name of the custom field.", 'wp-to-twitter' );
444
+ ?>
445
+ <br />
446
+ <?php
447
+ _e( "<strong>Example:</strong> <code>{{user_meta}}</code>", 'wp-to-twitter' );
448
+ ?>
449
+ </p>
450
  </div>
451
  </div>
452
  </div>
482
  <label
483
  for="wpt_tag_source"><?php _e( "Use tag slug as hashtag value", 'wp-to-twitter' ); ?></label><br/>
484
  </p>
485
+ <p>
486
+ <input type="checkbox" name="wpt_use_cats" id="wpt_use_cats" value="1" <?php checked( get_option( 'wpt_use_cats' ), '1' ); ?> />
487
+ <label for="wpt_use_cats"><?php _e( "Use categories instead of tags", 'wp-to-twitter' ); ?></label><br/>
488
+ </p>
489
  <p>
490
  <label
491
  for="jd_replace_character"><?php _e( "Spaces in tags replaced with:", 'wp-to-twitter' ); ?></label>
690
  }
691
  asort( $default_order );
692
  foreach ( $default_order as $k => $v ) {
693
+ if ( $k == 'blogname' ) {
694
+ $label = '<code>#blog#</code>';
695
+ } else if ( $k == 'excerpt' ) {
696
+ $label = '<code>#post#</code>';
697
+ } else {
698
+ $label = '<code>#' . $k . '#</code>';
699
+ }
700
  $inputs .= "<div class='wpt-truncate'><label for='$k-$v'>$label</label><br /><input type='number' size='3' value='$v' name='wpt_truncation_order[$k]' /></div> ";
701
  }
702
  ?>
745
  <div class='wpt-support-me'>
746
  <p>
747
  <?php printf(
748
+ __( 'Please, consider a <a href="%s">purchase</a> to support WP to Twitter!', 'wp-to-twitter' ), "http://www.wptweetspro.com/wp-tweets-pro" ); ?>
749
  </p>
750
  </div>
751
  <?php } ?>
777
  <?php } ?>
778
  <div class="inside resources">
779
  <?php if ( get_option( 'jd_donations' ) != 1 && ! function_exists( 'wpt_pro_exists' ) ) { ?>
780
+ <p class='cta'><?php _e( '<a href="http://www.wptweetspro.com/wp-tweets-pro">Get WP Tweets Pro</a>', 'wp-to-twitter' ); ?></p>
781
  <?php } ?>
782
  <p>
783
  <a href="https://twitter.com/intent/follow?screen_name=joedolson" class="twitter-follow-button"
826
  <?php _e( 'Check whether WP to Twitter is setup correctly for Twitter and your URL Shortener. The test sends a status update to Twitter and shortens a URL using your chosen shortener.', 'wp-to-twitter' ); ?>
827
  </p>
828
  <form method="post" action="">
829
+ <input type="hidden" name="submit-type" value="check-support"/>
830
+ <?php $nonce = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false );
831
+ echo "<div>$nonce</div>"; ?>
832
+ <p>
833
+ <input type="submit" name="submit" value="<?php _e( 'Test WP to Twitter', 'wp-to-twitter' ); ?>" class="button-primary" />
834
+ </p>
 
 
835
  </form>
836
  </div>
837
  </div>
wp-to-twitter-oauth.php CHANGED
@@ -189,6 +189,10 @@ function wtt_connect_oauth( $auth = false ) {
189
  echo '<div class="postbox">';
190
  }
191
 
 
 
 
 
192
  $class = ( $auth ) ? 'wpt-profile' : 'wpt-settings';
193
  $form = ( ! $auth ) ? '<form action="" method="post">' : '';
194
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
@@ -269,12 +273,12 @@ function wtt_connect_oauth( $auth = false ) {
269
  $ots = ( ! $auth ) ? esc_attr( get_option( 'oauth_token_secret' ) ) : esc_attr( get_user_meta( $auth, 'oauth_token_secret', true ) );
270
  $uname = ( ! $auth ) ? esc_attr( get_option( 'wtt_twitter_username' ) ) : esc_attr( get_user_meta( $auth, 'wtt_twitter_username', true ) );
271
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
272
- if ( ! $auth ) {
273
  $submit = '
274
  <input type="submit" name="submit" class="button-primary" value="' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '" />
275
  <input type="hidden" name="oauth_settings" value="wtt_twitter_disconnect" class="hidden" />
276
  ';
277
- } else {
278
  $submit = '<input type="checkbox" name="oauth_settings" value="wtt_twitter_disconnect" id="disconnect" /> <label for="disconnect">' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '</label>';
279
  }
280
 
@@ -304,4 +308,21 @@ function wtt_connect_oauth( $auth = false ) {
304
  echo "</div>";
305
  echo "</div>";
306
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  }
189
  echo '<div class="postbox">';
190
  }
191
 
192
+ if ( $auth ) {
193
+ wpt_update_authenticated_users();
194
+ }
195
+
196
  $class = ( $auth ) ? 'wpt-profile' : 'wpt-settings';
197
  $form = ( ! $auth ) ? '<form action="" method="post">' : '';
198
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
273
  $ots = ( ! $auth ) ? esc_attr( get_option( 'oauth_token_secret' ) ) : esc_attr( get_user_meta( $auth, 'oauth_token_secret', true ) );
274
  $uname = ( ! $auth ) ? esc_attr( get_option( 'wtt_twitter_username' ) ) : esc_attr( get_user_meta( $auth, 'wtt_twitter_username', true ) );
275
  $nonce = ( ! $auth ) ? wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false ) . wp_referer_field( false ) . '</form>' : '';
276
+ if ( ! $auth ) {
277
  $submit = '
278
  <input type="submit" name="submit" class="button-primary" value="' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '" />
279
  <input type="hidden" name="oauth_settings" value="wtt_twitter_disconnect" class="hidden" />
280
  ';
281
+ } else {
282
  $submit = '<input type="checkbox" name="oauth_settings" value="wtt_twitter_disconnect" id="disconnect" /> <label for="disconnect">' . __( 'Disconnect your WordPress and Twitter Account', 'wp-to-twitter' ) . '</label>';
283
  }
284
 
308
  echo "</div>";
309
  echo "</div>";
310
  }
311
+ }
312
+
313
+ function wpt_update_authenticated_users() {
314
+ $args = array( 'meta_query' => array( array( 'key' => 'wtt_twitter_username', 'compare' => 'EXISTS' ) ) );
315
+ // get all authorized users
316
+ $users = get_users( $args );
317
+ $authorized_users = array();
318
+ if ( is_array( $users ) ) {
319
+ foreach ( $users as $this_user ) {
320
+ if ( wtt_oauth_test( $this_user->ID,'verify' ) ) {
321
+ $twitter = get_user_meta( $this_user->ID, 'wtt_twitter_username', true );
322
+ $authorized_users[] = array( 'ID'=>$this_user->ID, 'name'=>$this_user->display_name, 'twitter'=>$twitter );
323
+ }
324
+ }
325
+ }
326
+
327
+ update_option( 'wpt_authorized_users', $authorized_users );
328
  }
wp-to-twitter-shorteners.php CHANGED
@@ -7,7 +7,7 @@ if ( ! defined( 'ABSPATH' ) ) {
7
  if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in replacement.
8
  add_filter( 'wptt_shorten_link', 'wpt_shorten_url', 10, 4 );
9
 
10
- function wpt_shorten_url( $url, $thisposttitle, $post_ID, $testmode = false ) {
11
  wpt_mail( "Initial Link Data: #$post_ID", "$url, $thisposttitle, $post_ID, $testmode" ); // DEBUG
12
  // filter link before sending to shortener or adding analytics
13
  $shortener = get_option( 'jd_shortener' );
@@ -38,7 +38,11 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
38
  }
39
  $medium = urlencode( trim( apply_filters( 'wpt_utm_medium', 'twitter' ) ) );
40
  $source = urlencode( trim( apply_filters( 'wpt_utm_source', 'twitter' ) ) );
41
- $url = add_query_arg( array( 'utm_campaign'=>$campaign, 'utm_medium'=>$medium, 'utm_source'=>$source ), $url );
 
 
 
 
42
  }
43
  $url = urldecode( trim( $url ) ); // prevent double-encoding
44
  $encoded = urlencode( $url );
@@ -56,14 +60,8 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
56
  $error = false;
57
  if ( !$shrink ) {
58
  switch ( $shortener ) {
59
- case 4:
60
- if ( function_exists( 'wp_get_shortlink' ) ) {
61
- // wp_get_shortlink doesn't natively support custom post types; but don't return an error in that case.
62
- $shrink = ( $post_ID != false ) ? wp_get_shortlink( $post_ID, 'post' ) : $url;
63
- }
64
- if ( ! $shrink ) {
65
- $shrink = $url;
66
- }
67
  break;
68
  case 2: // updated to v3 3/31/2010
69
  $bitlyapi = trim( get_option( 'bitlyapi' ) );
@@ -71,7 +69,7 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
71
  $decoded = wpt_remote_json( "https://api-ssl.bitly.com/v3/shorten?longUrl=" . $encoded . "&login=" . $bitlylogin . "&apiKey=" . $bitlyapi . "&format=json" );
72
  if ( $decoded && isset( $decoded['status_code'] ) ) {
73
  if ( $decoded['status_code'] != 200 ) {
74
- $shrink = $decoded;
75
  $error = $decoded['status_txt'];
76
  } else {
77
  $shrink = $decoded['data']['url'];
@@ -79,10 +77,19 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
79
  } else {
80
  $shrink = false;
81
  }
82
- if ( ! is_valid_url( $shrink ) ) {
83
  $shrink = false;
84
  }
85
  break;
 
 
 
 
 
 
 
 
 
86
  case 5:
87
  // local YOURLS installation
88
  global $yourls_reserved_URL;
@@ -122,7 +129,6 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
122
  'signature' => $token,
123
  'url' => $encoded,
124
  'action' => 'shorturl',
125
- 'keyword' => $keyword_format,
126
  'format' => 'json',
127
  'title' => urlencode( $thisposttitle )
128
  ), $yourlsurl );
@@ -132,11 +138,13 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
132
  'password' => $yourlsapi,
133
  'url' => $encoded,
134
  'action' => 'shorturl',
135
- 'keyword' => $keyword_format,
136
  'format' => 'json',
137
  'title' => urlencode( $thisposttitle )
138
  ), $yourlsurl );
139
  }
 
 
 
140
  $json = wpt_remote_json( $api_url, false );
141
  wpt_mail( "YOURLS JSON Response", print_r( $json, 1 ) ); // DEBUG YOURLS response
142
  if ( is_object( $json ) ) {
@@ -167,18 +175,19 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
167
  $shrink = false;
168
  $error = __( 'Su.pr query returned invalid data.', 'wp-to-twitter' );
169
  }
170
- if ( ! is_valid_url( $shrink ) ) {
171
  $shrink = false;
172
  }
173
  break;
174
  case 8:
175
  // Goo.gl
176
- $target = "https://www.googleapis.com/urlshortener/v1/url?key=AIzaSyBSnqQOg3vX1gwR7y2l-40yEG9SZiaYPUQ";
177
- $body = "{'longUrl':'$url'}";
 
178
  $json = wpt_fetch_url( $target, 'POST', $body, 'Content-Type: application/json' );
179
  $decoded = json_decode( $json );
180
- $shrink = $decoded->id;
181
- if ( ! is_valid_url( $shrink ) ) {
182
  $shrink = false;
183
  }
184
  break;
@@ -222,7 +231,7 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
222
  $error = $decoded;
223
  $shrink = false;
224
  }
225
- if ( ! is_valid_url( $shrink ) ) {
226
  $shrink = false;
227
  }
228
  break;
@@ -240,19 +249,19 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
240
  update_option( 'wp_url_failure', '0' );
241
  }
242
  }
243
- $store_urls = apply_filters( 'wpt_store_url', true );
244
  if ( $store_urls ) {
245
  wpt_store_url( $post_ID, $shrink );
246
  }
247
 
248
  return $shrink;
249
  }
250
-
251
  function wpt_store_url( $post_ID, $url ) {
252
  $store_urls = apply_filters( 'wpt_store_urls', true, $post_ID, $url );
253
  if ( function_exists( 'wpt_shorten_url' ) && $store_urls ) {
254
  $shortener = get_option( 'jd_shortener' );
255
- if ( get_post_meta( $post_ID, '_wpt_short_url', true ) != $url ) {
256
  update_post_meta( $post_ID, '_wpt_short_url', $url );
257
  }
258
  switch ( $shortener ) {
@@ -280,17 +289,11 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
280
  return wpt_expand_url( $short_url );
281
  }
282
 
 
 
 
283
  function wpt_expand_url( $short_url ) {
284
- $short_url = urlencode( $short_url );
285
- $decoded = wpt_remote_json( "http://api.longurl.org/v2/expand?format=json&url=" . $short_url );
286
- if ( isset( $decoded['long-url'] ) ) {
287
- $url = $decoded['long-url'];
288
- } else {
289
- $url = $short_url;
290
- }
291
-
292
- return $url;
293
- //return $short_url;
294
  }
295
 
296
  function jd_expand_yourl( $short_url, $remote ) {
@@ -407,22 +410,26 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
407
  <?php echo $form_end; ?>
408
  <?php } else if ( $shortener == 5 || $shortener == 6 ) { ?>
409
  <?php echo $form_start; ?>
 
410
  <p>
411
  <label
412
- for="yourlspath"><?php _e( 'Path to your YOURLS config file (Local installations)', 'wp-to-twitter' ); ?></label><br/><input
413
  type="text" id="yourlspath" name="yourlspath" size="60"
414
  value="<?php esc_attr_e( get_option( 'yourlspath' ) ); ?>"/><br/>
415
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>/home/username/www/www/yourls/user/config.php</code>
416
  </small>
417
  </p>
 
 
418
  <p>
419
  <label
420
- for="yourlsurl"><?php _e( 'URI to the YOURLS API (Remote installations)', 'wp-to-twitter' ); ?></label><br/><input
421
  type="text" id="yourlsurl" name="yourlsurl" size="60"
422
  value="<?php esc_attr_e( get_option( 'yourlsurl' ) ); ?>"/><br/>
423
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>http://domain.com/yourls-api.php</code>
424
  </small>
425
  </p>
 
426
  <p>
427
  <label
428
  for="yourlstoken"><?php _e( "YOURLS signature token:", 'wp-to-twitter' ); ?></label>
@@ -450,9 +457,18 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
450
  </p>
451
 
452
  <div>
453
- <input type="hidden" name="submit-type" value="yourlsapi"/>
454
  </div>
455
  <?php echo $form_end; ?>
 
 
 
 
 
 
 
 
 
456
  <?php } else if ( $shortener == 10 ) { ?>
457
  <?php echo $form_start; ?>
458
  <p>
@@ -517,20 +533,22 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
517
  }
518
  update_option( 'yourlsurl', trim( $post['yourlsurl'] ) );
519
  // yourls path is deprecated.
520
- if ( $post['yourlspath'] != '' ) {
521
  update_option( 'yourlspath', trim( $post['yourlspath'] ) );
522
  if ( file_exists( $post['yourlspath'] ) ) {
523
- $message .= __( "YOURLS local server path added. ", 'wp-to-twitter' );
524
  } else {
525
- $message .= __( "The path to your YOURLS installation is not correct. ", 'wp-to-twitter' );
526
  }
527
  }
528
  if ( $post['jd_keyword_format'] != '' ) {
529
  update_option( 'jd_keyword_format', $post['jd_keyword_format'] );
530
  if ( $post['jd_keyword_format'] == 1 ) {
531
- $message .= __( "YOURLS will use Post ID for short URL slug.", 'wp-to-twitter' );
 
 
532
  } else {
533
- $message .= __( "YOURLS will use your custom keyword for short URL slug.", 'wp-to-twitter' );
534
  }
535
  }
536
  if ( isset( $post['clear'] ) ) {
@@ -578,6 +596,14 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
578
  $message = __( "Bit.ly Login not added - <a href='http://bit.ly/account/'>get one here</a>! ", 'wp-to-twitter' );
579
  }
580
  }
 
 
 
 
 
 
 
 
581
 
582
  if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'joturlapi' ) {
583
  if ( $post['joturlapi'] != '' && isset( $post['submit'] ) ) {
@@ -597,7 +623,7 @@ if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in
597
  $message = __( "jotURL public API Key deleted. You cannot use the jotURL API without providing your public API Key. ", 'wp-to-twitter' );
598
  } else {
599
  $message = __( "jotURL public API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! ", 'wp-to-twitter' );
600
- }
601
  if ( $post['joturl_longurl_params'] != '' && isset( $post['submit'] ) ) {
602
  $v = trim( $post['joturl_longurl_params'] );
603
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
7
  if ( ! function_exists( 'wpt_shorten_url' ) ) { // prep work for future plug-in replacement.
8
  add_filter( 'wptt_shorten_link', 'wpt_shorten_url', 10, 4 );
9
 
10
+ function wpt_shorten_url( $url, $thisposttitle, $post_ID, $testmode = false, $store_urls = true ) {
11
  wpt_mail( "Initial Link Data: #$post_ID", "$url, $thisposttitle, $post_ID, $testmode" ); // DEBUG
12
  // filter link before sending to shortener or adding analytics
13
  $shortener = get_option( 'jd_shortener' );
38
  }
39
  $medium = urlencode( trim( apply_filters( 'wpt_utm_medium', 'twitter' ) ) );
40
  $source = urlencode( trim( apply_filters( 'wpt_utm_source', 'twitter' ) ) );
41
+ $url = add_query_arg( array(
42
+ 'utm_campaign' => $campaign,
43
+ 'utm_medium' => $medium,
44
+ 'utm_source' => $source ), $url
45
+ );
46
  }
47
  $url = urldecode( trim( $url ) ); // prevent double-encoding
48
  $encoded = urlencode( $url );
60
  $error = false;
61
  if ( !$shrink ) {
62
  switch ( $shortener ) {
63
+ case 3: // no shortener
64
+ $shrink = $url;
 
 
 
 
 
 
65
  break;
66
  case 2: // updated to v3 3/31/2010
67
  $bitlyapi = trim( get_option( 'bitlyapi' ) );
69
  $decoded = wpt_remote_json( "https://api-ssl.bitly.com/v3/shorten?longUrl=" . $encoded . "&login=" . $bitlylogin . "&apiKey=" . $bitlyapi . "&format=json" );
70
  if ( $decoded && isset( $decoded['status_code'] ) ) {
71
  if ( $decoded['status_code'] != 200 ) {
72
+ $shrink = $url;
73
  $error = $decoded['status_txt'];
74
  } else {
75
  $shrink = $decoded['data']['url'];
77
  } else {
78
  $shrink = false;
79
  }
80
+ if ( ! wpt_is_valid_url( $shrink ) ) {
81
  $shrink = false;
82
  }
83
  break;
84
+ case 4:
85
+ if ( function_exists( 'wp_get_shortlink' ) ) {
86
+ // wp_get_shortlink doesn't natively support custom post types; but don't return an error in that case.
87
+ $shrink = ( $post_ID != false ) ? wp_get_shortlink( $post_ID, 'post' ) : $url;
88
+ }
89
+ if ( ! $shrink ) {
90
+ $shrink = $url;
91
+ }
92
+ break;
93
  case 5:
94
  // local YOURLS installation
95
  global $yourls_reserved_URL;
129
  'signature' => $token,
130
  'url' => $encoded,
131
  'action' => 'shorturl',
 
132
  'format' => 'json',
133
  'title' => urlencode( $thisposttitle )
134
  ), $yourlsurl );
138
  'password' => $yourlsapi,
139
  'url' => $encoded,
140
  'action' => 'shorturl',
 
141
  'format' => 'json',
142
  'title' => urlencode( $thisposttitle )
143
  ), $yourlsurl );
144
  }
145
+ if ( $keyword_format ) {
146
+ $api_url['keyword'] = $keyword_format;
147
+ }
148
  $json = wpt_remote_json( $api_url, false );
149
  wpt_mail( "YOURLS JSON Response", print_r( $json, 1 ) ); // DEBUG YOURLS response
150
  if ( is_object( $json ) ) {
175
  $shrink = false;
176
  $error = __( 'Su.pr query returned invalid data.', 'wp-to-twitter' );
177
  }
178
+ if ( ! wpt_is_valid_url( $shrink ) ) {
179
  $shrink = false;
180
  }
181
  break;
182
  case 8:
183
  // Goo.gl
184
+ $googl_api_key = ( get_option( 'googl_api_key' ) == '' ) ? 'AIzaSyBSnqQOg3vX1gwR7y2l-40yEG9SZiaYPUQ' : get_option( 'googl_api_key' );
185
+ $target = "https://www.googleapis.com/urlshortener/v1/url?key=$googl_api_key";
186
+ $body = "{'longUrl':'$url'}";
187
  $json = wpt_fetch_url( $target, 'POST', $body, 'Content-Type: application/json' );
188
  $decoded = json_decode( $json );
189
+ $shrink = $decoded->id;
190
+ if ( ! wpt_is_valid_url( $shrink ) ) {
191
  $shrink = false;
192
  }
193
  break;
231
  $error = $decoded;
232
  $shrink = false;
233
  }
234
+ if ( ! wpt_is_valid_url( $shrink ) ) {
235
  $shrink = false;
236
  }
237
  break;
249
  update_option( 'wp_url_failure', '0' );
250
  }
251
  }
252
+ $store_urls = apply_filters( 'wpt_store_url', $store_urls );
253
  if ( $store_urls ) {
254
  wpt_store_url( $post_ID, $shrink );
255
  }
256
 
257
  return $shrink;
258
  }
259
+
260
  function wpt_store_url( $post_ID, $url ) {
261
  $store_urls = apply_filters( 'wpt_store_urls', true, $post_ID, $url );
262
  if ( function_exists( 'wpt_shorten_url' ) && $store_urls ) {
263
  $shortener = get_option( 'jd_shortener' );
264
+ if ( get_post_meta( $post_ID, '_wpt_short_url', true ) != $url && wpt_is_valid_url( $url ) ) {
265
  update_post_meta( $post_ID, '_wpt_short_url', $url );
266
  }
267
  switch ( $shortener ) {
289
  return wpt_expand_url( $short_url );
290
  }
291
 
292
+ /**
293
+ * LongUrl.org was taken off line; this no longer works.
294
+ */
295
  function wpt_expand_url( $short_url ) {
296
+ return $short_url;
 
 
 
 
 
 
 
 
 
297
  }
298
 
299
  function jd_expand_yourl( $short_url, $remote ) {
410
  <?php echo $form_end; ?>
411
  <?php } else if ( $shortener == 5 || $shortener == 6 ) { ?>
412
  <?php echo $form_start; ?>
413
+ <?php if ( $shortener == 5 ) { ?>
414
  <p>
415
  <label
416
+ for="yourlspath"><?php _e( 'Path to your YOURLS config file', 'wp-to-twitter' ); ?></label><br/><input
417
  type="text" id="yourlspath" name="yourlspath" size="60"
418
  value="<?php esc_attr_e( get_option( 'yourlspath' ) ); ?>"/><br/>
419
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>/home/username/www/www/yourls/user/config.php</code>
420
  </small>
421
  </p>
422
+ <?php } ?>
423
+ <?php if ( $shortener == 6 ) { ?>
424
  <p>
425
  <label
426
+ for="yourlsurl"><?php _e( 'URI to the YOURLS API', 'wp-to-twitter' ); ?></label><br/><input
427
  type="text" id="yourlsurl" name="yourlsurl" size="60"
428
  value="<?php esc_attr_e( get_option( 'yourlsurl' ) ); ?>"/><br/>
429
  <small><?php _e( 'Example:', 'wp-to-twitter' ); ?> <code>http://domain.com/yourls-api.php</code>
430
  </small>
431
  </p>
432
+ <?php } ?>
433
  <p>
434
  <label
435
  for="yourlstoken"><?php _e( "YOURLS signature token:", 'wp-to-twitter' ); ?></label>
457
  </p>
458
 
459
  <div>
460
+ <input type="hidden" name="submit-type" value="yourlsapi" />
461
  </div>
462
  <?php echo $form_end; ?>
463
+ <?php } else if ( $shortener == 8 ) { ?>
464
+ <?php echo $form_start; ?>
465
+ <p>
466
+ <label for="googl_api_key"><?php _e( "Goo.gl API Key:", 'wp-to-twitter' ); ?></label>
467
+ <input type="text" name="googl_api_key" id="googl_api_key" value="<?php esc_attr_e( get_option( 'googl_api_key' ) ) ?>"/>
468
+ </p>
469
+
470
+ <div><input type="hidden" name="submit-type" value="googlapi" /></div>
471
+ <?php echo $form_end; ?>
472
  <?php } else if ( $shortener == 10 ) { ?>
473
  <?php echo $form_start; ?>
474
  <p>
533
  }
534
  update_option( 'yourlsurl', trim( $post['yourlsurl'] ) );
535
  // yourls path is deprecated.
536
+ if ( isset( $post['yourlspath'] ) && $post['yourlspath'] != '' ) {
537
  update_option( 'yourlspath', trim( $post['yourlspath'] ) );
538
  if ( file_exists( $post['yourlspath'] ) ) {
539
+ $message .= ' ' . __( "YOURLS local server path added. ", 'wp-to-twitter' );
540
  } else {
541
+ $message .= ' ' . __( "The path to your YOURLS installation is not correct. ", 'wp-to-twitter' );
542
  }
543
  }
544
  if ( $post['jd_keyword_format'] != '' ) {
545
  update_option( 'jd_keyword_format', $post['jd_keyword_format'] );
546
  if ( $post['jd_keyword_format'] == 1 ) {
547
+ $message .= ' ' . __( "YOURLS will use Post ID for short URL slug.", 'wp-to-twitter' );
548
+ } else if ( $post['jd_keyword_format'] == 0 ) {
549
+ $message .= ' ' . __( 'YOURLS will use default URL structures.', 'wp-to-twitter' );
550
  } else {
551
+ $message .= ' ' . __( "YOURLS will use your custom keyword for short URL slug.", 'wp-to-twitter' );
552
  }
553
  }
554
  if ( isset( $post['clear'] ) ) {
596
  $message = __( "Bit.ly Login not added - <a href='http://bit.ly/account/'>get one here</a>! ", 'wp-to-twitter' );
597
  }
598
  }
599
+ if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'googlapi' ) {
600
+ if ( $post['googl_api_key'] != '' && isset( $post['submit'] ) ) {
601
+ update_option( 'googl_api_key', trim( $post['googl_api_key'] ) );
602
+ $message .= __( "Goo.gl API Key Updated. ", 'wp-to-twitter' );
603
+ } else {
604
+ $message = __( "Goo.gl API Key not added - <a href='https://developers.google.com/url-shortener/v1/getting_started'>get one here</a>! ", 'wp-to-twitter' );
605
+ }
606
+ }
607
 
608
  if ( isset( $post['submit-type'] ) && $post['submit-type'] == 'joturlapi' ) {
609
  if ( $post['joturlapi'] != '' && isset( $post['submit'] ) ) {
623
  $message = __( "jotURL public API Key deleted. You cannot use the jotURL API without providing your public API Key. ", 'wp-to-twitter' );
624
  } else {
625
  $message = __( "jotURL public API Key not added - <a href='https://www.joturl.com/reserved/api.html'>get one here</a>! ", 'wp-to-twitter' );
626
+ }
627
  if ( $post['joturl_longurl_params'] != '' && isset( $post['submit'] ) ) {
628
  $v = trim( $post['joturl_longurl_params'] );
629
  if ( substr( $v, 0, 1 ) == '&' || substr( $v, 0, 1 ) == '?' ) {
wp-to-twitter.php CHANGED
@@ -3,13 +3,13 @@
3
  Plugin Name: WP to Twitter
4
  Plugin URI: http://www.joedolson.com/wp-to-twitter/
5
  Description: Posts a Tweet when you update your WordPress blog or post a link, using your URL shortening service. Rich in features for customizing and promoting your Tweets.
6
- Version: 3.2.0
7
  Author: Joseph Dolson
8
  Text Domain: wp-to-twitter
9
  Domain Path: /lang
10
  Author URI: http://www.joedolson.com/
11
  */
12
- /* Copyright 2008-2016 Joseph C Dolson (email : plugins@joedolson.com)
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@ require_once( plugin_dir_path( __FILE__ ) . '/wpt-widget.php' );
44
  require_once( plugin_dir_path( __FILE__ ) . '/wpt-rate-limiting.php' );
45
 
46
  global $wpt_version;
47
- $wpt_version = "3.2.0";
48
 
49
  // Create a helper function for easy SDK access.
50
  function wtt_fs() {
@@ -73,8 +73,6 @@ function wtt_fs() {
73
  return $wtt_fs;
74
  }
75
 
76
- wtt_fs();
77
-
78
  function wtt_fs_custom_connect_message(
79
  $message,
80
  $user_first_name,
@@ -85,7 +83,7 @@ function wtt_fs_custom_connect_message(
85
  ) {
86
  return sprintf(
87
  __fs( 'hey-x' ) . '<br>' .
88
- __( 'Do you want to help me improve %2$s? Let me gather some data! To do that, I need to connect your user, %3$s at %4$s, to %5$s. </p><p><em>This is purely optional, but I\'d certainly appreciate it!</em>', 'wp-to-twitter' ),
89
  $user_first_name,
90
  '<b>' . $plugin_title . '</b>',
91
  '<b>' . $user_login . '</b>',
@@ -94,10 +92,11 @@ function wtt_fs_custom_connect_message(
94
  );
95
  }
96
 
97
- wtt_fs()->add_action( 'after_uninstall', 'wtt_fs_uninstall_cleanup' );
 
98
  wtt_fs()->add_filter( 'connect_message', 'wtt_fs_custom_connect_message', 10, 6 );
99
  wtt_fs()->add_action( 'after_uninstall', 'wtt_fs_uninstall_cleanup' );
100
- // Init Freemius.
101
 
102
  add_action( 'plugins_loaded', 'wpt_load_textdomain' );
103
  function wpt_load_textdomain() {
@@ -188,7 +187,6 @@ function wptotwitter_activate() {
188
  update_option( 'wpt_inline_edits', '0' );
189
  // Note that default options are set.
190
  update_option( 'wpt_twitter_setup', '1' );
191
- //YOURLS API
192
  update_option( 'jd_keyword_format', '0' );
193
  }
194
 
@@ -313,58 +311,6 @@ function wptotwitter_activate() {
313
  update_option( 'wp_to_twitter_version', $wpt_version );
314
  }
315
 
316
- /**
317
- * Migrates post meta to new format when post is called in editor.
318
- */
319
- add_action( 'load-post.php', 'wpt_migrate_url_meta' );
320
- function wpt_migrate_url_meta() {
321
- $post_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : false;
322
- if ( !$post_id ) {
323
- return;
324
- }
325
- $short = get_post_meta( $post_id, '_wpt_short_url', true );
326
- if ( $short != '' ) {
327
- return;
328
- }
329
- if ( $short == "" ) {
330
- $short = get_post_meta( $post_id, '_wp_jd_goo', true );
331
- delete_post_meta( $post_id, '_wp_jd_goo' );
332
- }
333
- if ( $short == "" ) {
334
- $short = get_post_meta( $post_id, '_wp_jd_supr', true );
335
- delete_post_meta( $post_id, '_wp_jd_supr' );
336
- }
337
- if ( $short == "" ) {
338
- $short = get_post_meta( $post_id, '_wp_jd_wp', true );
339
- delete_post_meta( $post_id, '_wp_jd_wp' );
340
- }
341
- if ( $short == "" ) {
342
- $short = get_post_meta( $post_id, '_wp_jd_ind', true );
343
- delete_post_meta( $post_id, '_wp_jd_ind' );
344
- }
345
- if ( $short == "" ) {
346
- $short = get_post_meta( $post_id, '_wp_jd_yourls', true );
347
- delete_post_meta( $post_id, '_wp_jd_yourls' );
348
- }
349
- if ( $short == "" ) {
350
- $short = get_post_meta( $post_id, '_wp_jd_url', true );
351
- delete_post_meta( $post_id, '_wp_jd_url' );
352
- }
353
- if ( $short == "" ) {
354
- $short = get_post_meta( $post_id, '_wp_jd_joturl', true );
355
- delete_post_meta( $post_id, '_wp_jd_joturl' );
356
- }
357
- if ( $short == "" ) {
358
- // don't delete target link
359
- $short = get_post_meta( $post_id, '_wp_jd_target', true );
360
- }
361
- if ( $short == "" ) {
362
- $short = get_post_meta( $post_id, '_wp_jd_clig', true );
363
- delete_post_meta( $post_id, '_wp_jd_clig' );
364
- }
365
- update_post_meta( $post_id, '_wpt_short_url', $short );
366
- }
367
-
368
  // Function checks for an alternate URL to be Tweeted. Contribution by Bill Berry.
369
  function wpt_link( $post_ID ) {
370
  $ex_link = false;
@@ -438,9 +384,9 @@ function wpt_check_recent_tweet( $id, $auth ) {
438
  *
439
  * @return boolean Success of query.
440
  */
441
- function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false ) {
442
  $recent = wpt_check_recent_tweet( $id, $auth );
443
-
444
  if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
445
  // check whether this post needs to be rate limited.
446
  $continue = wpt_test_rate_limit( $id, $auth );
@@ -461,6 +407,7 @@ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false
461
 
462
  return false;
463
  } // exit silently if not authorized
 
464
  $check = ( ! $auth ) ? get_option( 'jd_last_tweet' ) : get_user_meta( $auth, 'wpt_last_tweet', true ); // get user's last tweet
465
  // prevent duplicate Tweets
466
  if ( $check == $twit ) {
@@ -489,17 +436,17 @@ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false
489
  $attachment = false;
490
  }
491
  }
492
- $api = "https://api.twitter.com/1.1/statuses/update.json";
493
- $upload_api = 'https://upload.twitter.com/1.1/media/upload.json';
494
- $status = array(
495
  'status' => $twit,
496
  'source' => 'wp-to-twitter',
497
  'include_entities' => 'true'
498
  );
499
- // support for HTTP deprecated as of 1/14/2014 -- https://dev.twitter.com/discussions/24239
500
  if ( wtt_oauth_test( $auth ) && ( $connection = wtt_oauth_connection( $auth ) ) ) {
501
  if ( $media && $attachment && !$media_id ) {
502
- $media_id = $connection->media( $upload_api, array( 'auth'=>$auth, 'media'=>$attachment ) );
503
  wpt_mail( 'Media Uploaded', "$auth, $media_id, $attachment" );
504
  if ( $media_id ) {
505
  $status['media_ids'] = $media_id;
@@ -549,7 +496,7 @@ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false
549
  update_option( 'wpt_authentication_missing', "$auth" );
550
  break;
551
  case '403':
552
- $error = __( "403 Forbidden: The request is understood, but has been refused by Twitter. Possible reasons: too many Tweets, same Tweet submitted twice, Tweet longer than 140 characters.", 'wp-to-twitter' );
553
  break;
554
  case '404':
555
  $error = __( "404 Not Found: The URI requested is invalid or the resource requested does not exist.", 'wp-to-twitter' );
@@ -579,14 +526,22 @@ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false
579
  $error = __( "<strong>Code $http_code</strong>: Twitter did not return a recognized response code.", 'wp-to-twitter' );
580
  break;
581
  }
 
 
 
 
582
  $error .= ( $supplement != '' ) ? " $supplement" : '';
 
583
  // debugging
584
  wpt_mail( "Twitter Response: $http_code, #$id", "$http_code, $error" ); // DEBUG
585
  // end debugging
586
- if ( ! $auth ) {
587
- update_option( 'jd_last_tweet', $twit );
588
- } else {
589
- update_user_meta( $auth, 'wpt_last_tweet', $twit );
 
 
 
590
  }
591
  wpt_saves_error( $id, $auth, $twit, $error, $http_code, time() );
592
  if ( $http_code == '200' ) {
@@ -611,6 +566,7 @@ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false
611
  if ( ! $return ) {
612
  wpt_set_log( 'wpt_status_message', $id, $error );
613
  } else {
 
614
  wpt_set_log( 'wpt_status_message', $id, $notice . __( 'Tweet sent successfully.', 'wp-to-twitter' ) );
615
  }
616
 
@@ -725,7 +681,7 @@ function wpt_post_info( $post_ID ) {
725
  $cat_descs[] = $cat->description;
726
  }
727
  $cat_names = implode( ' ', apply_filters( 'wpt_twitter_category_names', $cats ) );
728
- $cat_descs = implode( ' ', apply_filters( 'wpt_twitter_category_descs', $cat_descs ) );
729
  } else {
730
  $category = '';
731
  $cat_desc = '';
@@ -743,11 +699,11 @@ function wpt_post_info( $post_ID ) {
743
  if ( $thisposttitle == "" && isset( $_POST['title'] ) ) {
744
  $thisposttitle = $_POST['title'];
745
  }
746
- $thisposttitle = strip_tags( apply_filters( 'the_title', stripcslashes( $thisposttitle ) ) );
747
  // These are common sequences that may not be fixed by html_entity_decode due to double encoding
748
- $search = array( '&apos;', '&#039;', '&quot;', '&#034;', '&amp;', '&#038;' );
749
- $replace = array( "'", "'", '"', '"', '&', '&' );
750
- $thisposttitle = str_replace( $search, $replace, $thisposttitle );
751
  $values['postTitle'] = html_entity_decode( $thisposttitle, ENT_QUOTES, $encoding );
752
  $values['postLink'] = wpt_link( $post_ID );
753
  $values['blogTitle'] = get_bloginfo( 'name' );
@@ -778,6 +734,7 @@ function wpt_short_url( $post_id ) {
778
  $post_id = $post_ID;
779
  }
780
  $short = get_post_meta( $post_id, '_wpt_short_url', true );
 
781
  return $short;
782
  }
783
 
@@ -835,14 +792,14 @@ function wpt_category_limit( $post_type, $post_info, $post_ID ) {
835
  * @return integer $post_ID
836
  */
837
  function wpt_tweet( $post_ID, $type = 'instant' ) {
838
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_ID ) ) {
839
  return $post_ID;
840
  }
841
 
842
  wpt_check_version();
843
- $jd_tweet_this = get_post_meta( $post_ID, '_jd_tweet_this', true );
844
- $newpost = $oldpost = $is_inline_edit = false;
845
- $sentence = $template = $nptext = '';
846
  if ( get_option( 'wpt_inline_edits' ) != 1 ) {
847
  if ( isset( $_POST['_inline_edit'] ) || isset( $_REQUEST['bulk_edit'] ) ) {
848
  return false;
@@ -853,11 +810,11 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
853
  }
854
  }
855
  if ( get_option( 'jd_tweet_default' ) == 0 ) {
856
- $default = ( $jd_tweet_this != 'no' ) ? true : false;
857
  } else {
858
- $default = ( $jd_tweet_this == 'yes' ) ? true : false;
859
  }
860
- wpt_mail( "1: JD Tweet This Value: #$post_ID", "Tweet this: $jd_tweet_this /" . get_option( 'jd_tweet_default' ) . " / $type" ); // DEBUG
861
  if ( $default ) { // default switch: depend on default settings.
862
  $post_info = wpt_post_info( $post_ID );
863
  $media = wpt_post_with_media( $post_ID, $post_info );
@@ -915,8 +872,8 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
915
  if ( $new == 0 || $is_inline_edit == true ) {
916
  // if this is an old post and editing updates are enabled
917
  if ( get_option( 'jd_tweet_default_edit' ) == 1 ) {
918
- $jd_tweet_this = apply_filters( 'wpt_tweet_this_edit', $jd_tweet_this, $_POST );
919
- if ( $jd_tweet_this != 'yes' ) {
920
  return false;
921
  }
922
  }
@@ -957,7 +914,7 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
957
  if ( $post_info['wpt_delay_tweet'] == 0 || $post_info['wpt_delay_tweet'] == '' || $post_info['wpt_no_delay'] == 'on' ) {
958
  foreach ( $wpt_selected_users as $acct ) {
959
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
960
- jd_doTwitterAPIPost( $sentence2, $acct, $post_ID, $media );
961
  }
962
  }
963
  } else {
@@ -1023,11 +980,14 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
1023
  'rt' => $i,
1024
  'post_id' => $post_ID,
1025
  'timestamp' => time() + $time + $offset + $delay,
 
 
 
1026
  'current_time' => time(),
1027
  'timezone' => get_option( 'gmt_offset' ),
1028
  'timestamp_string' => date( 'Y-m-d H:i:s', time() + $time + $offset + $delay ),
1029
  'current_time_string' => date( 'Y-m-d H:i:s', time() ),
1030
- ), 1 ) ); // DEBUG
1031
  }
1032
  $tweet_limit = apply_filters( 'wpt_tweet_repeat_limit', 4, $post_ID );
1033
  if ( $i == $tweet_limit ) {
@@ -1040,7 +1000,7 @@ function wpt_tweet( $post_ID, $type = 'instant' ) {
1040
  }
1041
  }
1042
  } else {
1043
- jd_doTwitterAPIPost( $sentence, false, $post_ID, $media );
1044
  }
1045
  // END WPT PRO //
1046
  }
@@ -1091,7 +1051,7 @@ function wpt_twit_link( $link_ID ) {
1091
  }
1092
 
1093
  if ( $sentence != '' ) {
1094
- jd_doTwitterAPIPost( $sentence, false, $link_ID );
1095
  }
1096
 
1097
  return $link_ID;
@@ -1116,8 +1076,9 @@ function wpt_generate_hash_tags( $post_ID ) {
1116
  if ( $max_tags == 0 || $max_tags == "" ) {
1117
  $max_tags = 100;
1118
  }
1119
- $tags = get_the_tags( $post_ID );
1120
- if ( $tags > 0 ) {
 
1121
  $i = 1;
1122
  foreach ( $tags as $value ) {
1123
  if ( function_exists( 'wpt_pro_exists' ) ) {
@@ -1135,7 +1096,7 @@ function wpt_generate_hash_tags( $post_ID ) {
1135
  $replace = ( $replace == "[ ]" || $replace == "" ) ? "" : $replace;
1136
  $tag = str_ireplace( " ", $replace, trim( $tag ) );
1137
  $tag = preg_replace( '/[\/]/', $replace, $tag ); // remove forward slashes.
1138
- $tag = ( $strip == '1' ) ? preg_replace( $search, $replace, $tag ) : $tag;
1139
 
1140
  switch ( $term_meta ) {
1141
  case 1 : $newtag = "#$tag"; break;
@@ -1184,22 +1145,22 @@ function wpt_add_twitter_inner_box( $post ) {
1184
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1185
  $is_pro = ( function_exists( 'wpt_pro_exists' ) ) ? 'pro' : 'free'; ?>
1186
  <div class='wp-to-twitter <?php echo $is_pro; ?>'>
1187
- <?php
1188
  $tweet_status = '';
1189
  $options = get_option( 'wpt_post_types' );
1190
  $type = $post->post_type;
1191
  $status = $post->post_status;
1192
  $post_id = $post->ID;
1193
 
1194
- $jd_tweet_this = get_post_meta( $post_id, '_jd_tweet_this', true );
1195
- if ( ! $jd_tweet_this ) {
1196
- $jd_tweet_this = ( get_option( 'jd_tweet_default' ) == '1' ) ? 'no' : 'yes';
1197
  }
1198
  if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && get_option( 'jd_tweet_default_edit' ) == '1' && $status == 'publish' ) {
1199
- $jd_tweet_this = 'no';
1200
  }
1201
  if ( isset( $_REQUEST['message'] ) && $_REQUEST['message'] != 10 ) { // don't display when draft is updated or if no message
1202
- if ( ! ( ( $_REQUEST['message'] == 1 ) && ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) ) && $jd_tweet_this != 'no' ) {
1203
  $log = wpt_log( 'wpt_status_message', $post_id );
1204
  $class = ( $log != __( 'Tweet sent successfully.', 'wp-to-twitter' ) ) ? 'error' : 'updated';
1205
  if ( $log != '' ) {
@@ -1211,7 +1172,7 @@ function wpt_add_twitter_inner_box( $post ) {
1211
  $failed_tweets = get_post_meta( $post_id, '_wpt_failed' );
1212
  $tweet = esc_attr( stripcslashes( get_post_meta( $post_id, '_jd_twitter', true ) ) );
1213
  $tweet = apply_filters( 'wpt_user_text', $tweet, $status );
1214
- $jd_template = ( $status == 'publish' ) ? $options[ $type ]['post-edited-text'] : $options[ $type ]['post-published-text'];
1215
 
1216
  if ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) {
1217
  $tweet_status = sprintf( __( '%s will not be Tweeted on update.', 'wp-to-twitter' ), ucfirst( $type ) );
@@ -1220,29 +1181,17 @@ function wpt_add_twitter_inner_box( $post ) {
1220
  if ( $status == 'publish' && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1221
  ?>
1222
  <div class='tweet-buttons'>
1223
- <button class='tweet button-primary'
1224
- data-action='tweet'><?php _e( 'Tweet Now', 'wp-to-twitter' ); ?></button>
1225
  <?php if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) { ?>
1226
- <button class='tweet schedule button-secondary' data-action='schedule'
1227
- disabled><?php _e( 'Schedule', 'wp-to-twitter' ); ?></button>
1228
- <button class='time button-secondary'>
1229
- <span class="dashicons dashicons-clock" aria-hidden="true"><span
1230
- class="screen-reader-text"><?php _e( 'Set Date/Time', 'wp-to-twitter' ); ?></span></span>
1231
  </button>
1232
  <div id="jts">
1233
  <label for='wpt_date'><?php _e( 'Date', 'wp-to-twitter' ); ?></label>
1234
- <input type='date'
1235
- value=''
1236
- class='date'
1237
- name='wpt_datetime'
1238
- id='wpt_date'
1239
- data-value='<?php echo date( 'Y-m-d', current_time( 'timestamp' ) ); ?>' /><br/>
1240
  <label for='wpt_time'><?php _e( 'Time', 'wp-to-twitter' ); ?></label>
1241
- <input type='text'
1242
- value='<?php echo date_i18n( 'h:s a', current_time( 'timestamp' ) + 3600 ); ?>'
1243
- class='time'
1244
- name='wpt_datetime'
1245
- id='wpt_time'/>
1246
  </div>
1247
  <?php } ?>
1248
  <div class='wpt_log' aria-live='assertive'></div>
@@ -1252,22 +1201,23 @@ function wpt_add_twitter_inner_box( $post ) {
1252
  if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1253
  ?>
1254
  <p class='jtw'>
1255
- <label
1256
- for="jtw"><?php _e( "Custom Twitter Post", 'wp-to-twitter', 'wp-to-twitter' ) ?></label><br/><textarea class="wpt_tweet_box" name="_jd_twitter" id="jtw" rows="2"
1257
- cols="60"><?php echo esc_attr( $tweet ); ?></textarea>
1258
  </p>
1259
  <?php
1260
- $jd_expanded = $jd_template;
1261
  if ( get_option( 'jd_twit_prepend' ) != "" ) {
1262
- $jd_expanded = "<span title='" . __( 'Your prepended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_prepend' ) ) . "</span> " . $jd_expanded;
1263
  }
1264
  if ( get_option( 'jd_twit_append' ) != "" ) {
1265
- $jd_expanded = $jd_expanded . " <span title='" . __( 'Your appended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_append' ) ) . "</span>";
1266
  }
1267
  ?>
1268
  <p class='template'>
1269
  <?php _e( 'Template:', 'wp-to-twitter' ); ?><br />
1270
- <code><?php echo stripcslashes( $jd_expanded ); ?></code>
 
1271
  </p>
1272
  <?php
1273
  echo apply_filters( 'wpt_custom_retweet_fields', '', $post_id );
@@ -1310,9 +1260,9 @@ function wpt_add_twitter_inner_box( $post ) {
1310
  } else {
1311
  echo "<p>";
1312
  if ( function_exists( 'wpt_pro_exists' ) ) {
1313
- printf( __( 'WP Tweets PRO allows you to select Twitter accounts. <a href="%s">Log in and download now!</a>', 'wp-to-twitter' ), 'http://www.joedolson.com/account/' );
1314
  } else {
1315
- printf( __( 'Upgrade to WP Tweets PRO to select Twitter accounts! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.joedolson.com/wp-tweets-pro/' );
1316
  }
1317
  echo "</p>";
1318
  }
@@ -1326,7 +1276,7 @@ function wpt_add_twitter_inner_box( $post ) {
1326
  do_action( 'wpt_custom_tab', $post_id, 'visible' );
1327
  } else {
1328
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1329
- echo "<p>" .sprintf( __( 'Upgrade to WP Tweets PRO to configure options! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.joedolson.com/wp-tweets-pro/' ) . "</p>";
1330
  }
1331
  }
1332
  ?>
@@ -1360,18 +1310,17 @@ function wpt_add_twitter_inner_box( $post ) {
1360
  <?php
1361
  if ( current_user_can( 'wpt_twitter_switch' ) || current_user_can( 'manage_options' ) ) {
1362
  // "no" means 'Don't Tweet' (is checked)
1363
- $nochecked = ( $jd_tweet_this == 'no' ) ? ' checked="checked"' : '';
1364
- $yeschecked = ( $jd_tweet_this == 'yes' ) ? ' checked="checked"' : '';
1365
  ?>
1366
  <p class='toggle-btn-group'>
1367
  <input type="radio" name="_jd_tweet_this" value="no" id="jtn"<?php echo $nochecked; ?> /><label for="jtn"><?php _e( "Don't Tweet post", 'wp-to-twitter' ); ?></label>
1368
- <input type="radio" name="_jd_tweet_this" value="yes" id="jty"<?php echo $yeschecked; ?> />
1369
- <label for="jty"><?php _e( "Tweet post", 'wp-to-twitter' ); ?></label>
1370
  </p>
1371
  <?php
1372
  } else {
1373
  ?>
1374
- <input type='hidden' name='_jd_tweet_this' value='<?php echo $jd_tweet_this; ?>'/>
1375
  <?php
1376
  }
1377
  wpt_show_tweets( $previous_tweets, $failed_tweets );
@@ -1380,7 +1329,7 @@ function wpt_add_twitter_inner_box( $post ) {
1380
  <?php if ( ! function_exists( 'wpt_pro_exists' ) ) {
1381
  /* These aren't actually usages that require esc_url. But using it will give people the illusion that it does something. */
1382
  ?>
1383
- <strong><a href="https://www.joedolson.com/wp-tweets-pro/"><?php _e( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) ?></a></strong> &raquo;
1384
  <?php } else { ?>
1385
  <a href="<?php echo esc_url( add_query_arg( 'tab', 'support', admin_url( 'admin.php?page=wp-tweets-pro' ) ) ); ?>#get-support"><?php _e( 'Get Support', 'wp-to-twitter', 'wp-to-twitter' ); ?></a> &raquo;
1386
  <?php } ?>
@@ -1393,8 +1342,7 @@ function wpt_add_twitter_inner_box( $post ) {
1393
  </div>
1394
  <?php
1395
  } else { // permissions: this user isn't allowed to Tweet;
1396
- _e( 'Your role does not have the ability to Post Tweets from this site.', 'wp-to-twitter' ); ?> <input
1397
- type='hidden' name='_jd_tweet_this' value='no'/> <?php
1398
  }
1399
  }
1400
 
@@ -1455,7 +1403,9 @@ function wpt_show_tweets( $previous_tweets, $failed_tweets ) {
1455
  if ( $has_history || $list ) {
1456
  echo "<p><input type='checkbox' name='wpt_clear_history' id='wptch' value='clear' /> <label for='wptch'>" . __( 'Delete Tweet History', 'wp-to-twitter' ) . "</label></p>";
1457
  }
1458
- echo "</div>";
 
 
1459
  }
1460
  }
1461
 
@@ -1495,9 +1445,9 @@ function wpt_ajax_tweet() {
1495
  echo "Invalid Security Check";
1496
  die;
1497
  }
1498
- $action = ( $_REQUEST['tweet_action'] == 'tweet' ) ? 'tweet' : 'schedule';
1499
- // This isn't used right now, because of time.
1500
- $authors = ( isset( $_REQUEST['tweet_auth'] ) && $_REQUEST['tweet_auth'] != null ) ? $_REQUEST['tweet_auth'] : false;
1501
  $current_user = wp_get_current_user();
1502
  if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) {
1503
  if ( wtt_oauth_test( $current_user->ID, 'verify' ) ) {
@@ -1510,6 +1460,9 @@ function wpt_ajax_tweet() {
1510
  $auth = false;
1511
  $user_ID = $current_user->ID;
1512
  }
 
 
 
1513
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1514
  $options = get_option( 'wpt_post_types' );
1515
  $post_ID = intval( $_REQUEST['tweet_post_id'] );
@@ -1523,22 +1476,31 @@ function wpt_ajax_tweet() {
1523
  $print_schedule = date_i18n( get_option( 'date_format' ) . ' @ ' . get_option( 'time_format' ), $schedule );
1524
  $offset = ( 60 * 60 * get_option( 'gmt_offset' ) );
1525
  $schedule = $schedule - $offset;
1526
- $media = wpt_post_with_media( $post_ID, $post_info );
1527
- switch ( $action ) {
1528
- case 'tweet' :
1529
- jd_doTwitterAPIPost( $sentence, $auth, $post_ID, $media );
1530
- break;
1531
- case 'schedule' :
1532
- wp_schedule_single_event( $schedule, 'wpt_schedule_tweet_action', array(
1533
- 'id' => $auth,
1534
- 'sentence' => $sentence,
1535
- 'rt' => 0,
1536
- 'post_id' => $post_ID
1537
- ) );
1538
- break;
 
 
 
 
 
 
 
 
 
 
 
1539
  }
1540
- $return = ( $action == 'tweet' ) ? wpt_log( 'wpt_status_message', $post_ID ) : "Tweet scheduled: '$sentence' for $print_schedule";
1541
- echo $return;
1542
  } else {
1543
  echo __( 'You are not authorized to perform this action', 'wp-to-twitter' );
1544
  }
@@ -1555,7 +1517,7 @@ function wpt_admin_script() {
1555
  wp_register_style( 'wpt-post-styles', plugins_url( 'css/post-styles.css', __FILE__ ) );
1556
  wp_enqueue_style( 'wpt-post-styles' );
1557
  if ( $current_screen->base == 'post' ) {
1558
- $allowed = 140 - mb_strlen( get_option( 'jd_twit_prepend' ) . get_option( 'jd_twit_append' ) );
1559
  } else {
1560
  $allowed = ( wpt_is_ssl( home_url() ) ) ? 137 : 138;
1561
  }
@@ -1575,7 +1537,7 @@ function wpt_admin_script() {
1575
  ) );
1576
  echo "
1577
  <style type='text/css'>
1578
- #wp2t h3 span { padding-left: 30px; background: url(" . plugins_url( 'wp-to-twitter/images/twitter-bird-light-bgs.png' ) . ") left 50% no-repeat; }
1579
  </style>";
1580
  }
1581
  }
@@ -1594,21 +1556,23 @@ function wpt_save_post( $id ) {
1594
  $yourls = $_POST['_yourls_keyword'];
1595
  $update = update_post_meta( $id, '_yourls_keyword', $yourls );
1596
  }
1597
- if ( isset( $_POST['_jd_twitter'] ) ) {
1598
- $jd_twitter = $_POST['_jd_twitter'];
1599
- $update = update_post_meta( $id, '_jd_twitter', $jd_twitter );
 
 
1600
  }
1601
  if ( isset( $_POST['_jd_wp_twitter'] ) && $_POST['_jd_wp_twitter'] != '' ) {
1602
- $jd_wp_twitter = $_POST['_jd_wp_twitter'];
1603
- $update = update_post_meta( $id, '_jd_wp_twitter', $jd_wp_twitter );
1604
  }
1605
  if ( isset( $_POST['_jd_tweet_this'] ) ) {
1606
- $jd_tweet_this = ( $_POST['_jd_tweet_this'] == 'no' ) ? 'no' : 'yes';
1607
- $update = update_post_meta( $id, '_jd_tweet_this', $jd_tweet_this );
1608
  } else {
1609
  if ( isset( $_POST['_wpnonce'] ) ) {
1610
- $jd_tweet_default = ( get_option( 'jd_tweet_default' ) == 1 ) ? 'no' : 'yes';
1611
- $update = update_post_meta( $id, '_jd_tweet_this', $jd_tweet_default );
1612
  }
1613
  }
1614
  if ( isset( $_POST['wpt_clear_history'] ) && $_POST['wpt_clear_history'] == 'clear' ) {
@@ -1626,32 +1590,6 @@ function wpt_save_post( $id ) {
1626
  }
1627
  }
1628
 
1629
- /**
1630
- * Parse custom shortcodes
1631
- *
1632
- * @param string $sentence Tweet template
1633
- * @param integer $post_ID Post ID.
1634
- *
1635
- * @return string $sentence with any custom shortcodes replaced with their appropriate content.
1636
- */
1637
- function wpt_custom_shortcodes( $sentence, $post_ID ) {
1638
- $pattern = '/([([\[\]?)([A-Za-z0-9-_])*(\]\]]?)+/';
1639
- $params = array( 0 => "[[", 1 => "]]" );
1640
- preg_match_all( $pattern, $sentence, $matches );
1641
- if ( $matches && is_array( $matches[0] ) ) {
1642
- foreach ( $matches[0] as $value ) {
1643
- $shortcode = "$value";
1644
- $field = str_replace( $params, "", $shortcode );
1645
- $custom = apply_filters( 'wpt_custom_shortcode', strip_tags( get_post_meta( $post_ID, $field, true ) ), $post_ID, $field );
1646
- $sentence = str_replace( $shortcode, $custom, $sentence );
1647
- }
1648
-
1649
- return $sentence;
1650
- } else {
1651
- return $sentence;
1652
- }
1653
- }
1654
-
1655
  /**
1656
  * Show user profile data on Edit User pages.
1657
  *
@@ -1767,7 +1705,7 @@ add_action( 'admin_head', 'wpt_admin_style' );
1767
  * Add stylesheets to WP to Twitter pages.
1768
  */
1769
  function wpt_admin_style() {
1770
- if ( isset( $_GET['page'] ) && ( $_GET['page'] == "wp-to-twitter" || $_GET['page'] == "wp-to-twitter/wp-to-twitter.php" || $_GET['page'] == "wp-tweets-pro" || $_GET['page'] == "wp-to-twitter-schedule" || $_GET['page'] == "wp-to-twitter-tweets" || $_GET['page'] == "wp-to-twitter-errors" ) ) {
1771
  wp_enqueue_style( 'wpt-styles', plugins_url( 'css/styles.css', __FILE__ ) );
1772
  }
1773
  }
@@ -1780,7 +1718,7 @@ function wpt_plugin_action( $links, $file ) {
1780
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
1781
  $links[] = "<a href='$admin_url'>" . __( 'WP to Twitter Settings', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1782
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1783
- $links[] = "<a href='https://www.joedolson.com/wp-tweets-pro/'>" . __( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1784
  }
1785
  }
1786
 
@@ -1840,6 +1778,7 @@ function wpt_in_post_type( $id ) {
1840
  }
1841
  }
1842
  }
 
1843
  return false;
1844
  }
1845
 
@@ -1849,7 +1788,7 @@ add_action( 'future_to_publish', 'wpt_future_to_publish', 16 );
1849
  */
1850
  function wpt_future_to_publish( $post ) {
1851
  $id = $post->ID;
1852
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $id ) || ! wpt_in_post_type( $id ) ) {
1853
  return;
1854
  }
1855
  wpt_twit_future( $id );
@@ -1865,8 +1804,13 @@ function wpt_twit( $id ) {
1865
  $post = get_post( $id );
1866
  if ( $post->post_status != 'publish' ) {
1867
  return;
1868
- } // is there any reason to accept any other status?
 
 
 
 
1869
  wpt_twit_instant( $id );
 
1870
  }
1871
 
1872
  add_action( 'xmlrpc_publish_post', 'wpt_twit_xmlrpc' );
@@ -1885,6 +1829,7 @@ function wpt_twit_future( $id ) {
1885
 
1886
  return;
1887
  }
 
1888
  wpt_tweet( $id, 'future' );
1889
  }
1890
 
@@ -1948,9 +1893,9 @@ add_action( 'admin_notices', 'wpt_promotion_notice', 10 );
1948
  */
1949
  function wpt_promotion_notice() {
1950
  if ( current_user_can( 'activate_plugins' ) && get_option( 'wpt_promotion_scheduled' ) == 2 && get_option( 'jd_donations' ) != 1 ) {
1951
- $upgrade = "https://www.joedolson.com/wp-tweets-pro/";
1952
- $dismiss = admin_url( 'options-general.php?page=wp-to-twitter/wp-to-twitter.php&dismiss=promotion' );
1953
- echo "<div class='updated fade'><p>" . sprintf( __( "I hope you've enjoyed <strong>WP to Twitter</strong>! Take a look at <a href='%s'>upgrading to WP Tweets PRO</a> for advanced Tweeting with WordPress! <a href='%s'>Dismiss</a>", 'wp-to-twitter' ), $upgrade, $dismiss ) . "</p></div>";
1954
  }
1955
  }
1956
 
3
  Plugin Name: WP to Twitter
4
  Plugin URI: http://www.joedolson.com/wp-to-twitter/
5
  Description: Posts a Tweet when you update your WordPress blog or post a link, using your URL shortening service. Rich in features for customizing and promoting your Tweets.
6
+ Version: 3.2.19
7
  Author: Joseph Dolson
8
  Text Domain: wp-to-twitter
9
  Domain Path: /lang
10
  Author URI: http://www.joedolson.com/
11
  */
12
+ /* Copyright 2008-2017 Joseph C Dolson (email : plugins@joedolson.com)
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
44
  require_once( plugin_dir_path( __FILE__ ) . '/wpt-rate-limiting.php' );
45
 
46
  global $wpt_version;
47
+ $wpt_version = "3.2.19";
48
 
49
  // Create a helper function for easy SDK access.
50
  function wtt_fs() {
73
  return $wtt_fs;
74
  }
75
 
 
 
76
  function wtt_fs_custom_connect_message(
77
  $message,
78
  $user_first_name,
83
  ) {
84
  return sprintf(
85
  __fs( 'hey-x' ) . '<br>' .
86
+ __( 'Can you help me improve %2$s? Let me connect your user, %3$s at %4$s, to %5$s. </p><p><em>This is purely optional, but I appreciate your help!</em>', 'wp-to-twitter' ),
87
  $user_first_name,
88
  '<b>' . $plugin_title . '</b>',
89
  '<b>' . $user_login . '</b>',
92
  );
93
  }
94
 
95
+ // Init Freemius.
96
+ wtt_fs();
97
  wtt_fs()->add_filter( 'connect_message', 'wtt_fs_custom_connect_message', 10, 6 );
98
  wtt_fs()->add_action( 'after_uninstall', 'wtt_fs_uninstall_cleanup' );
99
+
100
 
101
  add_action( 'plugins_loaded', 'wpt_load_textdomain' );
102
  function wpt_load_textdomain() {
187
  update_option( 'wpt_inline_edits', '0' );
188
  // Note that default options are set.
189
  update_option( 'wpt_twitter_setup', '1' );
 
190
  update_option( 'jd_keyword_format', '0' );
191
  }
192
 
311
  update_option( 'wp_to_twitter_version', $wpt_version );
312
  }
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  // Function checks for an alternate URL to be Tweeted. Contribution by Bill Berry.
315
  function wpt_link( $post_ID ) {
316
  $ex_link = false;
384
  *
385
  * @return boolean Success of query.
386
  */
387
+ function wpt_post_to_twitter( $twit, $auth = false, $id = false, $media = false ) {
388
  $recent = wpt_check_recent_tweet( $id, $auth );
389
+ $error = false;
390
  if ( get_option( 'wpt_rate_limiting' ) == 1 ) {
391
  // check whether this post needs to be rate limited.
392
  $continue = wpt_test_rate_limit( $id, $auth );
407
 
408
  return false;
409
  } // exit silently if not authorized
410
+
411
  $check = ( ! $auth ) ? get_option( 'jd_last_tweet' ) : get_user_meta( $auth, 'wpt_last_tweet', true ); // get user's last tweet
412
  // prevent duplicate Tweets
413
  if ( $check == $twit ) {
436
  $attachment = false;
437
  }
438
  }
439
+ $api = "https://api.twitter.com/1.1/statuses/update.json";
440
+ $upload_api = 'https://upload.twitter.com/1.1/media/upload.json';
441
+ $status = array(
442
  'status' => $twit,
443
  'source' => 'wp-to-twitter',
444
  'include_entities' => 'true'
445
  );
446
+
447
  if ( wtt_oauth_test( $auth ) && ( $connection = wtt_oauth_connection( $auth ) ) ) {
448
  if ( $media && $attachment && !$media_id ) {
449
+ $media_id = $connection->media( $upload_api, array( 'auth'=>$auth, 'media'=>$attachment ) );
450
  wpt_mail( 'Media Uploaded', "$auth, $media_id, $attachment" );
451
  if ( $media_id ) {
452
  $status['media_ids'] = $media_id;
496
  update_option( 'wpt_authentication_missing', "$auth" );
497
  break;
498
  case '403':
499
+ $error = __( "403 Forbidden: The request is understood, but has been refused by Twitter.", 'wp-to-twitter' );
500
  break;
501
  case '404':
502
  $error = __( "404 Not Found: The URI requested is invalid or the resource requested does not exist.", 'wp-to-twitter' );
526
  $error = __( "<strong>Code $http_code</strong>: Twitter did not return a recognized response code.", 'wp-to-twitter' );
527
  break;
528
  }
529
+ $body = $connection->body;
530
+ $error_code = ( $http_code != 200 ) ? $body->errors[0]->code : '';
531
+ $error_message = ( $http_code != 200 ) ? $body->errors[0]->message : '';
532
+ $error_supplement = ($error_code != '' ) ? " (Error Code: " . $error_code . ': ' . $error_message . ")" : '';
533
  $error .= ( $supplement != '' ) ? " $supplement" : '';
534
+ $error .= $error_supplement;
535
  // debugging
536
  wpt_mail( "Twitter Response: $http_code, #$id", "$http_code, $error" ); // DEBUG
537
  // end debugging
538
+ // only save last Tweet if successful
539
+ if ( $http_code == '200' ) {
540
+ if ( ! $auth ) {
541
+ update_option( 'jd_last_tweet', $twit );
542
+ } else {
543
+ update_user_meta( $auth, 'wpt_last_tweet', $twit );
544
+ }
545
  }
546
  wpt_saves_error( $id, $auth, $twit, $error, $http_code, time() );
547
  if ( $http_code == '200' ) {
566
  if ( ! $return ) {
567
  wpt_set_log( 'wpt_status_message', $id, $error );
568
  } else {
569
+ do_action( 'wpt_tweet_posted', $connection, $id );
570
  wpt_set_log( 'wpt_status_message', $id, $notice . __( 'Tweet sent successfully.', 'wp-to-twitter' ) );
571
  }
572
 
681
  $cat_descs[] = $cat->description;
682
  }
683
  $cat_names = implode( ' ', apply_filters( 'wpt_twitter_category_names', $cats ) );
684
+ $cat_descs = implode( ' ', apply_filters( 'wpt_twitter_category_descs', $cat_descs ) );
685
  } else {
686
  $category = '';
687
  $cat_desc = '';
699
  if ( $thisposttitle == "" && isset( $_POST['title'] ) ) {
700
  $thisposttitle = $_POST['title'];
701
  }
702
+ $thisposttitle = strip_tags( apply_filters( 'the_title', stripcslashes( $thisposttitle ) ) );
703
  // These are common sequences that may not be fixed by html_entity_decode due to double encoding
704
+ $search = array( '&apos;', '&#039;', '&quot;', '&#034;', '&amp;', '&#038;' );
705
+ $replace = array( "'", "'", '"', '"', '&', '&' );
706
+ $thisposttitle = str_replace( $search, $replace, $thisposttitle );
707
  $values['postTitle'] = html_entity_decode( $thisposttitle, ENT_QUOTES, $encoding );
708
  $values['postLink'] = wpt_link( $post_ID );
709
  $values['blogTitle'] = get_bloginfo( 'name' );
734
  $post_id = $post_ID;
735
  }
736
  $short = get_post_meta( $post_id, '_wpt_short_url', true );
737
+
738
  return $short;
739
  }
740
 
792
  * @return integer $post_ID
793
  */
794
  function wpt_tweet( $post_ID, $type = 'instant' ) {
795
+ if ( wp_is_post_autosave( $post_ID ) || wp_is_post_revision( $post_ID ) ) {
796
  return $post_ID;
797
  }
798
 
799
  wpt_check_version();
800
+ $tweet_this = get_post_meta( $post_ID, '_jd_tweet_this', true );
801
+ $newpost = $oldpost = $is_inline_edit = false;
802
+ $sentence = $template = $nptext = '';
803
  if ( get_option( 'wpt_inline_edits' ) != 1 ) {
804
  if ( isset( $_POST['_inline_edit'] ) || isset( $_REQUEST['bulk_edit'] ) ) {
805
  return false;
810
  }
811
  }
812
  if ( get_option( 'jd_tweet_default' ) == 0 ) {
813
+ $default = ( $tweet_this != 'no' ) ? true : false;
814
  } else {
815
+ $default = ( $tweet_this == 'yes' ) ? true : false;
816
  }
817
+ wpt_mail( "1: JD Tweet This Value: #$post_ID", "Tweet this: $tweet_this /" . get_option( 'jd_tweet_default' ) . " / $type" ); // DEBUG
818
  if ( $default ) { // default switch: depend on default settings.
819
  $post_info = wpt_post_info( $post_ID );
820
  $media = wpt_post_with_media( $post_ID, $post_info );
872
  if ( $new == 0 || $is_inline_edit == true ) {
873
  // if this is an old post and editing updates are enabled
874
  if ( get_option( 'jd_tweet_default_edit' ) == 1 ) {
875
+ $tweet_this = apply_filters( 'wpt_tweet_this_edit', $tweet_this, $_POST );
876
+ if ( $tweet_this != 'yes' ) {
877
  return false;
878
  }
879
  }
914
  if ( $post_info['wpt_delay_tweet'] == 0 || $post_info['wpt_delay_tweet'] == '' || $post_info['wpt_no_delay'] == 'on' ) {
915
  foreach ( $wpt_selected_users as $acct ) {
916
  if ( wtt_oauth_test( $acct, 'verify' ) ) {
917
+ wpt_post_to_twitter( $sentence2, $acct, $post_ID, $media );
918
  }
919
  }
920
  } else {
980
  'rt' => $i,
981
  'post_id' => $post_ID,
982
  'timestamp' => time() + $time + $offset + $delay,
983
+ 'time' => $time,
984
+ 'offset' => $offset,
985
+ 'delay' => $delay,
986
  'current_time' => time(),
987
  'timezone' => get_option( 'gmt_offset' ),
988
  'timestamp_string' => date( 'Y-m-d H:i:s', time() + $time + $offset + $delay ),
989
  'current_time_string' => date( 'Y-m-d H:i:s', time() ),
990
+ ), 1 ), true ); // DEBUG
991
  }
992
  $tweet_limit = apply_filters( 'wpt_tweet_repeat_limit', 4, $post_ID );
993
  if ( $i == $tweet_limit ) {
1000
  }
1001
  }
1002
  } else {
1003
+ wpt_post_to_twitter( $sentence, false, $post_ID, $media );
1004
  }
1005
  // END WPT PRO //
1006
  }
1051
  }
1052
 
1053
  if ( $sentence != '' ) {
1054
+ wpt_post_to_twitter( $sentence, false, $link_ID );
1055
  }
1056
 
1057
  return $link_ID;
1076
  if ( $max_tags == 0 || $max_tags == "" ) {
1077
  $max_tags = 100;
1078
  }
1079
+ $use_cats = ( get_option( 'wpt_use_cats' ) == '1' ) ? true : false;
1080
+ $tags = ( $use_cats == true ) ? wp_get_post_categories( $post_ID, array( 'fields' => 'all' ) ) : get_the_tags( $post_ID );
1081
+ if ( $tags && count( $tags ) > 0 ) {
1082
  $i = 1;
1083
  foreach ( $tags as $value ) {
1084
  if ( function_exists( 'wpt_pro_exists' ) ) {
1096
  $replace = ( $replace == "[ ]" || $replace == "" ) ? "" : $replace;
1097
  $tag = str_ireplace( " ", $replace, trim( $tag ) );
1098
  $tag = preg_replace( '/[\/]/', $replace, $tag ); // remove forward slashes.
1099
+ $tag = ( $strip == '1' ) ? preg_replace( $search, $replace, $tag ) : $tag;
1100
 
1101
  switch ( $term_meta ) {
1102
  case 1 : $newtag = "#$tag"; break;
1145
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1146
  $is_pro = ( function_exists( 'wpt_pro_exists' ) ) ? 'pro' : 'free'; ?>
1147
  <div class='wp-to-twitter <?php echo $is_pro; ?>'>
1148
+ <?php
1149
  $tweet_status = '';
1150
  $options = get_option( 'wpt_post_types' );
1151
  $type = $post->post_type;
1152
  $status = $post->post_status;
1153
  $post_id = $post->ID;
1154
 
1155
+ $tweet_this = get_post_meta( $post_id, '_jd_tweet_this', true );
1156
+ if ( ! $tweet_this ) {
1157
+ $tweet_this = ( get_option( 'jd_tweet_default' ) == '1' ) ? 'no' : 'yes';
1158
  }
1159
  if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && get_option( 'jd_tweet_default_edit' ) == '1' && $status == 'publish' ) {
1160
+ $tweet_this = 'no';
1161
  }
1162
  if ( isset( $_REQUEST['message'] ) && $_REQUEST['message'] != 10 ) { // don't display when draft is updated or if no message
1163
+ if ( ! ( ( $_REQUEST['message'] == 1 ) && ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) ) && $tweet_this != 'no' ) {
1164
  $log = wpt_log( 'wpt_status_message', $post_id );
1165
  $class = ( $log != __( 'Tweet sent successfully.', 'wp-to-twitter' ) ) ? 'error' : 'updated';
1166
  if ( $log != '' ) {
1172
  $failed_tweets = get_post_meta( $post_id, '_wpt_failed' );
1173
  $tweet = esc_attr( stripcslashes( get_post_meta( $post_id, '_jd_twitter', true ) ) );
1174
  $tweet = apply_filters( 'wpt_user_text', $tweet, $status );
1175
+ $template = ( $status == 'publish' ) ? $options[ $type ]['post-edited-text'] : $options[ $type ]['post-published-text'];
1176
 
1177
  if ( $status == 'publish' && $options[ $type ]['post-edited-update'] != 1 ) {
1178
  $tweet_status = sprintf( __( '%s will not be Tweeted on update.', 'wp-to-twitter' ), ucfirst( $type ) );
1181
  if ( $status == 'publish' && ( current_user_can( 'wpt_tweet_now' ) || current_user_can( 'manage_options' ) ) ) {
1182
  ?>
1183
  <div class='tweet-buttons'>
1184
+ <button type='button' class='tweet button-primary' data-action='tweet'><span class='dashicons dashicons-twitter' aria-hidden='true'></span><?php _e( 'Tweet Now', 'wp-to-twitter' ); ?></button>
 
1185
  <?php if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) { ?>
1186
+ <button type='button' class='tweet schedule button-secondary' data-action='schedule' disabled><?php _e( 'Schedule', 'wp-to-twitter' ); ?></button>
1187
+ <button type='button' class='time button-secondary'>
1188
+ <span class="dashicons dashicons-clock" aria-hidden="true"></span><span class="screen-reader-text"><?php _e( 'Set Date/Time', 'wp-to-twitter' ); ?></span>
 
 
1189
  </button>
1190
  <div id="jts">
1191
  <label for='wpt_date'><?php _e( 'Date', 'wp-to-twitter' ); ?></label>
1192
+ <input type='date' value='' class='wpt_date date' name='wpt_datetime' id='wpt_date' data-value='<?php echo date( 'Y-m-d', current_time( 'timestamp' ) ); ?>' /><br/>
 
 
 
 
 
1193
  <label for='wpt_time'><?php _e( 'Time', 'wp-to-twitter' ); ?></label>
1194
+ <input type='text' value='<?php echo date_i18n( 'h:s a', current_time( 'timestamp' ) + 3600 ); ?>' class='wpt_time time' name='wpt_datetime' id='wpt_time'/>
 
 
 
 
1195
  </div>
1196
  <?php } ?>
1197
  <div class='wpt_log' aria-live='assertive'></div>
1201
  if ( current_user_can( 'wpt_twitter_custom' ) || current_user_can( 'manage_options' ) ) {
1202
  ?>
1203
  <p class='jtw'>
1204
+ <label for="jtw"><?php _e( "Custom Twitter Post", 'wp-to-twitter', 'wp-to-twitter' ) ?></label><br/>
1205
+ <textarea class="wpt_tweet_box" name="_jd_twitter" id="jtw" rows="2" cols="60"><?php echo esc_attr( $tweet ); ?></textarea>
1206
+ <?php echo apply_filters( 'wpt_custom_box', '', $tweet, $post_id ); ?>
1207
  </p>
1208
  <?php
1209
+ $expanded = $template;
1210
  if ( get_option( 'jd_twit_prepend' ) != "" ) {
1211
+ $expanded = "<span title='" . __( 'Your prepended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_prepend' ) ) . "</span> " . $expanded;
1212
  }
1213
  if ( get_option( 'jd_twit_append' ) != "" ) {
1214
+ $expanded = $expanded . " <span title='" . __( 'Your appended Tweet text; not part of your template.', 'wp-to-twitter' ) . "'>" . stripslashes( get_option( 'jd_twit_append' ) ) . "</span>";
1215
  }
1216
  ?>
1217
  <p class='template'>
1218
  <?php _e( 'Template:', 'wp-to-twitter' ); ?><br />
1219
+ <code><?php echo stripcslashes( $expanded ); ?></code>
1220
+ <?php echo apply_filters( 'wpt_template_block', '', $expanded, $post_id ); ?>
1221
  </p>
1222
  <?php
1223
  echo apply_filters( 'wpt_custom_retweet_fields', '', $post_id );
1260
  } else {
1261
  echo "<p>";
1262
  if ( function_exists( 'wpt_pro_exists' ) ) {
1263
+ printf( __( 'WP Tweets PRO allows you to select Twitter accounts. <a href="%s">Log in and download now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/account/' );
1264
  } else {
1265
+ printf( __( 'Upgrade to WP Tweets PRO to select Twitter accounts! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' );
1266
  }
1267
  echo "</p>";
1268
  }
1276
  do_action( 'wpt_custom_tab', $post_id, 'visible' );
1277
  } else {
1278
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1279
+ echo "<p>" . sprintf( __( 'Upgrade to WP Tweets PRO to configure options! <a href="%s">Upgrade now!</a>', 'wp-to-twitter' ), 'http://www.wptweetspro.com/wp-tweets-pro/' ) . "</p>";
1280
  }
1281
  }
1282
  ?>
1310
  <?php
1311
  if ( current_user_can( 'wpt_twitter_switch' ) || current_user_can( 'manage_options' ) ) {
1312
  // "no" means 'Don't Tweet' (is checked)
1313
+ $nochecked = ( $tweet_this == 'no' ) ? ' checked="checked"' : '';
1314
+ $yeschecked = ( $tweet_this == 'yes' ) ? ' checked="checked"' : '';
1315
  ?>
1316
  <p class='toggle-btn-group'>
1317
  <input type="radio" name="_jd_tweet_this" value="no" id="jtn"<?php echo $nochecked; ?> /><label for="jtn"><?php _e( "Don't Tweet post", 'wp-to-twitter' ); ?></label>
1318
+ <input type="radio" name="_jd_tweet_this" value="yes" id="jty"<?php echo $yeschecked; ?> /><label for="jty"><?php _e( "Tweet post", 'wp-to-twitter' ); ?></label>
 
1319
  </p>
1320
  <?php
1321
  } else {
1322
  ?>
1323
+ <input type='hidden' name='_jd_tweet_this' value='<?php echo $tweet_this; ?>'/>
1324
  <?php
1325
  }
1326
  wpt_show_tweets( $previous_tweets, $failed_tweets );
1329
  <?php if ( ! function_exists( 'wpt_pro_exists' ) ) {
1330
  /* These aren't actually usages that require esc_url. But using it will give people the illusion that it does something. */
1331
  ?>
1332
+ <strong><a href="http://www.wptweetspro.com/wp-tweets-pro"><?php _e( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) ?></a></strong> &raquo;
1333
  <?php } else { ?>
1334
  <a href="<?php echo esc_url( add_query_arg( 'tab', 'support', admin_url( 'admin.php?page=wp-tweets-pro' ) ) ); ?>#get-support"><?php _e( 'Get Support', 'wp-to-twitter', 'wp-to-twitter' ); ?></a> &raquo;
1335
  <?php } ?>
1342
  </div>
1343
  <?php
1344
  } else { // permissions: this user isn't allowed to Tweet;
1345
+ _e( 'Your role does not have the ability to Post Tweets from this site.', 'wp-to-twitter' ); ?> <input type='hidden' name='_jd_tweet_this' value='no'/> <?php
 
1346
  }
1347
  }
1348
 
1403
  if ( $has_history || $list ) {
1404
  echo "<p><input type='checkbox' name='wpt_clear_history' id='wptch' value='clear' /> <label for='wptch'>" . __( 'Delete Tweet History', 'wp-to-twitter' ) . "</label></p>";
1405
  }
1406
+ ?>
1407
+ </div>
1408
+ <?php
1409
  }
1410
  }
1411
 
1445
  echo "Invalid Security Check";
1446
  die;
1447
  }
1448
+ $action = ( $_REQUEST['tweet_action'] == 'tweet' ) ? 'tweet' : 'schedule';
1449
+ $authors = ( isset( $_REQUEST['tweet_auth'] ) && $_REQUEST['tweet_auth'] != null ) ? $_REQUEST['tweet_auth'] : false;
1450
+ $upload = ( isset( $_REQUEST['tweet_upload'] ) && $_REQUEST['tweet_upload'] != null ) ? $_REQUEST['tweet_upload'] : 1;
1451
  $current_user = wp_get_current_user();
1452
  if ( function_exists( 'wpt_pro_exists' ) && wpt_pro_exists() ) {
1453
  if ( wtt_oauth_test( $current_user->ID, 'verify' ) ) {
1460
  $auth = false;
1461
  $user_ID = $current_user->ID;
1462
  }
1463
+
1464
+ $authors = ( is_array( $authors ) && !empty( $authors ) ) ? $authors : array( $auth );
1465
+
1466
  if ( current_user_can( 'wpt_can_tweet' ) ) {
1467
  $options = get_option( 'wpt_post_types' );
1468
  $post_ID = intval( $_REQUEST['tweet_post_id'] );
1476
  $print_schedule = date_i18n( get_option( 'date_format' ) . ' @ ' . get_option( 'time_format' ), $schedule );
1477
  $offset = ( 60 * 60 * get_option( 'gmt_offset' ) );
1478
  $schedule = $schedule - $offset;
1479
+ $media = ( $upload == 1 ) ? false: true; // this is correct; the boolean logic is reversed. Blah.
1480
+
1481
+ foreach( $authors as $auth ) {
1482
+
1483
+ $auth = ( $auth == 'main' ) ? false : $auth;
1484
+
1485
+ switch ( $action ) {
1486
+ case 'tweet' :
1487
+ wpt_post_to_twitter( $sentence, $auth, $post_ID, $media );
1488
+ break;
1489
+ case 'schedule' :
1490
+ wp_schedule_single_event( $schedule, 'wpt_schedule_tweet_action', array(
1491
+ 'id' => $auth,
1492
+ 'sentence' => $sentence,
1493
+ 'rt' => 0,
1494
+ 'post_id' => $post_ID
1495
+ ) );
1496
+ break;
1497
+ }
1498
+ $return = ( $action == 'tweet' ) ? wpt_log( 'wpt_status_message', $post_ID ) : sprintf( __( "Tweet scheduled: '%s' for %s", 'wp-tweets-pro' ), $sentence, $print_schedule );
1499
+ echo $return;
1500
+ if ( count( $authors ) > 1 ) {
1501
+ echo "<br />";
1502
+ }
1503
  }
 
 
1504
  } else {
1505
  echo __( 'You are not authorized to perform this action', 'wp-to-twitter' );
1506
  }
1517
  wp_register_style( 'wpt-post-styles', plugins_url( 'css/post-styles.css', __FILE__ ) );
1518
  wp_enqueue_style( 'wpt-post-styles' );
1519
  if ( $current_screen->base == 'post' ) {
1520
+ $allowed = 140 - mb_strlen( stripslashes( get_option( 'jd_twit_prepend' ) . get_option( 'jd_twit_append' ) ) );
1521
  } else {
1522
  $allowed = ( wpt_is_ssl( home_url() ) ) ? 137 : 138;
1523
  }
1537
  ) );
1538
  echo "
1539
  <style type='text/css'>
1540
+ #wp2t h3 span, #wp2t h2 span { padding-left: 30px; background: url(" . plugins_url( 'wp-to-twitter/images/twitter-bird-light-bgs.png' ) . ") left 50% no-repeat; }
1541
  </style>";
1542
  }
1543
  }
1556
  $yourls = $_POST['_yourls_keyword'];
1557
  $update = update_post_meta( $id, '_yourls_keyword', $yourls );
1558
  }
1559
+ if ( isset( $_POST['_jd_twitter'] ) && $_POST['_jd_twitter'] != '' ) {
1560
+ $twitter = $_POST['_jd_twitter'];
1561
+ $update = update_post_meta( $id, '_jd_twitter', $twitter );
1562
+ } else if ( isset( $_POST['_jd_twitter'] ) && $_POST['_jd_twitter'] == '' ) {
1563
+ delete_post_meta( $id, '_jd_twitter' );
1564
  }
1565
  if ( isset( $_POST['_jd_wp_twitter'] ) && $_POST['_jd_wp_twitter'] != '' ) {
1566
+ $wp_twitter = $_POST['_jd_wp_twitter'];
1567
+ $update = update_post_meta( $id, '_jd_wp_twitter', $wp_twitter );
1568
  }
1569
  if ( isset( $_POST['_jd_tweet_this'] ) ) {
1570
+ $tweet_this = ( $_POST['_jd_tweet_this'] == 'no' ) ? 'no' : 'yes';
1571
+ $update = update_post_meta( $id, '_jd_tweet_this', $tweet_this );
1572
  } else {
1573
  if ( isset( $_POST['_wpnonce'] ) ) {
1574
+ $tweet_default = ( get_option( 'jd_tweet_default' ) == 1 ) ? 'no' : 'yes';
1575
+ $update = update_post_meta( $id, '_jd_tweet_this', $tweet_default );
1576
  }
1577
  }
1578
  if ( isset( $_POST['wpt_clear_history'] ) && $_POST['wpt_clear_history'] == 'clear' ) {
1590
  }
1591
  }
1592
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1593
  /**
1594
  * Show user profile data on Edit User pages.
1595
  *
1705
  * Add stylesheets to WP to Twitter pages.
1706
  */
1707
  function wpt_admin_style() {
1708
+ if ( isset( $_GET['page'] ) && ( $_GET['page'] == "wp-to-twitter" || $_GET['page'] == "wp-tweets-pro" || $_GET['page'] == "wp-to-twitter-schedule" || $_GET['page'] == "wp-to-twitter-tweets" || $_GET['page'] == "wp-to-twitter-errors" ) ) {
1709
  wp_enqueue_style( 'wpt-styles', plugins_url( 'css/styles.css', __FILE__ ) );
1710
  }
1711
  }
1718
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
1719
  $links[] = "<a href='$admin_url'>" . __( 'WP to Twitter Settings', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1720
  if ( ! function_exists( 'wpt_pro_exists' ) ) {
1721
+ $links[] = "<a href='http://www.wptweetspro.com/wp-tweets-pro'>" . __( 'Go Premium', 'wp-to-twitter', 'wp-to-twitter' ) . "</a>";
1722
  }
1723
  }
1724
 
1778
  }
1779
  }
1780
  }
1781
+
1782
  return false;
1783
  }
1784
 
1788
  */
1789
  function wpt_future_to_publish( $post ) {
1790
  $id = $post->ID;
1791
+ if ( wp_is_post_autosave( $id ) || wp_is_post_revision( $id ) || ! wpt_in_post_type( $id ) ) {
1792
  return;
1793
  }
1794
  wpt_twit_future( $id );
1804
  $post = get_post( $id );
1805
  if ( $post->post_status != 'publish' ) {
1806
  return;
1807
+ }
1808
+ // is there any reason to accept any other status?
1809
+
1810
+ // This is an issue only until the release of WP 4.7
1811
+ remove_action( 'save_post', 'wpt_twit', 15 );
1812
  wpt_twit_instant( $id );
1813
+ add_action( 'save_post', 'wpt_twit', 15 );
1814
  }
1815
 
1816
  add_action( 'xmlrpc_publish_post', 'wpt_twit_xmlrpc' );
1829
 
1830
  return;
1831
  }
1832
+
1833
  wpt_tweet( $id, 'future' );
1834
  }
1835
 
1893
  */
1894
  function wpt_promotion_notice() {
1895
  if ( current_user_can( 'activate_plugins' ) && get_option( 'wpt_promotion_scheduled' ) == 2 && get_option( 'jd_donations' ) != 1 ) {
1896
+ $upgrade = "http://www.wptweetspro.com/wp-tweets-pro/";
1897
+ $dismiss = admin_url( 'admin.php?page=wp-tweets-pro&dismiss=promotion' );
1898
+ echo "<div class='notice'><p>" . sprintf( __( "I hope you've enjoyed <strong>WP to Twitter</strong>! Take a look at <a href='%s'>upgrading to WP Tweets PRO</a> for advanced Tweeting with WordPress! <a href='%s'>Dismiss</a>", 'wp-to-twitter' ), $upgrade, $dismiss ) . "</p></div>";
1899
  }
1900
  }
1901
 
wpt-feed.php CHANGED
@@ -1,4 +1,7 @@
1
  <?php
 
 
 
2
  /*
3
  * Version 2.0.3, Twitter Feed for Developers by Storm Consultancy (Liam Gladdy)
4
  * The base class for the storm twitter feed for developers.
@@ -166,22 +169,22 @@ class WPT_TwitterFeed {
166
  $token = $this->defaults['token'];
167
  $token_secret = $this->defaults['token_secret'];
168
  $cachename = $screenname . "-" . $this->getOptionsHash( $options );
169
- $options = array_merge( $options, array( 'screen_name' => $screenname, 'count' => 20 ) );
170
 
171
  if ( empty( $key ) ) {
172
- return array( 'error' => 'Missing Consumer Key - Check Settings' );
173
  }
174
  if ( empty( $secret ) ) {
175
- return array( 'error' => 'Missing Consumer Secret - Check Settings' );
176
  }
177
  if ( empty( $token ) ) {
178
- return array( 'error' => 'Missing Access Token - Check Settings' );
179
  }
180
  if ( empty( $token_secret ) ) {
181
- return array( 'error' => 'Missing Access Token Secret - Check Settings' );
182
  }
183
  if ( empty( $screenname ) ) {
184
- return array( 'error' => __( 'Missing Twitter Feed Screen Name - Check Settings', 'wp-to-twitter' ) );
185
  }
186
 
187
  $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ } // Exit if accessed directly
5
  /*
6
  * Version 2.0.3, Twitter Feed for Developers by Storm Consultancy (Liam Gladdy)
7
  * The base class for the storm twitter feed for developers.
169
  $token = $this->defaults['token'];
170
  $token_secret = $this->defaults['token_secret'];
171
  $cachename = $screenname . "-" . $this->getOptionsHash( $options );
172
+ $options = array_merge( $options, array( 'screen_name' => $screenname, 'count' => 20, 'include_ext_alt_text' => 'true' ) );
173
 
174
  if ( empty( $key ) ) {
175
+ return array( 'error' => __( 'Missing Consumer Key - Check settings', 'wp-to-twitter' ) );
176
  }
177
  if ( empty( $secret ) ) {
178
+ return array( 'error' => __( 'Missing Consumer Secret - Check settings', 'wp-to-twitter' ) );
179
  }
180
  if ( empty( $token ) ) {
181
+ return array( 'error' => __( 'Missing Access Token - Check settings', 'wp-to-twitter' ) );
182
  }
183
  if ( empty( $token_secret ) ) {
184
+ return array( 'error' => __( 'Missing Access Token Secret - Check settings', 'wp-to-twitter' ) );
185
  }
186
  if ( empty( $screenname ) ) {
187
+ return array( 'error' => __( 'Missing Twitter Feed Screen Name - Check settings', 'wp-to-twitter' ) );
188
  }
189
 
190
  $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
wpt-functions.php CHANGED
@@ -74,7 +74,7 @@ function wpt_check_functions() {
74
  //check twitter credentials
75
  if ( wtt_oauth_test() ) {
76
  $rand = rand( 1000000, 9999999 );
77
- $testpost = jd_doTwitterAPIPost( "This is a test of WP to Twitter. $shrink ($rand)" );
78
  if ( $testpost ) {
79
  $message .= __( "<li><strong>WP to Twitter successfully submitted a status update to Twitter.</strong></li>", 'wp-to-twitter' );
80
  } else {
@@ -112,6 +112,10 @@ function wpt_settings_tabs() {
112
  'support' => __( 'Get Help', 'wp-to-twitter' ),
113
  'pro' => $pro_text
114
  );
 
 
 
 
115
  $pages = apply_filters( 'wpt_settings_tabs_pages', $pages, $current );
116
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
117
 
@@ -209,7 +213,9 @@ function wpt_show_debug() {
209
 
210
  function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
211
  $input = wpt_fetch_url( $url, $method );
 
212
  $obj = json_decode( $input, $array );
 
213
  if ( function_exists( 'json_last_error' ) ) { // > PHP 5.3
214
  try {
215
  if ( is_null( $obj ) ) {
@@ -243,7 +249,7 @@ function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
243
  return $obj;
244
  }
245
 
246
- function is_valid_url( $url ) {
247
  if ( is_string( $url ) ) {
248
  $url = urldecode( $url );
249
 
@@ -279,48 +285,6 @@ function wpt_fetch_url( $url, $method = 'GET', $body = '', $headers = '', $retur
279
  }
280
  }
281
 
282
- if ( ! function_exists( 'mb_strlen' ) ) {
283
- /**
284
- * Fallback implementation of mb_strlen, hardcoded to UTF-8.
285
- *
286
- * @param string $str
287
- *
288
- * @return int
289
- */
290
- function mb_strlen( $str ) {
291
- $counts = count_chars( $str );
292
- $total = 0;
293
-
294
- // Count ASCII bytes
295
- for ( $i = 0; $i < 0x80; $i ++ ) {
296
- $total += $counts[ $i ];
297
- }
298
-
299
- // Count multibyte sequence heads
300
- for ( $i = 0xc0; $i < 0xff; $i ++ ) {
301
- $total += $counts[ $i ];
302
- }
303
-
304
- return $total;
305
- }
306
- }
307
-
308
- if ( ! function_exists( 'mb_substr' ) ) {
309
- function mb_substr( $str, $start, $count = 'end' ) {
310
- if ( $start != 0 ) {
311
- $split = mb_substr_split_unicode( $str, intval( $start ) );
312
- $str = substr( $str, $split );
313
- }
314
-
315
- if ( $count !== 'end' ) {
316
- $split = mb_substr_split_unicode( $str, intval( $count ) );
317
- $str = substr( $str, 0, $split );
318
- }
319
-
320
- return $str;
321
- }
322
- }
323
-
324
  if ( ! function_exists( 'mb_substr_split_unicode' ) ) {
325
  function mb_substr_split_unicode( $str, $splitPos ) {
326
  if ( $splitPos == 0 ) {
@@ -479,16 +443,16 @@ function wtt_option_selected( $field, $value, $type = 'checkbox' ) {
479
  /**
480
  * Compares two dates to identify which is earlier. Used to differentiate between post edits and original publication.
481
  *
482
- * @param string $early
483
  * @param string $late
484
  *
485
  * @return integer 1|0
486
  */
487
- function wpt_date_compare( $early, $late ) {
488
  $modifier = apply_filters( 'wpt_edit_sensitivity', 0 ); // alter time in seconds to modified date.
489
- $firstdate = strtotime( $early );
490
- $lastdate = strtotime( $late ) + $modifier;
491
- if ( $firstdate <= $lastdate ) { // if post_modified is before or equal to post_date
492
  return 1;
493
  } else {
494
  return 0;
@@ -535,7 +499,7 @@ function wpt_get_support_form() {
535
  // send fields for WP to Twitter
536
  $license = ( get_option( 'wpt_license_key' ) != '' ) ? get_option( 'wpt_license_key' ) : 'none';
537
  if ( $license != 'none' ) {
538
- $valid = ( ( get_option( 'wpt_license_valid' ) == 'true' ) || ( get_option( 'wpt_license_valid' ) == 'active' ) ) ? ' (active)' : ' (inactive)';
539
  } else {
540
  $valid = '';
541
  }
@@ -974,6 +938,208 @@ class WPT_Normalizer
974
  }
975
  }
976
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
  /**
978
  * Functions to provide fallbacks for changed function names in case any plug-ins or themes are calling WP to Twitter functions in custom code.
979
  */
@@ -999,4 +1165,8 @@ function jd_twit( $post_ID, $type = 'instant' ) {
999
 
1000
  function jd_addTwitterAdminStyles() {
1001
  return wpt_admin_style();
 
 
 
 
1002
  }
74
  //check twitter credentials
75
  if ( wtt_oauth_test() ) {
76
  $rand = rand( 1000000, 9999999 );
77
+ $testpost = wpt_post_to_twitter( "This is a test of WP to Twitter. $shrink ($rand)" );
78
  if ( $testpost ) {
79
  $message .= __( "<li><strong>WP to Twitter successfully submitted a status update to Twitter.</strong></li>", 'wp-to-twitter' );
80
  } else {
112
  'support' => __( 'Get Help', 'wp-to-twitter' ),
113
  'pro' => $pro_text
114
  );
115
+ if ( get_option( 'jd_donations' ) == '1' && !function_exists( 'wpt_pro_exists' ) ) {
116
+ unset( $pages['pro'] );
117
+ }
118
+
119
  $pages = apply_filters( 'wpt_settings_tabs_pages', $pages, $current );
120
  $admin_url = admin_url( 'admin.php?page=wp-tweets-pro' );
121
 
213
 
214
  function wpt_remote_json( $url, $array = true, $method = 'GET' ) {
215
  $input = wpt_fetch_url( $url, $method );
216
+ wpt_mail( 'Remote JSON input', print_r( $input, 1 ) . "\n\n" . $url );
217
  $obj = json_decode( $input, $array );
218
+ wpt_mail( 'Remote JSON return value', print_r( $obj, 1 ) . "\n\n" . "$url" );
219
  if ( function_exists( 'json_last_error' ) ) { // > PHP 5.3
220
  try {
221
  if ( is_null( $obj ) ) {
249
  return $obj;
250
  }
251
 
252
+ function wpt_is_valid_url( $url ) {
253
  if ( is_string( $url ) ) {
254
  $url = urldecode( $url );
255
 
285
  }
286
  }
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  if ( ! function_exists( 'mb_substr_split_unicode' ) ) {
289
  function mb_substr_split_unicode( $str, $splitPos ) {
290
  if ( $splitPos == 0 ) {
443
  /**
444
  * Compares two dates to identify which is earlier. Used to differentiate between post edits and original publication.
445
  *
446
+ * @param string $modified
447
  * @param string $late
448
  *
449
  * @return integer 1|0
450
  */
451
+ function wpt_date_compare( $modified, $postdate ) {
452
  $modifier = apply_filters( 'wpt_edit_sensitivity', 0 ); // alter time in seconds to modified date.
453
+ $mod_date = strtotime( $modified );
454
+ $post_date = strtotime( $postdate ) + $modifier;
455
+ if ( $mod_date <= $post_date ) { // if post_modified is before or equal to post_date
456
  return 1;
457
  } else {
458
  return 0;
499
  // send fields for WP to Twitter
500
  $license = ( get_option( 'wpt_license_key' ) != '' ) ? get_option( 'wpt_license_key' ) : 'none';
501
  if ( $license != 'none' ) {
502
+ $valid = ( ( get_option( 'wpt_license_valid' ) == 'true' ) || ( get_option( 'wpt_license_valid' ) == 'active' ) || ( get_option( 'wpt_license_valid' ) == 'valid' ) ) ? ' (active)' : ' (inactive)';
503
  } else {
504
  $valid = '';
505
  }
938
  }
939
  }
940
 
941
+
942
+ /**
943
+ * Migrates post meta to new format when post is called in editor.
944
+ */
945
+ add_action( 'load-post.php', 'wpt_migrate_url_meta' );
946
+ function wpt_migrate_url_meta() {
947
+ $post_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : false;
948
+ if ( !$post_id ) {
949
+ // if this is a new post screen, no migration
950
+ return;
951
+ }
952
+
953
+ $post = get_post( $post_id );
954
+ if ( strtotime( $post->post_date ) > 1449764285 ) {
955
+ // if this post was added after the migration function was added, it will not need to be migrated. Guaranteed.
956
+ return;
957
+ }
958
+
959
+ $short = get_post_meta( $post_id, '_wpt_short_url', true );
960
+ if ( $short != '' ) {
961
+ return;
962
+ }
963
+ if ( $short == "" ) {
964
+ $short = get_post_meta( $post_id, '_wp_jd_goo', true );
965
+ delete_post_meta( $post_id, '_wp_jd_goo' );
966
+ }
967
+ if ( $short == "" ) {
968
+ $short = get_post_meta( $post_id, '_wp_jd_supr', true );
969
+ delete_post_meta( $post_id, '_wp_jd_supr' );
970
+ }
971
+ if ( $short == "" ) {
972
+ $short = get_post_meta( $post_id, '_wp_jd_wp', true );
973
+ delete_post_meta( $post_id, '_wp_jd_wp' );
974
+ }
975
+ if ( $short == "" ) {
976
+ $short = get_post_meta( $post_id, '_wp_jd_ind', true );
977
+ delete_post_meta( $post_id, '_wp_jd_ind' );
978
+ }
979
+ if ( $short == "" ) {
980
+ $short = get_post_meta( $post_id, '_wp_jd_yourls', true );
981
+ delete_post_meta( $post_id, '_wp_jd_yourls' );
982
+ }
983
+ if ( $short == "" ) {
984
+ $short = get_post_meta( $post_id, '_wp_jd_url', true );
985
+ delete_post_meta( $post_id, '_wp_jd_url' );
986
+ }
987
+ if ( $short == "" ) {
988
+ $short = get_post_meta( $post_id, '_wp_jd_joturl', true );
989
+ delete_post_meta( $post_id, '_wp_jd_joturl' );
990
+ }
991
+ if ( $short == "" ) {
992
+ // don't delete target link
993
+ $short = get_post_meta( $post_id, '_wp_jd_target', true );
994
+ }
995
+ if ( $short == "" ) {
996
+ $short = get_post_meta( $post_id, '_wp_jd_clig', true );
997
+ delete_post_meta( $post_id, '_wp_jd_clig' );
998
+ }
999
+
1000
+ if ( $short == '' ) {
1001
+ $short = get_permalink( $post_id );
1002
+ }
1003
+
1004
+ update_post_meta( $post_id, '_wpt_short_url', $short );
1005
+ }
1006
+
1007
+ function wp_get_curl( $url ) {
1008
+
1009
+ $curl = curl_init( $url );
1010
+
1011
+ curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
1012
+ curl_setopt( $curl, CURLOPT_HEADER, 0 );
1013
+ curl_setopt( $curl, CURLOPT_USERAGENT, '' );
1014
+ curl_setopt( $curl, CURLOPT_TIMEOUT, 10 );
1015
+ curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
1016
+ curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
1017
+
1018
+ $response = curl_exec( $curl );
1019
+ if( 0 !== curl_errno( $curl ) || 200 !== curl_getinfo( $curl, CURLINFO_HTTP_CODE ) ) {
1020
+ $response = false;
1021
+ } // end if
1022
+ curl_close( $curl );
1023
+
1024
+ return $response;
1025
+ }
1026
+
1027
+ add_action( 'dp_duplicate_post', 'wpt_delete_copied_meta', 10, 2 );
1028
+ add_action( 'dp_duplicate_page', 'wpt_delete_copied_meta', 10, 2 );
1029
+ /**
1030
+ * Prevent 'Duplicate Posts' plug-in from copying WP to Twitter meta data
1031
+ */
1032
+ function wpt_delete_copied_meta( $new_id, $post ) {
1033
+ $disable = apply_filters( 'wpt_allow_copy_meta', false );
1034
+ if ( $disable ) {
1035
+ return;
1036
+ }
1037
+ // delete WP to Twitter's meta data from copied post.
1038
+ // I can't prevent them from being copied, but I can delete them after the fact.
1039
+ delete_post_meta( $new_id, '_wpt_short_url' );
1040
+ delete_post_meta( $new_id, '_wp_jd_target' );
1041
+ delete_post_meta( $new_id, '_jd_wp_twitter' );
1042
+ delete_post_meta( $new_id, '_jd_twitter' );
1043
+ delete_post_meta( $new_id, '_wpt_failed' );
1044
+ }
1045
+
1046
+ // uninstall WP to Twitter
1047
+ function wtt_fs_uninstall_cleanup() {
1048
+ delete_option( 'wpt_post_types' );
1049
+ delete_option( 'jd_twit_remote' );
1050
+ delete_option( 'jd_post_excerpt' );
1051
+
1052
+ delete_option( 'comment-published-update' );
1053
+ delete_option( 'comment-published-text' );
1054
+ delete_option( 'wpt_status_message_last' );
1055
+ delete_option( 'wtt_twitter_username' );
1056
+ // Su.pr API
1057
+ delete_option( 'suprapi' );
1058
+
1059
+ // Error checking
1060
+ delete_option( 'jd-functions-checked' );
1061
+ delete_option( 'wp_twitter_failure' );
1062
+ delete_option( 'wp_supr_failure' );
1063
+ delete_option( 'wp_url_failure' );
1064
+ delete_option( 'wp_bitly_failure' );
1065
+ delete_option( 'wpt_curl_error' );
1066
+
1067
+ // Rate Limiting
1068
+ delete_option( 'wpt_rate_limits' );
1069
+ delete_option( 'wpt_default_rate_limit' );
1070
+ delete_option( 'wpt_rate_limit' );
1071
+ delete_option( 'wpt_rate_limiting' );
1072
+
1073
+ // Blogroll options
1074
+ delete_option( 'jd-use-link-title' );
1075
+ delete_option( 'jd-use-link-description' );
1076
+ delete_option( 'newlink-published-text' );
1077
+ delete_option( 'jd_twit_blogroll' );
1078
+
1079
+ // Default publishing options.
1080
+ delete_option( 'jd_tweet_default' );
1081
+ delete_option( 'jd_tweet_default_edit' );
1082
+ delete_option( 'wpt_inline_edits' );
1083
+
1084
+ // Note that default options are set.
1085
+ delete_option( 'twitterInitialised' );
1086
+ delete_option( 'wpt_twitter_setup' );
1087
+ delete_option( 'wp_twitter_failure' );
1088
+ delete_option( 'twitterlogin' );
1089
+ delete_option( 'twitterpw' );
1090
+ delete_option( 'twitterlogin_encrypted' );
1091
+ delete_option( 'suprapi' );
1092
+ delete_option( 'jd_twit_quickpress' );
1093
+ delete_option( 'jd-use-supr' );
1094
+ delete_option( 'jd-use-none' );
1095
+ delete_option( 'jd-use-wp' );
1096
+
1097
+ // Special Options
1098
+ delete_option( 'jd_twit_prepend' );
1099
+ delete_option( 'jd_twit_append' );
1100
+ delete_option( 'jd_twit_remote' );
1101
+ delete_option( 'twitter-analytics-campaign' );
1102
+ delete_option( 'use-twitter-analytics' );
1103
+ delete_option( 'jd_twit_custom_url' );
1104
+ delete_option( 'jd_shortener' );
1105
+ delete_option( 'jd_strip_nonan' );
1106
+
1107
+ delete_option( 'jd_individual_twitter_users' );
1108
+ delete_option( 'use_tags_as_hashtags' );
1109
+ delete_option( 'jd_max_tags' );
1110
+ delete_option( 'jd_max_characters' );
1111
+ // Bitly Settings
1112
+ delete_option( 'bitlylogin' );
1113
+ delete_option( 'jd-use-bitly' );
1114
+ delete_option( 'bitlyapi' );
1115
+
1116
+ // twitter compatible api
1117
+ delete_option( 'jd_api_post_status' );
1118
+ delete_option( 'app_consumer_key' );
1119
+ delete_option( 'app_consumer_secret' );
1120
+ delete_option( 'oauth_token' );
1121
+ delete_option( 'oauth_token_secret' );
1122
+
1123
+ //dymamic analytics
1124
+ delete_option( 'jd_dynamic_analytics' );
1125
+ delete_option( 'use_dynamic_analytics' );
1126
+ //category limits
1127
+ delete_option( 'limit_categories' );
1128
+ delete_option( 'tweet_categories' );
1129
+ //yourls installation
1130
+ delete_option( 'yourlsapi' );
1131
+ delete_option( 'yourlspath' );
1132
+ delete_option( 'yourlsurl' );
1133
+ delete_option( 'yourlslogin' );
1134
+ delete_option( 'jd_replace_character' );
1135
+ delete_option( 'jd_date_format' );
1136
+ delete_option( 'jd_keyword_format' );
1137
+ //Version
1138
+ delete_option( 'wp_to_twitter_version' );
1139
+ delete_option( 'wpt_authentication_missing' );
1140
+ delete_option( 'wpt_http' );
1141
+ }
1142
+
1143
  /**
1144
  * Functions to provide fallbacks for changed function names in case any plug-ins or themes are calling WP to Twitter functions in custom code.
1145
  */
1165
 
1166
  function jd_addTwitterAdminStyles() {
1167
  return wpt_admin_style();
1168
+ }
1169
+
1170
+ function jd_doTwitterAPIPost( $twit, $auth = false, $id = false, $media = false ) {
1171
+ return wpt_post_to_twitter( $twit, $auth, $id, $media );
1172
  }
wpt-rate-limiting.php CHANGED
@@ -88,6 +88,7 @@ function wpt_test_rate_limit( $post_ID, $auth ) {
88
  function wpt_default_rate_limit( $term = false ) {
89
  $limit = ( get_option( 'wpt_default_rate_limit' ) != '' ) ? get_option( 'wpt_default_rate_limit' ) : 10;
90
  $limit = ( $limit == 0 ) ? 1 : $limit;
 
91
  return apply_filters( 'wpt_default_rate_limit', $limit, $term );
92
  }
93
 
88
  function wpt_default_rate_limit( $term = false ) {
89
  $limit = ( get_option( 'wpt_default_rate_limit' ) != '' ) ? get_option( 'wpt_default_rate_limit' ) : 10;
90
  $limit = ( $limit == 0 ) ? 1 : $limit;
91
+
92
  return apply_filters( 'wpt_default_rate_limit', $limit, $term );
93
  }
94
 
wpt-truncate.php CHANGED
@@ -3,12 +3,77 @@ if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
  } // Exit if accessed directly
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = false ) {
7
- // media file occupies 22 characters, need to account for in shortening.
8
- $maxlength = apply_filters( 'wpt_max_length', array( 'with_media' => 116, 'without_media' => 139 ) );
9
- $length = ( wpt_post_with_media( $post_ID, $post ) ) ? $maxlength['with_media'] : $maxlength['without_media'];
10
  $tweet = apply_filters( 'wpt_tweet_sentence', $tweet, $post_ID );
11
  $tweet = trim( wpt_custom_shortcodes( $tweet, $post_ID ) );
 
12
  $encoding = ( get_option( 'blog_charset' ) != 'UTF-8' && get_option( 'blog_charset' ) != '' ) ? get_option( 'blog_charset' ) : 'UTF-8';
13
  $diff = 0;
14
 
@@ -52,15 +117,15 @@ function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = fa
52
  $has_short_url = wpt_has( $tweet, '#url#' );
53
  $has_long_url = wpt_has( $tweet, '#longurl#' );
54
 
55
- $url_strlen = mb_strlen( urldecode( wpt_normalize( $values['url'] ) ), $encoding );
56
  $longurl_strlen = mb_strlen( urldecode( wpt_normalize( $values['longurl'] ) ), $encoding );
57
  /**
58
  * Tweet is too long, so we'll have to truncate that sucker.
59
  */
60
  $length_array = wpt_length_array( $values, $encoding );
61
 
62
- // Twitter's t.co shortener is mandatory. All URLS are max-character value set by Twitter.
63
- $tco = ( wpt_is_ssl( $values['url'] ) ) ? 23 : 22;
64
  $order = get_option( 'wpt_truncation_order' );
65
  if ( is_array( $order ) ) {
66
  asort( $order );
@@ -207,7 +272,6 @@ function wpt_remove_tag( $key ) {
207
  }
208
 
209
  return $return;
210
- //$key == 'account' || $key == 'author' || $key == 'category' || $key == 'date' || $key == 'modified' || $key == 'reference' || $key == '@'
211
  }
212
 
213
  function wpt_tags() {
@@ -288,4 +352,53 @@ function wpt_length_array( $values, $encoding ) {
288
  }
289
 
290
  return $array;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  }
3
  exit;
4
  } // Exit if accessed directly
5
 
6
+ function wpt_max_length() {
7
+ $config = get_transient( 'wpt_twitter_config' );
8
+ if ( ! $config ) {
9
+ $connection = wtt_oauth_connection();
10
+ if ( $connection ) {
11
+ $config = $connection->get( 'https://api.twitter.com/1.1/help/configuration.json' );
12
+ set_transient( 'wpt_twitter_config', $config, 60*60*24 );
13
+ } else {
14
+ $config = json_encode( array(
15
+ 'base_length' => 139,
16
+ 'http_length' => 23,
17
+ 'https_length' => 23,
18
+ 'reserved_chars' => 24
19
+ ) );
20
+ }
21
+ }
22
+
23
+ $decoded = json_decode( $config );
24
+
25
+ if ( is_object( $decoded ) && isset( $decoded->short_url_length ) ) {
26
+ $short_url_length = $decoded->short_url_length;
27
+ $short_url_https = $decoded->short_url_length_https;
28
+ $reserved_char = $decoded->characters_reserved_per_media;
29
+ $values = array(
30
+ 'base_length' => 139,
31
+ 'http_length' => $short_url_length,
32
+ 'https_length' => $short_url_https,
33
+ 'reserved_chars' => $reserved_char
34
+ );
35
+
36
+ } else {
37
+ // if config query is invalid, use default values; these may become invalid
38
+ $values = array(
39
+ 'base_length' => 139,
40
+ 'http_length' => 23,
41
+ 'https_length' => 23,
42
+ 'reserved_chars' => 24
43
+ );
44
+ }
45
+
46
+ return apply_filters( 'wpt_max_length', $values );
47
+ }
48
+
49
+ add_filter( 'wpt_tweet_sentence', 'wpt_filter_urls', 10, 2 );
50
+ function wpt_filter_urls( $tweet, $post_ID ) {
51
+ preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $tweet, $match);
52
+ $title = get_the_title( $post_ID );
53
+
54
+ if ( isset( $match[0] ) && !empty( $match[0] ) ) {
55
+ $urls = $match[0];
56
+ foreach( $urls as $url ) {
57
+ if ( esc_url( $url ) ) {
58
+ $short = wpt_shorten_url( $url, $title, $post_ID, false, false );
59
+ if ( $short ) {
60
+ $tweet = str_replace( $url, $short, $tweet );
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ return $tweet;
67
+ }
68
+
69
+
70
  function jd_truncate_tweet( $tweet, $post, $post_ID, $retweet = false, $ref = false ) {
71
+ // media file no longer needs accounting in shortening. 9/22/2016
72
+ $maxlength = wpt_max_length();
73
+ $length = $maxlength['base_length'];
74
  $tweet = apply_filters( 'wpt_tweet_sentence', $tweet, $post_ID );
75
  $tweet = trim( wpt_custom_shortcodes( $tweet, $post_ID ) );
76
+ $tweet = trim( wpt_user_meta_shortcodes( $tweet, $post['authId'] ) );
77
  $encoding = ( get_option( 'blog_charset' ) != 'UTF-8' && get_option( 'blog_charset' ) != '' ) ? get_option( 'blog_charset' ) : 'UTF-8';
78
  $diff = 0;
79
 
117
  $has_short_url = wpt_has( $tweet, '#url#' );
118
  $has_long_url = wpt_has( $tweet, '#longurl#' );
119
 
120
+ $url_strlen = mb_strlen( urldecode( wpt_normalize( $values['url'] ) ), $encoding );
121
  $longurl_strlen = mb_strlen( urldecode( wpt_normalize( $values['longurl'] ) ), $encoding );
122
  /**
123
  * Tweet is too long, so we'll have to truncate that sucker.
124
  */
125
  $length_array = wpt_length_array( $values, $encoding );
126
 
127
+ // Twitter's t.co shortener is mandatory. All URLS are max-character value set by Twitter.
128
+ $tco = ( wpt_is_ssl( $values['url'] ) ) ? $maxlength['https_length'] : $maxlength['http_length'];
129
  $order = get_option( 'wpt_truncation_order' );
130
  if ( is_array( $order ) ) {
131
  asort( $order );
272
  }
273
 
274
  return $return;
 
275
  }
276
 
277
  function wpt_tags() {
352
  }
353
 
354
  return $array;
355
+ }
356
+
357
+
358
+ /**
359
+ * Parse custom shortcodes
360
+ *
361
+ * @param string $sentence Tweet template
362
+ * @param integer $post_ID Post ID.
363
+ *
364
+ * @return string $sentence with any custom shortcodes replaced with their appropriate content.
365
+ */
366
+ function wpt_custom_shortcodes( $sentence, $post_ID ) {
367
+ $pattern = '/([([\[\]?)([A-Za-z0-9-_])*(\]\]]?)+/';
368
+ $params = array( 0 => "[[", 1 => "]]" );
369
+ preg_match_all( $pattern, $sentence, $matches );
370
+ if ( $matches && is_array( $matches[0] ) ) {
371
+ foreach ( $matches[0] as $value ) {
372
+ $shortcode = "$value";
373
+ $field = str_replace( $params, "", $shortcode );
374
+ $custom = apply_filters( 'wpt_custom_shortcode', strip_tags( get_post_meta( $post_ID, $field, true ) ), $post_ID, $field );
375
+ $sentence = str_replace( $shortcode, $custom, $sentence );
376
+ }
377
+ }
378
+
379
+ return $sentence;
380
+ }
381
+
382
+ /**
383
+ * Parse user meta shortcodes
384
+ *
385
+ * @param string $sentence Tweet template
386
+ * @param integer $auth_ID Post Author ID.
387
+ *
388
+ * @return string $sentence with any custom shortcodes replaced with their appropriate content.
389
+ */
390
+ function wpt_user_meta_shortcodes( $sentence, $auth_ID ) {
391
+ $pattern = '/([({\{\}?)([A-Za-z0-9-_])*(\}\}}?)+/';
392
+ $params = array( 0 => "{{", 1 => "}}" );
393
+ preg_match_all( $pattern, $sentence, $matches );
394
+ if ( $matches && is_array( $matches[0] ) ) {
395
+ foreach ( $matches[0] as $value ) {
396
+ $shortcode = "$value";
397
+ $field = str_replace( $params, "", $shortcode );
398
+ $custom = apply_filters( 'wpt_user_meta_shortcode', strip_tags( get_user_meta( $auth_ID, $field, true ) ), $auth_ID, $field );
399
+ $sentence = str_replace( $shortcode, $custom, $sentence );
400
+ }
401
+ }
402
+
403
+ return $sentence;
404
  }
wpt-widget.php CHANGED
@@ -16,10 +16,14 @@ function wpt_get_user( $twitter_ID = false ) {
16
  $secret = get_option( 'app_consumer_secret' );
17
  $token = get_option( 'oauth_token' );
18
  $token_secret = get_option( 'oauth_token_secret' );
19
- $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
20
- $result = $connection->get( "https://api.twitter.com/1.1/users/show.json?screen_name=$twitter_ID", $options );
 
21
 
22
- return json_decode( $result );
 
 
 
23
  }
24
 
25
  add_shortcode( 'get_tweets', 'wpt_get_twitter_feed' );
@@ -61,6 +65,9 @@ function wpt_twitter_feed( $instance ) {
61
  if ( ! isset( $instance['search'] ) ) {
62
  $twitter_ID = ( isset( $instance['twitter_id'] ) && $instance['twitter_id'] != '' ) ? $instance['twitter_id'] : get_option( 'wtt_twitter_username' );
63
  $user = wpt_get_user( $twitter_ID );
 
 
 
64
  if ( isset( $user->errors ) && $user->errors[0]->message ) {
65
  return __( "Error: ", 'wp-to-twitter' ) . $user->errors[0]->message;
66
  }
@@ -72,8 +79,8 @@ function wpt_twitter_feed( $instance ) {
72
  $follow_url = esc_url( 'https://twitter.com/' . $twitter_ID );
73
  $follow_button = apply_filters( 'wpt_follow_button', "<a href='$follow_url' class='twitter-follow-button $follow_alignment' data-width='30px' data-show-screen-name='false' data-size='large' data-show-count='false' data-lang='en'>Follow @" . esc_html( $twitter_ID ) . "</a>" );
74
  $header .= '<div class="wpt-header">';
75
- $header .= "<p>
76
- $follow_button
77
  <img src='$avatar' alt='' class='wpt-twitter-avatar $img_alignment $verified' />
78
  <span class='wpt-twitter-name'>$name</span><br />
79
  <span class='wpt-twitter-id'><a href='$follow_url'>@" . esc_html( $twitter_ID ) . "</a></span>
@@ -177,6 +184,7 @@ class WPT_Latest_Tweets_Widget extends WP_Widget {
177
  $widget_ops = array(
178
  'classname' => 'wpt-latest-tweets',
179
  'description' => __( 'Display a list of your latest tweets.', 'wp-to-twitter' ),
 
180
  );
181
 
182
  $control_ops = array(
@@ -377,6 +385,7 @@ class WPT_Search_Tweets_Widget extends WP_Widget {
377
  $widget_ops = array(
378
  'classname' => 'wpt-search-tweets',
379
  'description' => __( 'Display a list of tweets returned by a search.', 'wp-to-twitter' ),
 
380
  );
381
 
382
  $control_ops = array(
@@ -483,6 +492,7 @@ class WPT_Search_Tweets_Widget extends WP_Widget {
483
  for="<?php echo $this->get_field_id( 'geocode' ); ?>"><?php _e( 'Geocode (Latitude,Longitude,Radius)', 'wp-to-twitter' ); ?>
484
  :</label>
485
  <input type="text" id="<?php echo $this->get_field_id( 'geocode' ); ?>"
 
486
  name="<?php echo $this->get_field_name( 'geocode' ); ?>"
487
  value="<?php echo esc_attr( $instance['geocode'] ); ?>" size="32"
488
  placeholder="37.781157,-122.398720,2km"/>
@@ -550,24 +560,27 @@ add_action( 'widgets_init', create_function( '', "register_widget('WPT_Search_Tw
550
  */
551
  function wpt_tweet_linkify( $text, $opts, $tweet ) {
552
  if ( $opts['show_images'] == true ) {
553
- $media = $tweet['entities']['media'];
554
- $media_urls = array();
555
- if ( !empty( $media ) ) {
556
- foreach ( $media as $image ) {
557
- $media_urls[] = $image['url'];
558
- // alt attributes are not available on Twitter.
559
- $text .= "<img src='$image[media_url_https]' alt='' class='wpt-twitter-image' />";
 
 
 
560
  }
561
- }
562
- if ( !empty( $media_urls ) ) {
563
- foreach ( $media_urls as $media_url ) {
564
- $text = str_replace( "$media_url", '', $text );
565
  }
566
  }
567
  }
568
  $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#", '\\1<a href="\\2" rel="nofollow">\\2</a>', $text ) : $text;
569
  $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#", '\\1<a href="http://\\2" rel="nofollow">\\2</a>', $text ) : $text;
570
- $text = ( $opts['mentions'] == true ) ? preg_replace( '/@(\w+)/', '<a href="https://www.twitter.com/\\1" rel="nofollow">@\\1</a>', $text ) : $text;
571
  $text = ( $opts['hashtags'] == true ) ? preg_replace( '/#(\w+)/', '<a href="https://twitter.com/search?q=%23\\1" rel="nofollow">#\\1</a>', $text ) : $text;
572
  $urls = $tweet['entities']['urls'];
573
  if ( is_array( $urls ) ) {
16
  $secret = get_option( 'app_consumer_secret' );
17
  $token = get_option( 'oauth_token' );
18
  $token_secret = get_option( 'oauth_token_secret' );
19
+ if ( $key && $secret && $token && $token_secret ) {
20
+ $connection = new wpt_TwitterOAuth( $key, $secret, $token, $token_secret );
21
+ $result = $connection->get( "https://api.twitter.com/1.1/users/show.json?screen_name=$twitter_ID&include_ext_alt_text=true", $options );
22
 
23
+ return json_decode( $result );
24
+ } else {
25
+ return array();
26
+ }
27
  }
28
 
29
  add_shortcode( 'get_tweets', 'wpt_get_twitter_feed' );
65
  if ( ! isset( $instance['search'] ) ) {
66
  $twitter_ID = ( isset( $instance['twitter_id'] ) && $instance['twitter_id'] != '' ) ? $instance['twitter_id'] : get_option( 'wtt_twitter_username' );
67
  $user = wpt_get_user( $twitter_ID );
68
+ if ( empty( $user ) ) {
69
+ return __( 'Error: You are not connected to Twitter.', 'wp-to-twitter' );
70
+ }
71
  if ( isset( $user->errors ) && $user->errors[0]->message ) {
72
  return __( "Error: ", 'wp-to-twitter' ) . $user->errors[0]->message;
73
  }
79
  $follow_url = esc_url( 'https://twitter.com/' . $twitter_ID );
80
  $follow_button = apply_filters( 'wpt_follow_button', "<a href='$follow_url' class='twitter-follow-button $follow_alignment' data-width='30px' data-show-screen-name='false' data-size='large' data-show-count='false' data-lang='en'>Follow @" . esc_html( $twitter_ID ) . "</a>" );
81
  $header .= '<div class="wpt-header">';
82
+ $header .= "<div class='wpt-follow-button'>$follow_button</div>
83
+ <p>
84
  <img src='$avatar' alt='' class='wpt-twitter-avatar $img_alignment $verified' />
85
  <span class='wpt-twitter-name'>$name</span><br />
86
  <span class='wpt-twitter-id'><a href='$follow_url'>@" . esc_html( $twitter_ID ) . "</a></span>
184
  $widget_ops = array(
185
  'classname' => 'wpt-latest-tweets',
186
  'description' => __( 'Display a list of your latest tweets.', 'wp-to-twitter' ),
187
+ 'customize_selective_refresh' => true
188
  );
189
 
190
  $control_ops = array(
385
  $widget_ops = array(
386
  'classname' => 'wpt-search-tweets',
387
  'description' => __( 'Display a list of tweets returned by a search.', 'wp-to-twitter' ),
388
+ 'customize_selective_refresh' => true
389
  );
390
 
391
  $control_ops = array(
492
  for="<?php echo $this->get_field_id( 'geocode' ); ?>"><?php _e( 'Geocode (Latitude,Longitude,Radius)', 'wp-to-twitter' ); ?>
493
  :</label>
494
  <input type="text" id="<?php echo $this->get_field_id( 'geocode' ); ?>"
495
+ class="widefat"
496
  name="<?php echo $this->get_field_name( 'geocode' ); ?>"
497
  value="<?php echo esc_attr( $instance['geocode'] ); ?>" size="32"
498
  placeholder="37.781157,-122.398720,2km"/>
560
  */
561
  function wpt_tweet_linkify( $text, $opts, $tweet ) {
562
  if ( $opts['show_images'] == true ) {
563
+ $media = isset( $tweet['entities']['media'] ) ? $tweet['entities']['media'] : false;
564
+ if ( $media ) {
565
+ $media_urls = array();
566
+ if ( !empty( $media ) ) {
567
+ foreach ( $media as $key => $image ) {
568
+ $media_urls[] = $image['url'];
569
+ // alt attributes are not available on Twitter.
570
+ $alt = isset( $tweet['extended_entities']['media'][$key]['ext_alt_text'] ) ? $tweet['extended_entities']['media'][$key]['ext_alt_text'] : '';
571
+ $text .= "<img src='$image[media_url_https]' alt='$alt' class='wpt-twitter-image' />";
572
+ }
573
  }
574
+ if ( !empty( $media_urls ) ) {
575
+ foreach ( $media_urls as $media_url ) {
576
+ $text = str_replace( "$media_url", '', $text );
577
+ }
578
  }
579
  }
580
  }
581
  $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#", '\\1<a href="\\2" rel="nofollow">\\2</a>', $text ) : $text;
582
  $text = ( $opts['links'] == true ) ? preg_replace( "#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#", '\\1<a href="http://\\2" rel="nofollow">\\2</a>', $text ) : $text;
583
+ $text = ( $opts['mentions'] == true ) ? preg_replace( '/@(\w+)/', '<a href="https://twitter.com/\\1" rel="nofollow">@\\1</a>', $text ) : $text;
584
  $text = ( $opts['hashtags'] == true ) ? preg_replace( '/#(\w+)/', '<a href="https://twitter.com/search?q=%23\\1" rel="nofollow">#\\1</a>', $text ) : $text;
585
  $urls = $tweet['entities']['urls'];
586
  if ( is_array( $urls ) ) {
wpt_twitter_oauth.php CHANGED
@@ -32,6 +32,8 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
32
  private $last_api_call;
33
  /* containe the header */
34
  public $http_header;
 
 
35
 
36
  /**
37
  * Set API URLS
@@ -186,6 +188,18 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
186
  return $response;
187
  }
188
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  /**
190
  * Handles a status update that includes an image.
191
  *
@@ -235,7 +249,17 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
235
  $upload = wp_get_attachment_image_src( $attachment, apply_filters( 'wpt_upload_image_size', $size ) );
236
  $image_url = $upload[0];
237
  $remote = wp_remote_get( $image_url );
238
- $binary = wp_remote_retrieve_body( $remote );
 
 
 
 
 
 
 
 
 
 
239
 
240
  $mime_type = get_post_mime_type( $attachment );
241
  if ( ! $mime_type ) {
@@ -253,7 +277,11 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
253
 
254
  $response = $tmhOAuth->response['response'];
255
  $full = $tmhOAuth->response;
256
- wpt_mail( "Media Posted - Media ID #$args[media]", print_r( $full, 1 ) . "\n" . "\n" . print_r( $upload, 1 ) . "\n" . $image_url );
 
 
 
 
257
 
258
  if ( is_wp_error( $response ) ) {
259
  return '';
@@ -265,7 +293,30 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
265
  $this->http_header = $response;
266
  $response = json_decode( $response );
267
  $media_id = $response->media_id_string;
268
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  return $media_id;
270
  }
271
 
@@ -284,6 +335,7 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
284
  }
285
  $req = WPOAuthRequest::from_consumer_and_token( $this->consumer, $this->token, $method, $url, $args );
286
  $req->sign_request( $this->sha1_method, $this->consumer, $this->token );
 
287
 
288
  $response = false;
289
  $url = null;
@@ -297,14 +349,14 @@ if ( ! class_exists( 'wpt_TwitterOAuth' ) ) {
297
  $url = $req->get_normalized_http_url();
298
  $args = wp_parse_args( $req->to_postdata() );
299
  $response = wp_remote_post( $url, array( 'body' => $args, 'timeout' => 30 ) );
300
- break;
301
  }
302
 
303
  if ( is_wp_error( $response ) ) {
304
  return false;
305
  }
306
-
307
  $this->http_code = $response['response']['code'];
 
308
  $this->last_api_call = $url;
309
  $this->format = 'json';
310
  $this->http_header = $response['headers'];
32
  private $last_api_call;
33
  /* containe the header */
34
  public $http_header;
35
+ /* contains the body */
36
+ public $body;
37
 
38
  /**
39
  * Set API URLS
188
  return $response;
189
  }
190
 
191
+ /**
192
+ * Wrapper for metadata requests
193
+ */
194
+ function meta( $url, $parameters = array() ) {
195
+ $response = $this->WPOAuthRequest( $url, $parameters, 'META' );
196
+ if ( $this->format === 'json' && $this->decode_json ) {
197
+ return json_decode( $response );
198
+ }
199
+
200
+ return $response;
201
+ }
202
+
203
  /**
204
  * Handles a status update that includes an image.
205
  *
249
  $upload = wp_get_attachment_image_src( $attachment, apply_filters( 'wpt_upload_image_size', $size ) );
250
  $image_url = $upload[0];
251
  $remote = wp_remote_get( $image_url );
252
+ if ( is_wp_error( $remote ) ) {
253
+ $transport = 'curl';
254
+ $binary = wp_get_curl( $image_url );
255
+ } else {
256
+ $transport = 'wp_http';
257
+ $binary = wp_remote_retrieve_body( $remote );
258
+ }
259
+ wpt_mail( 'Media fetched binary', print_r( $remote, 1 ) . "\n\n" . print_r( $binary, 1 ) );
260
+ if ( !$binary ) {
261
+ return;
262
+ }
263
 
264
  $mime_type = get_post_mime_type( $attachment );
265
  if ( ! $mime_type ) {
277
 
278
  $response = $tmhOAuth->response['response'];
279
  $full = $tmhOAuth->response;
280
+ wpt_mail( "Media Posted - Media ID #$args[media] ($transport)",
281
+ "Twitter Response" . "\n" . print_r( $full, 1 ) . "\n\n" .
282
+ "Attachment Details" . "\n" . print_r( $upload, 1 ) . "\n\n" .
283
+ "Img Request Response" . "\n" . print_r( $remote, 1 )
284
+ );
285
 
286
  if ( is_wp_error( $response ) ) {
287
  return '';
293
  $this->http_header = $response;
294
  $response = json_decode( $response );
295
  $media_id = $response->media_id_string;
296
+
297
+ /**
298
+ * Eventually, use this to add alt text. Not supported at this time.
299
+ *
300
+ $metadata_api = 'https://upload.twitter.com/1.1/media/metadata/create.json';
301
+ $alt_text = get_post_meta( $args['media'], '_wp_attachment_image_alt', true );
302
+ if ( $alt_text != '' ) {
303
+ $image_alt = json_encode( array(
304
+ 'media_id' => $media_id,
305
+ 'alt_text' => array(
306
+ 'text' => $alt_text
307
+ )
308
+ ) );
309
+ $post_image = $tmhOAuth->request(
310
+ 'POST',
311
+ $metadata_api,
312
+ array( 'body' => $image_alt ),
313
+ true
314
+ );
315
+
316
+ wpt_debug( 'Test of post image alt', print_r( $post_image, 1 ) );
317
+ }
318
+ */
319
+
320
  return $media_id;
321
  }
322
 
335
  }
336
  $req = WPOAuthRequest::from_consumer_and_token( $this->consumer, $this->token, $method, $url, $args );
337
  $req->sign_request( $this->sha1_method, $this->consumer, $this->token );
338
+
339
 
340
  $response = false;
341
  $url = null;
349
  $url = $req->get_normalized_http_url();
350
  $args = wp_parse_args( $req->to_postdata() );
351
  $response = wp_remote_post( $url, array( 'body' => $args, 'timeout' => 30 ) );
352
+ break;
353
  }
354
 
355
  if ( is_wp_error( $response ) ) {
356
  return false;
357
  }
 
358
  $this->http_code = $response['response']['code'];
359
+ $this->body = json_decode( $response['body'] );
360
  $this->last_api_call = $url;
361
  $this->format = 'json';
362
  $this->http_header = $response['headers'];