New User Approve - Version 2.5

Version Description

  • Updated localization - pot file updated, French and Italian po mo updated.
  • Fixed - Approve button color issue.
  • Fixed - Duplicate text message on user registration by invitation code.
  • Fixed - Rest API notice.
  • Improvement - When using invitation code user will not be created if invition code is not given or incorrect invitation code is used.
  • Improvement - When user successfully registers via invitation code the welcome email not sent, instead Approve email is sent and success message appears.
Download this release

Release Info

Developer wpexpertsio
Plugin Icon 128x128 New User Approve
Version 2.5
Comparing to
See all releases

Code changes from version 2.4.1 to 2.5

Files changed (99) hide show
  1. assets/css/nua-admin-style.css +54 -3
  2. freemius/assets/css/admin/account.css +1 -1
  3. freemius/assets/css/admin/add-ons.css +1 -2
  4. freemius/assets/css/admin/affiliation.css +1 -1
  5. freemius/assets/css/admin/clone-resolution.css +1 -0
  6. freemius/assets/css/admin/common.css +1 -2
  7. freemius/assets/css/admin/connect.css +1 -1
  8. freemius/assets/css/admin/debug.css +1 -1
  9. freemius/assets/css/admin/dialog-boxes.css +1 -2
  10. freemius/assets/css/admin/gdpr-optin-notice.css +1 -1
  11. freemius/assets/css/admin/optout.css +1 -0
  12. freemius/assets/css/customizer.css +1 -1
  13. freemius/config.php +5 -5
  14. freemius/includes/class-freemius-abstract.php +4 -63
  15. freemius/includes/class-freemius.php +2226 -1050
  16. freemius/includes/class-fs-admin-notices.php +56 -24
  17. freemius/includes/class-fs-api.php +27 -3
  18. freemius/includes/class-fs-lock.php +110 -0
  19. freemius/includes/class-fs-logger.php +2 -1
  20. freemius/includes/class-fs-plugin-updater.php +9 -7
  21. freemius/includes/class-fs-storage.php +106 -80
  22. freemius/includes/class-fs-user-lock.php +10 -46
  23. freemius/includes/customizer/class-fs-customizer-upsell-control.php +2 -2
  24. freemius/includes/entities/class-fs-affiliate-terms.php +4 -0
  25. freemius/includes/entities/class-fs-site.php +22 -21
  26. freemius/includes/entities/class-fs-user.php +12 -1
  27. freemius/includes/fs-core-functions.php +10 -22
  28. freemius/includes/fs-essential-functions.php +7 -97
  29. freemius/includes/fs-plugin-info-dialog.php +1 -1
  30. freemius/includes/managers/class-fs-admin-notice-manager.php +75 -20
  31. freemius/includes/managers/class-fs-clone-manager.php +1660 -0
  32. freemius/includes/managers/class-fs-key-value-storage.php +10 -0
  33. freemius/includes/managers/class-fs-option-manager.php +35 -80
  34. freemius/includes/managers/class-fs-permission-manager.php +698 -0
  35. freemius/includes/managers/class-fs-plugin-manager.php +18 -5
  36. freemius/includes/sdk/FreemiusBase.php +169 -171
  37. freemius/includes/sdk/FreemiusWordPress.php +5 -5
  38. freemius/includes/supplements/fs-migration-2.5.1.php +31 -0
  39. freemius/languages/freemius-cs_CZ.mo +0 -0
  40. freemius/languages/freemius-da_DK.mo +0 -0
  41. freemius/languages/freemius-de_DE.mo +0 -0
  42. freemius/languages/freemius-en.mo +0 -0
  43. freemius/languages/freemius-es_ES.mo +0 -0
  44. freemius/languages/freemius-fr_FR.mo +0 -0
  45. freemius/languages/freemius-he_IL.mo +0 -0
  46. freemius/languages/freemius-hu_HU.mo +0 -0
  47. freemius/languages/freemius-it_IT.mo +0 -0
  48. freemius/languages/freemius-ja.mo +0 -0
  49. freemius/languages/freemius-nl_NL.mo +0 -0
  50. freemius/languages/freemius-ru_RU.mo +0 -0
  51. freemius/languages/freemius-ta.mo +0 -0
  52. freemius/languages/freemius-zh_CN.mo +0 -0
  53. freemius/languages/freemius.pot +794 -568
  54. freemius/require.php +2 -0
  55. freemius/start.php +6 -2
  56. freemius/templates/account.php +65 -30
  57. freemius/templates/account/billing.php +1 -1
  58. freemius/templates/account/partials/disconnect-button.php +104 -0
  59. freemius/templates/account/partials/site.php +8 -6
  60. freemius/templates/account/payments.php +10 -11
  61. freemius/templates/admin-notice.php +4 -1
  62. freemius/templates/auto-installation.php +1 -1
  63. freemius/templates/clone-resolution-js.php +79 -0
  64. freemius/templates/connect.php +151 -142
  65. freemius/templates/connect/index.php +3 -0
  66. freemius/templates/connect/permission.php +43 -0
  67. freemius/templates/connect/permissions-group.php +72 -0
  68. freemius/templates/contact.php +1 -1
  69. freemius/templates/debug.php +78 -16
  70. freemius/templates/firewall-issues-js.php +1 -2
  71. freemius/templates/forms/affiliation.php +6 -6
  72. freemius/templates/forms/data-debug-mode.php +1 -1
  73. freemius/templates/forms/deactivation/form.php +174 -51
  74. freemius/templates/forms/email-address-update.php +347 -0
  75. freemius/templates/forms/license-activation.php +38 -18
  76. freemius/templates/forms/optout.php +147 -301
  77. freemius/templates/forms/resend-key.php +5 -2
  78. freemius/templates/forms/trial-start.php +1 -1
  79. freemius/templates/forms/user-change.php +1 -1
  80. freemius/templates/gdpr-optin-js.php +1 -1
  81. freemius/templates/js/permissions.php +546 -0
  82. freemius/templates/partials/network-activation.php +1 -1
  83. freemius/templates/plugin-icon.php +3 -1
  84. freemius/templates/plugin-info/features.php +1 -1
  85. freemius/templates/powered-by.php +7 -7
  86. freemius/templates/pricing.php +12 -11
  87. freemius/templates/sticky-admin-notice-js.php +1 -2
  88. freemius/templates/tabs-capture-js.php +1 -1
  89. includes/admin-approve.php +14 -10
  90. includes/invitation-code.php +111 -4
  91. includes/messages.php +18 -0
  92. includes/zapier/includes/rest-api.php +17 -14
  93. localization/new-user-approve-fr_FR.mo +0 -0
  94. localization/new-user-approve-fr_FR.po +473 -218
  95. localization/new-user-approve-it_IT.mo +0 -0
  96. localization/new-user-approve-it_IT.po +450 -207
  97. localization/new-user-approve.pot +371 -127
  98. new-user-approve.php +16 -13
  99. readme.txt +11 -3
assets/css/nua-admin-style.css CHANGED
@@ -68,16 +68,67 @@ body.new-users-approve_page_nua-invitation-code {
68
  float: right;
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  #pw_denied_users .button-primary {
72
  float: none;
73
  }
74
 
75
- #pw_pending_users .button,
76
- #pw_approved_users .button,
77
- #pw_denied_users .button {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  background: #eb5a46;
79
  color: #FFF;
80
  border-color: #f3463a;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  }
82
 
83
  #nua-approve-admin .postbox-header {
68
  float: right;
69
  }
70
 
71
+
72
+ #pw_pending_users table.widefat thead {
73
+
74
+ width:606px;
75
+
76
+ }
77
+
78
+
79
+ #pw_pending_users table.widefat thead th {
80
+
81
+ width:151px;
82
+
83
+ }
84
+
85
+ .users_edit_links {
86
+ display:block;
87
+ margin-top:-33px;
88
+ margin-left:38px;
89
+ }
90
+
91
+
92
  #pw_denied_users .button-primary {
93
  float: none;
94
  }
95
 
96
+ #pw_approved_users .button {
97
+ background: #eb5a46;
98
+ color: #FFF;
99
+ border-color: #f3463a;
100
+ }
101
+
102
+
103
+
104
+
105
+ #pw_pending_users .approve-btn {
106
+
107
+ background: #61bd4f;
108
+ color: #FFF;
109
+ border-color: #73e831;
110
+ }
111
+
112
+ #pw_pending_users .deny-btn {
113
+
114
  background: #eb5a46;
115
  color: #FFF;
116
  border-color: #f3463a;
117
+ margin-left:20px;
118
+ }
119
+
120
+ #pw_pending_users .deny-btn, #pw_pending_users .approve-btn {
121
+
122
+ width:81px;
123
+ text-align:center;
124
+ align-self: center;
125
+ margin-left:20px;
126
+ }
127
+
128
+ #pw_denied_users .button {
129
+ background: #61bd4f;
130
+ color: #FFF;
131
+ border-color: #73e831;
132
  }
133
 
134
  #nua-approve-admin .postbox-header {
freemius/assets/css/admin/account.css CHANGED
@@ -1 +1 @@
1
- label.fs-tag,span.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,span.fs-tag.fs-warn{background:#ffba00}label.fs-tag.fs-info,span.fs-tag.fs-info{background:#00a0d2}label.fs-tag.fs-success,span.fs-tag.fs-success{background:#46b450}label.fs-tag.fs-error,span.fs-tag.fs-error{background:#dc3232}.fs-notice[data-id="license_not_whitelabeled"].success,.fs-notice[data-id="license_whitelabeled"].success{color:inherit;border-left-color:#00a0d2}.fs-notice[data-id="license_not_whitelabeled"].success label.fs-plugin-title,.fs-notice[data-id="license_whitelabeled"].success label.fs-plugin-title{display:none}#fs_account .postbox,#fs_account .widefat{max-width:800px}#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 h3 .dashicons{width:26px;height:26px;font-size:1.3em}#fs_account i.dashicons{font-size:1.2em;height:1.2em;width:1.2em}#fs_account .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}.fs-field-beta_program label{margin-left:7px}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_sites .fs-scrollable-table .fs-table-body{max-height:200px;overflow:auto;border:1px solid #e5e5e5}#fs_sites .fs-scrollable-table .fs-table-body>table.widefat{border:none !important}#fs_sites .fs-scrollable-table .fs-main-column{width:100%}#fs_sites .fs-scrollable-table .fs-site-details td:first-of-type{text-align:right;color:grey;width:1px}#fs_sites .fs-scrollable-table .fs-site-details td:last-of-type{text-align:right}#fs_sites .fs-scrollable-table .fs-install-details table tr td{width:1px;white-space:nowrap}#fs_sites .fs-scrollable-table .fs-install-details table tr td:last-of-type{width:auto}#fs_addons h3{border:none;margin-bottom:0;padding:4px 5px}#fs_addons td{vertical-align:middle}#fs_addons thead{white-space:nowrap}#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}#fs_billing_address{width:100%}#fs_billing_address tr td{width:50%;padding:5px}#fs_billing_address tr:first-of-type td{padding-top:0}#fs_billing_address span{font-weight:bold}#fs_billing_address input,#fs_billing_address select{display:block;width:100%;margin-top:5px}#fs_billing_address input::-moz-placeholder,#fs_billing_address select::-moz-placeholder{color:transparent;opacity:1}#fs_billing_address input:-ms-input-placeholder,#fs_billing_address select:-ms-input-placeholder{color:transparent}#fs_billing_address input::-webkit-input-placeholder,#fs_billing_address select::-webkit-input-placeholder{color:transparent}#fs_billing_address input.fs-read-mode,#fs_billing_address select.fs-read-mode{border-color:transparent;color:#777;border-bottom:1px dashed #ccc;padding-left:0;background:none}#fs_billing_address.fs-read-mode td span{display:none}#fs_billing_address.fs-read-mode input,#fs_billing_address.fs-read-mode select{border-color:transparent;color:#777;border-bottom:1px dashed #ccc;padding-left:0;background:none}#fs_billing_address.fs-read-mode input::-moz-placeholder,#fs_billing_address.fs-read-mode select::-moz-placeholder{color:#ccc;opacity:1}#fs_billing_address.fs-read-mode input:-ms-input-placeholder,#fs_billing_address.fs-read-mode select:-ms-input-placeholder{color:#ccc}#fs_billing_address.fs-read-mode input::-webkit-input-placeholder,#fs_billing_address.fs-read-mode select::-webkit-input-placeholder{color:#ccc}#fs_billing_address button{display:block;width:100%}
1
+ label.fs-tag,span.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,span.fs-tag.fs-warn{background:#ffba00}label.fs-tag.fs-info,span.fs-tag.fs-info{background:#00a0d2}label.fs-tag.fs-success,span.fs-tag.fs-success{background:#46b450}label.fs-tag.fs-error,span.fs-tag.fs-error{background:#dc3232}.fs-notice[data-id=license_not_whitelabeled].success,.fs-notice[data-id=license_whitelabeled].success{color:inherit;border-left-color:#00a0d2}.fs-notice[data-id=license_not_whitelabeled].success label.fs-plugin-title,.fs-notice[data-id=license_whitelabeled].success label.fs-plugin-title{display:none}#fs_account .postbox,#fs_account .widefat{max-width:800px}#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 h3 .dashicons{width:26px;height:26px;font-size:1.3em}#fs_account i.dashicons{font-size:1.2em;height:1.2em;width:1.2em}#fs_account .dashicons{vertical-align:middle}#fs_account .fs-header-actions{position:absolute;top:17px;right:15px;font-size:.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}.fs-field-beta_program label{margin-left:7px}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_sites .fs-scrollable-table .fs-table-body{max-height:200px;overflow:auto;border:1px solid #e5e5e5}#fs_sites .fs-scrollable-table .fs-table-body>table.widefat{border:none !important}#fs_sites .fs-scrollable-table .fs-main-column{width:100%}#fs_sites .fs-scrollable-table .fs-site-details td:first-of-type{text-align:right;color:gray;width:1px}#fs_sites .fs-scrollable-table .fs-site-details td:last-of-type{text-align:right}#fs_sites .fs-scrollable-table .fs-install-details table tr td{width:1px;white-space:nowrap}#fs_sites .fs-scrollable-table .fs-install-details table tr td:last-of-type{width:auto}#fs_addons h3{border:none;margin-bottom:0;padding:4px 5px}#fs_addons td{vertical-align:middle}#fs_addons thead{white-space:nowrap}#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}#fs_billing_address{width:100%}#fs_billing_address tr td{width:50%;padding:5px}#fs_billing_address tr:first-of-type td{padding-top:0}#fs_billing_address span{font-weight:bold}#fs_billing_address input,#fs_billing_address select{display:block;width:100%;margin-top:5px}#fs_billing_address input::-moz-placeholder,#fs_billing_address select::-moz-placeholder{color:transparent;opacity:1}#fs_billing_address input:-ms-input-placeholder,#fs_billing_address select:-ms-input-placeholder{color:transparent}#fs_billing_address input::-webkit-input-placeholder,#fs_billing_address select::-webkit-input-placeholder{color:transparent}#fs_billing_address input.fs-read-mode,#fs_billing_address select.fs-read-mode{border-color:transparent;color:#777;border-bottom:1px dashed #ccc;padding-left:0;background:none}#fs_billing_address.fs-read-mode td span{display:none}#fs_billing_address.fs-read-mode input,#fs_billing_address.fs-read-mode select{border-color:transparent;color:#777;border-bottom:1px dashed #ccc;padding-left:0;background:none}#fs_billing_address.fs-read-mode input::-moz-placeholder,#fs_billing_address.fs-read-mode select::-moz-placeholder{color:#ccc;opacity:1}#fs_billing_address.fs-read-mode input:-ms-input-placeholder,#fs_billing_address.fs-read-mode select:-ms-input-placeholder{color:#ccc}#fs_billing_address.fs-read-mode input::-webkit-input-placeholder,#fs_billing_address.fs-read-mode select::-webkit-input-placeholder{color:#ccc}#fs_billing_address button{display:block;width:100%}@media screen and (max-width: 639px){#fs_account .fs-header-actions{position:static;padding:0 15px 12px 15px;margin:0 0 12px 0}#fs_account .fs-header-actions li{float:none;display:inline-block}#fs_account #fs_account_details{display:block}#fs_account #fs_account_details tbody,#fs_account #fs_account_details tr,#fs_account #fs_account_details td,#fs_account #fs_account_details th{display:block}#fs_account #fs_account_details tr td:first-child{text-align:left}#fs_account #fs_account_details tr td:nth-child(2){padding:0 12px}#fs_account #fs_account_details tr td:nth-child(2) code{margin:0;padding:0}#fs_account #fs_account_details tr td:nth-child(2) label{margin-left:0}#fs_account #fs_account_details tr td:nth-child(3){text-align:left}#fs_account #fs_account_details tr.fs-field-plan td:nth-child(2) .button-group{float:none;margin:12px 0}}
freemius/assets/css/admin/add-ons.css CHANGED
@@ -1,2 +1 @@
1
- .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:white;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3)}#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>ul>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-card-banner .fs-badge.fs-installed-addon-badge{font-size:1.02em;line-height:1.3em}#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,#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button-group{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:821px !important}#plugin-information .fyi{width:266px !important}#plugin-information #section-holder{margin-right:299px}#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 iframe{max-width:100%}#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}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button,#plugin-information .fs-dropdown .button-group .button{position:relative;width:auto;top:0;right:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button:focus,#plugin-information .fs-dropdown .button-group .button:focus{z-index:10}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .fs-dropdown-arrow,#plugin-information .fs-dropdown .button-group .fs-dropdown-arrow{border-top:6px solid white;border-right:4px solid transparent;border-left:4px solid transparent;top:12px;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button){border-bottom-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button{border-bottom-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button){border-top-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active.up .fs-dropdown-arrow-button{border-top-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list,#plugin-information .fs-dropdown .fs-dropdown-list{position:absolute;right:-1px;top:100%;margin-left:auto;padding:3px 0;border:1px solid #bfbfbf;background-color:#fff;z-index:1;width:230px;text-align:left;-moz-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);-webkit-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li,#plugin-information .fs-dropdown .fs-dropdown-list li{margin:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li a,#plugin-information .fs-dropdown .fs-dropdown-list li a{display:block;padding:5px 10px;text-decoration:none;text-shadow:none}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover,#plugin-information .fs-dropdown .fs-dropdown-list li:hover{background-color:#0074a3;color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover a,#plugin-information .fs-dropdown .fs-dropdown-list li:hover a{color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown:not(.up) .fs-dropdown-list,#plugin-information .fs-dropdown:not(.up) .fs-dropdown-list{-moz-border-radius:3px 0 3px 3px;-webkit-border-radius:3px 0 3px 3px;border-radius:3px 0 3px 3px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.up .fs-dropdown-list,#plugin-information .fs-dropdown.up .fs-dropdown-list{-moz-border-radius:3px 3px 0 3px;-webkit-border-radius:3px 3px 0 3px;border-radius:3px 3px 0 3px}#plugin-information .fs-dropdown .button-group{width:100%}#plugin-information .fs-dropdown .button-group .button{float:none;font-size:14px;font-weight:normal;text-transform:none}#plugin-information .fs-dropdown .fs-dropdown-list{margin-top:1px}#plugin-information .fs-dropdown.up .fs-dropdown-list{top:auto;bottom:100%;margin-bottom:2px}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group{text-align:center;display:table}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button{display:table-cell}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button:not(.fs-dropdown-arrow-button){left:1px;width:100%}#plugin-information-footer>.button,#plugin-information-footer .fs-dropdown{position:relative;top:3px}#plugin-information-footer>.button.left,#plugin-information-footer .fs-dropdown.left{float:left}#plugin-information-footer>.right,#plugin-information-footer .fs-dropdown{float:right}@media screen and (max-width: 961px){#fs_addons .fs-cards-list .fs-card{height:265px}}
1
+ .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:#fff;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.3);box-shadow:0 2px 1px -1px rgba(0,0,0,.3)}#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,.15s;-o-transition:all,.15s;-ms-transition:all,.15s;-webkit-transition:all,.15s;transition:all,.15s;left:0;right:0;top:0;position:absolute}#fs_addons .fs-cards-list .fs-card .fs-inner>ul>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,.15s;-o-transition:all,.15s;-ms-transition:all,.15s;-webkit-transition:all,.15s;transition:all,.15s}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner .fs-badge.fs-installed-addon-badge{font-size:1.02em;line-height:1.3em}#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:.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:#adff2f;display:block;padding:2px 10px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,.3);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.3);box-shadow:1px 1px 1px rgba(0,0,0,.3);text-transform:uppercase;font-size:.9em;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button,#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button-group{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}}#TB_window,#TB_window iframe{width:821px !important}#plugin-information .fyi{width:266px !important}#plugin-information #section-holder{margin-right:299px}#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 iframe{max-width:100%}#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,.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(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:.9em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab label{text-transform:uppercase;color:green;background:#adff2f;position:absolute;left:-1px;right:-1px;bottom:100%;border:1px solid #006400;padding:2px;text-align:center;font-size:.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:#adff2f}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms{font-size:.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}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button,#plugin-information .fs-dropdown .button-group .button{position:relative;width:auto;top:0;right:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button:focus,#plugin-information .fs-dropdown .button-group .button:focus{z-index:10}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .fs-dropdown-arrow,#plugin-information .fs-dropdown .button-group .fs-dropdown-arrow{border-top:6px solid #fff;border-right:4px solid transparent;border-left:4px solid transparent;top:12px;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button){border-bottom-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button{border-bottom-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button){border-top-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active.up .fs-dropdown-arrow-button{border-top-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list,#plugin-information .fs-dropdown .fs-dropdown-list{position:absolute;right:-1px;top:100%;margin-left:auto;padding:3px 0;border:1px solid #bfbfbf;background-color:#fff;z-index:1;width:230px;text-align:left;-moz-box-shadow:0px 2px 4px -1px rgba(0,0,0,.2),0px 4px 5px 0px rgba(0,0,0,.14),0px 1px 10px 0px rgba(0,0,0,.12);-webkit-box-shadow:0px 2px 4px -1px rgba(0,0,0,.2),0px 4px 5px 0px rgba(0,0,0,.14),0px 1px 10px 0px rgba(0,0,0,.12);box-shadow:0px 2px 4px -1px rgba(0,0,0,.2),0px 4px 5px 0px rgba(0,0,0,.14),0px 1px 10px 0px rgba(0,0,0,.12)}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li,#plugin-information .fs-dropdown .fs-dropdown-list li{margin:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li a,#plugin-information .fs-dropdown .fs-dropdown-list li a{display:block;padding:5px 10px;text-decoration:none;text-shadow:none}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover,#plugin-information .fs-dropdown .fs-dropdown-list li:hover{background-color:#0074a3;color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover a,#plugin-information .fs-dropdown .fs-dropdown-list li:hover a{color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown:not(.up) .fs-dropdown-list,#plugin-information .fs-dropdown:not(.up) .fs-dropdown-list{-moz-border-radius:3px 0 3px 3px;-webkit-border-radius:3px 0 3px 3px;border-radius:3px 0 3px 3px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.up .fs-dropdown-list,#plugin-information .fs-dropdown.up .fs-dropdown-list{-moz-border-radius:3px 3px 0 3px;-webkit-border-radius:3px 3px 0 3px;border-radius:3px 3px 0 3px}#plugin-information .fs-dropdown .button-group{width:100%}#plugin-information .fs-dropdown .button-group .button{float:none;font-size:14px;font-weight:normal;text-transform:none}#plugin-information .fs-dropdown .fs-dropdown-list{margin-top:1px}#plugin-information .fs-dropdown.up .fs-dropdown-list{top:auto;bottom:100%;margin-bottom:2px}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group{text-align:center;display:table}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button{display:table-cell}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button:not(.fs-dropdown-arrow-button){left:1px;width:100%}#plugin-information-footer>.button,#plugin-information-footer .fs-dropdown{position:relative;top:3px}#plugin-information-footer>.button.left,#plugin-information-footer .fs-dropdown.left{float:left}#plugin-information-footer>.right,#plugin-information-footer .fs-dropdown{float:right}@media screen and (max-width: 961px){#fs_addons .fs-cards-list .fs-card{height:265px}}
 
freemius/assets/css/admin/affiliation.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";#fs_affiliation_content_wrapper #messages{margin-top:25px}#fs_affiliation_content_wrapper h3{font-size:24px;padding:0;margin-left:0}#fs_affiliation_content_wrapper ul li{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;list-style-type:none}#fs_affiliation_content_wrapper ul li:before{content:'';margin-right:10px;font-weight:bold}#fs_affiliation_content_wrapper p:not(.description),#fs_affiliation_content_wrapper li,#fs_affiliation_content_wrapper label{font-size:16px !important;line-height:26px !important}#fs_affiliation_content_wrapper .button{margin-top:20px;margin-bottom:7px;line-height:35px;height:40px;font-size:16px}#fs_affiliation_content_wrapper .button#cancel_button{margin-right:5px}#fs_affiliation_content_wrapper form .input-container{margin-bottom:15px}#fs_affiliation_content_wrapper form .input-container .input-label{font-weight:bold;display:block;width:100%}#fs_affiliation_content_wrapper form .input-container.input-container-text label,#fs_affiliation_content_wrapper form .input-container.input-container-text input,#fs_affiliation_content_wrapper form .input-container.input-container-text textarea{display:block}#fs_affiliation_content_wrapper form .input-container #add_domain,#fs_affiliation_content_wrapper form .input-container .remove-domain{text-decoration:none;display:inline-block;margin-top:3px}#fs_affiliation_content_wrapper form .input-container #add_domain:focus,#fs_affiliation_content_wrapper form .input-container .remove-domain:focus{box-shadow:none}#fs_affiliation_content_wrapper form .input-container #add_domain.disabled,#fs_affiliation_content_wrapper form .input-container .remove-domain.disabled{color:#aaa;cursor:default}#fs_affiliation_content_wrapper form #extra_domains_container .description{margin-top:0;position:relative;top:-4px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container{margin-bottom:15px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container .domain{display:inline-block;margin-right:5px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container .domain:last-of-type{margin-bottom:0}
1
+ #fs_affiliation_content_wrapper #messages{margin-top:25px}#fs_affiliation_content_wrapper h3{font-size:24px;padding:0;margin-left:0}#fs_affiliation_content_wrapper ul li{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;list-style-type:none}#fs_affiliation_content_wrapper ul li:before{content:"";margin-right:10px;font-weight:bold}#fs_affiliation_content_wrapper p:not(.description),#fs_affiliation_content_wrapper li,#fs_affiliation_content_wrapper label{font-size:16px !important;line-height:26px !important}#fs_affiliation_content_wrapper .button{margin-top:20px;margin-bottom:7px;line-height:35px;height:40px;font-size:16px}#fs_affiliation_content_wrapper .button#cancel_button{margin-right:5px}#fs_affiliation_content_wrapper form .input-container{margin-bottom:15px}#fs_affiliation_content_wrapper form .input-container .input-label{font-weight:bold;display:block;width:100%}#fs_affiliation_content_wrapper form .input-container.input-container-text label,#fs_affiliation_content_wrapper form .input-container.input-container-text input,#fs_affiliation_content_wrapper form .input-container.input-container-text textarea{display:block}#fs_affiliation_content_wrapper form .input-container #add_domain,#fs_affiliation_content_wrapper form .input-container .remove-domain{text-decoration:none;display:inline-block;margin-top:3px}#fs_affiliation_content_wrapper form .input-container #add_domain:focus,#fs_affiliation_content_wrapper form .input-container .remove-domain:focus{box-shadow:none}#fs_affiliation_content_wrapper form .input-container #add_domain.disabled,#fs_affiliation_content_wrapper form .input-container .remove-domain.disabled{color:#aaa;cursor:default}#fs_affiliation_content_wrapper form #extra_domains_container .description{margin-top:0;position:relative;top:-4px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container{margin-bottom:15px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container .domain{display:inline-block;margin-right:5px}#fs_affiliation_content_wrapper form #extra_domains_container .extra-domain-input-container .domain:last-of-type{margin-bottom:0}
freemius/assets/css/admin/clone-resolution.css ADDED
@@ -0,0 +1 @@
 
1
+ .fs-notice[data-id^=clone_resolution_options_notice]{padding:0;color:inherit !important}.fs-notice[data-id^=clone_resolution_options_notice] .fs-notice-body{padding:0;margin-bottom:0}.fs-notice[data-id^=clone_resolution_options_notice] .fs-notice-header{padding:5px 10px}.fs-notice[data-id^=clone_resolution_options_notice] ol{margin-top:0;margin-bottom:0}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-options-container{display:flex;flex-direction:row;padding:0 10px 10px}@media(max-width: 750px){.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-options-container{flex-direction:column}}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-option{border:1px solid #ccc;padding:10px 10px 15px 10px;flex:auto;margin:5px}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-option:first-child{margin-left:0}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-option:last-child{margin-right:0}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-resolution-option strong{font-size:1.2em;padding:2px;line-height:1.5em}.fs-notice[data-id^=clone_resolution_options_notice] a{text-decoration:none}.fs-notice[data-id^=clone_resolution_options_notice] .button{margin-right:10px}.rtl .fs-notice[data-id^=clone_resolution_options_notice] .button{margin-right:0;margin-left:10px}.fs-notice[data-id^=clone_resolution_options_notice] .fs-clone-documentation-container{padding:0 10px 15px}.fs-notice[data-id=temporary_duplicate_notice] #fs_clone_resolution_error_message{border:1px solid #d3135a;background:#fee;color:#d3135a;padding:10px}.fs-notice[data-id=temporary_duplicate_notice] ol{margin-top:0}
freemius/assets/css/admin/common.css CHANGED
@@ -1,2 +1 @@
1
- .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:white;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3)}.theme-browser .theme .fs-premium-theme-badge-container{position:absolute;right:0;top:0}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge{position:relative;top:0;margin-top:10px;text-align:center}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge.fs-premium-theme-badge{font-size:1.1em}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge.fs-beta-theme-badge{background:#00a0d2}.fs-switch{position:relative;display:inline-block;color:#ccc;text-shadow:0 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);background:#ececec;box-shadow:0 0 4px rgba(0,0,0,0.1),inset 0 1px 3px 0 rgba(0,0,0,0.1);cursor:pointer}.fs-switch span{display:inline-block;width:35px;text-transform:uppercase}.fs-switch .fs-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-color:#fff;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #ececec), color-stop(1, #fff));background-image:-webkit-linear-gradient(top, #ececec, #fff);background-image:-moz-linear-gradient(top, #ececec, #fff);background-image:-ms-linear-gradient(top, #ececec, #fff);background-image:-o-linear-gradient(top, #ececec, #fff);background-image:linear-gradient(top, bottom, #ececec, #fff);box-shadow:inset 0 1px 0 0 rgba(255,255,255,0.5);z-index:999;-moz-transition:0.4s cubic-bezier(0.54, 1.6, 0.5, 1);-o-transition:0.4s cubic-bezier(0.54, 1.6, 0.5, 1);-ms-transition:0.4s cubic-bezier(0.54, 1.6, 0.5, 1);-webkit-transition:0.4s cubic-bezier(0.54, 1.6, 0.5, 1);transition:0.4s cubic-bezier(0.54, 1.6, 0.5, 1)}.fs-switch.fs-off .fs-toggle{left:2%}.fs-switch.fs-on .fs-toggle{left:54%}.fs-switch.fs-round{top:8px;padding:4px 25px;-moz-border-radius:24px;-webkit-border-radius:24px;border-radius:24px}.fs-switch.fs-round .fs-toggle{top:0;width:24px;height:24px;-moz-border-radius:24px;-webkit-border-radius:24px;border-radius:24px}.fs-switch.fs-round.fs-off .fs-toggle{left:-1px}.fs-switch.fs-round.fs-on{background:#0085ba}.fs-switch.fs-round.fs-on .fs-toggle{left:25px}.fs-switch.fs-small.fs-round{padding:1px 19px}.fs-switch.fs-small.fs-round .fs-toggle{top:0;width:18px;height:18px;-moz-border-radius:18px;-webkit-border-radius:18px;border-radius:18px}.fs-switch.fs-small.fs-round.fs-on .fs-toggle{left:19px}.fs-switch-feedback{margin-left:10px}.fs-switch-feedback.success{color:#71ae00}.rtl .fs-switch-feedback{margin-left:0;margin-right:10px}#fs_frame{line-height:0;font-size:0}.fs-full-size-wrapper{margin:40px 0 -65px -20px}@media (max-width: 600px){.fs-full-size-wrapper{margin:0 0 -65px -10px}}
2
- .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}div.fs-notice.updated,div.fs-notice.success,div.fs-notice.promotion{display:block !important}.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;-moz-box-shadow:0 2px 2px rgba(6,113,6,0.3);-webkit-box-shadow:0 2px 2px rgba(6,113,6,0.3);box-shadow:0 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)}.fs-secure-notice a.fs-security-proof{color:green;text-decoration:none}@media screen and (max-width: 960px){.fs-secure-notice{left:36px}}@media screen and (max-width: 600px){.fs-secure-notice{display:none}}@media screen and (max-width: 1250px){#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'}.fs-submenu-item.pricing.upgrade-mode{color:greenyellow}.fs-submenu-item.pricing.trial-mode{color:#83e2ff}#adminmenu .update-plugins.fs-trial{background-color:#00b9eb}.fs-ajax-spinner{border:0;width:20px;height:20px;margin-right:5px;vertical-align:sub;display:inline-block;background:url("/wp-admin/images/wpspin_light-2x.gif");background-size:contain;margin-bottom:-2px}.wrap.fs-section h2{text-align:left}.plugins p.fs-upgrade-notice{border:0;background-color:#d54e21;padding:10px;color:#f9f9f9;margin-top:10px}
1
+ .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:#fff;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.3);box-shadow:0 2px 1px -1px rgba(0,0,0,.3)}.theme-browser .theme .fs-premium-theme-badge-container{position:absolute;right:0;top:0}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge{position:relative;top:0;margin-top:10px;text-align:center}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge.fs-premium-theme-badge{font-size:1.1em}.theme-browser .theme .fs-premium-theme-badge-container .fs-badge.fs-beta-theme-badge{background:#00a0d2}.fs-switch{position:relative;display:inline-block;color:#ccc;text-shadow:0 1px 1px rgba(255,255,255,.8);height:18px;padding:6px 6px 5px 6px;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);background:#ececec;box-shadow:0 0 4px rgba(0,0,0,.1),inset 0 1px 3px 0 rgba(0,0,0,.1);cursor:pointer}.fs-switch span{display:inline-block;width:35px;text-transform:uppercase}.fs-switch .fs-toggle{position:absolute;top:1px;width:37px;height:25px;border:1px solid #ccc;border:1px solid rgba(0,0,0,.3);border-radius:4px;background:#fff;background-color:#fff;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #ececec), color-stop(1, #fff));background-image:-webkit-linear-gradient(top, #ececec, #fff);background-image:-moz-linear-gradient(top, #ececec, #fff);background-image:-ms-linear-gradient(top, #ececec, #fff);background-image:-o-linear-gradient(top, #ececec, #fff);background-image:linear-gradient(top, bottom, #ececec, #fff);box-shadow:inset 0 1px 0 0 rgba(255,255,255,.5);z-index:999;-moz-transition:.4s cubic-bezier(0.54, 1.6, 0.5, 1);-o-transition:.4s cubic-bezier(0.54, 1.6, 0.5, 1);-ms-transition:.4s cubic-bezier(0.54, 1.6, 0.5, 1);-webkit-transition:.4s cubic-bezier(0.54, 1.6, 0.5, 1);transition:.4s cubic-bezier(0.54, 1.6, 0.5, 1)}.fs-switch.fs-off .fs-toggle{left:2%}.fs-switch.fs-on .fs-toggle{left:54%}.fs-switch.fs-round{top:8px;padding:4px 25px;-moz-border-radius:24px;-webkit-border-radius:24px;border-radius:24px}.fs-switch.fs-round .fs-toggle{top:0;width:24px;height:24px;-moz-border-radius:24px;-webkit-border-radius:24px;border-radius:24px}.fs-switch.fs-round.fs-off .fs-toggle{left:-1px}.fs-switch.fs-round.fs-on{background:#0085ba}.fs-switch.fs-round.fs-on .fs-toggle{left:25px}.fs-switch.fs-small.fs-round{padding:1px 19px}.fs-switch.fs-small.fs-round .fs-toggle{top:0;width:18px;height:18px;-moz-border-radius:18px;-webkit-border-radius:18px;border-radius:18px}.fs-switch.fs-small.fs-round.fs-on .fs-toggle{left:19px}body.fs-loading,body.fs-loading *{cursor:wait !important}#fs_frame{line-height:0;font-size:0}.fs-full-size-wrapper{margin:40px 0 -65px -20px}@media(max-width: 600px){.fs-full-size-wrapper{margin:0 0 -65px -10px}}.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,.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}div.fs-notice.updated,div.fs-notice.success,div.fs-notice.promotion{display:block !important}.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;-moz-box-shadow:0 2px 2px rgba(6,113,6,.3);-webkit-box-shadow:0 2px 2px rgba(6,113,6,.3);box-shadow:0 2px 2px rgba(6,113,6,.3);opacity:.95;filter:alpha(opacity=95)}.fs-secure-notice:hover{opacity:1;filter:alpha(opacity=100)}.fs-secure-notice a.fs-security-proof{color:green;text-decoration:none}@media screen and (max-width: 960px){.fs-secure-notice{left:36px}}@media screen and (max-width: 600px){.fs-secure-notice{display:none}}@media screen and (max-width: 1250px){#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:"↳";padding:0 5px}.rtl span.fs-submenu-item.fs-sub:before{content:"↲"}.fs-submenu-item.pricing.upgrade-mode{color:#adff2f}.fs-submenu-item.pricing.trial-mode{color:#83e2ff}#adminmenu .update-plugins.fs-trial{background-color:#00b9eb}.fs-ajax-spinner{border:0;width:20px;height:20px;margin-right:5px;vertical-align:sub;display:inline-block;background:url("/wp-admin/images/wpspin_light-2x.gif");background-size:contain;margin-bottom:-2px}.wrap.fs-section h2{text-align:left}.plugins p.fs-upgrade-notice{border:0;background-color:#d54e21;padding:10px;color:#f9f9f9;margin-top:10px}
 
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 .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.require-license-key .fs-sites-list-container td{cursor:pointer}#fs_connect #delegate_to_site_admins{margin-right:15px;float:right;height:26px;vertical-align:middle;line-height:37px;font-weight:bold;border-bottom:1px dashed;text-decoration:none}#fs_connect #delegate_to_site_admins.rtl{margin-left:15px;margin-right:0}#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 .fs-switch{float:right}#fs_connect .fs-permissions ul li .fs-permission-description{margin-left:55px}#fs_connect .fs-permissions ul li .fs-permission-description span{font-weight:bold;text-transform:uppercase;color:#23282d}#fs_connect .fs-permissions ul li .fs-permission-description p{margin:2px 0 0 0}#fs_connect .fs-permissions.fs-open{background:#fff}#fs_connect .fs-permissions.fs-open ul{overflow:initial;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}.fs-multisite-options-container{margin-top:10px;border:1px solid #ccc;padding:5px}.fs-multisite-options-container a{text-decoration:none}.fs-multisite-options-container a:focus{box-shadow:none}.fs-multisite-options-container a.selected{font-weight:bold}.fs-multisite-options-container.fs-apply-on-all-sites{border:0 none;padding:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options{border-spacing:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options td:not(:first-child){display:none}.fs-multisite-options-container .fs-sites-list-container{display:none;overflow:auto}.fs-multisite-options-container .fs-sites-list-container table td{border-top:1px solid #ccc;padding:4px 2px}.fs-tooltip-trigger{position:relative}.fs-tooltip-trigger:not(a){cursor:help}.fs-tooltip-trigger .fs-tooltip{opacity:0;visibility:hidden;-moz-transition:opacity 0.3s ease-in-out;-o-transition:opacity 0.3s ease-in-out;-ms-transition:opacity 0.3s ease-in-out;-webkit-transition:opacity 0.3s ease-in-out;transition:opacity 0.3s ease-in-out;position:absolute;background:rgba(0,0,0,0.8);color:#fff !important;font-family:'arial', serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:-17px;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-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);line-height:1.3em;font-weight:bold;text-align:left;text-transform:none !important}.rtl .fs-tooltip-trigger .fs-tooltip{text-align:right;left:auto;right:-17px}.fs-tooltip-trigger .fs-tooltip::after{content:' ';display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:rgba(0,0,0,0.8) transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl .fs-tooltip-trigger .fs-tooltip::after{right:21px;left:auto}.fs-tooltip-trigger:hover .fs-tooltip{visibility:visible;opacity:1}#fs_marketing_optin{display:none;margin-top:10px;border:1px solid #ccc;padding:10px;line-height:1.5em}#fs_marketing_optin .fs-message{display:block;margin-bottom:5px;font-size:1.05em;font-weight:600}#fs_marketing_optin.error{border:1px solid #d3135a;background:#fee}#fs_marketing_optin.error .fs-message{color:#d3135a}#fs_marketing_optin .fs-input-container{margin-top:5px}#fs_marketing_optin .fs-input-container label{margin-top:5px;display:block}#fs_marketing_optin .fs-input-container label input{float:left;margin:1px 0 0 0}#fs_marketing_optin .fs-input-container label:first-child{display:block;margin-bottom:2px}#fs_marketing_optin .fs-input-label{display:block;margin-left:20px}#fs_marketing_optin .fs-input-label .underlined{text-decoration:underline}.rtl #fs_marketing_optin .fs-input-container label input{float:right}.rtl #fs_marketing_optin .fs-input-label{margin-left:0;margin-right:20px}.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 .fs-permission-description{margin-right:55px;margin-left:0}.rtl #fs_connect .fs-permissions ul li .fs-switch{float:left}.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}#fs_theme_connect_wrapper{position:fixed;top:0;height:100%;width:100%;z-index:99990;background:rgba(0,0,0,0.75);text-align:center;overflow-y:auto}#fs_theme_connect_wrapper:before{content:"";display:inline-block;vertical-align:middle;height:100%}#fs_theme_connect_wrapper>button.close{color:white;cursor:pointer;height:40px;width:40px;position:absolute;right:0;border:0;background-color:transparent;top:32px}#fs_theme_connect_wrapper #fs_connect{top:0;text-align:left;display:inline-block;vertical-align:middle;margin-top:52px;margin-bottom:20px}#fs_theme_connect_wrapper #fs_connect .fs-terms{background:rgba(140,140,140,0.64)}#fs_theme_connect_wrapper #fs_connect .fs-terms,#fs_theme_connect_wrapper #fs_connect .fs-terms a{color:#c5c5c5}.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}#license_issues_link{display:block;text-align:center;font-size:0.9em;margin-top:10px}
1
+ .fs-tooltip-trigger{position:relative}.fs-tooltip-trigger:not(a){cursor:help}.fs-tooltip-trigger .dashicons{float:none !important}.fs-tooltip-trigger .fs-tooltip{opacity:0;visibility:hidden;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-ms-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;position:absolute;background:rgba(0,0,0,.8);color:#fff !important;font-family:"arial",serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:-17px;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(0,0,0,.2);line-height:1.3em;font-weight:bold;text-align:left;text-transform:none !important}.rtl .fs-tooltip-trigger .fs-tooltip{text-align:right;left:auto;right:-17px}.fs-tooltip-trigger .fs-tooltip::after{content:" ";display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:rgba(0,0,0,.8) transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl .fs-tooltip-trigger .fs-tooltip::after{right:21px;left:auto}.fs-tooltip-trigger:hover .fs-tooltip{visibility:visible;opacity:1}#fs_connect{width:484px;margin:60px auto 20px auto}#fs_connect a{color:inherit}#fs_connect a:not(.button){text-decoration:underline}#fs_connect .fs-box-container{box-shadow:0 1px 2px rgba(0,0,0,.3);border-radius:3px;overflow:hidden;padding-top:40px;background:#f0f0f1}@media screen and (max-width: 483px){#fs_connect{width:auto;margin:30px 0 0 -10px}#fs_connect .fs-box-container{-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}}#fs_connect .fs-content{background:#fff;padding:30px 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,.1);-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);text-align:center;padding:5px;margin-bottom:10px}#fs_connect .fs-content h2{line-height:1.5em}#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.require-license-key .fs-content{padding-bottom:10px}#fs_connect.require-license-key .fs-actions{border-top:none}#fs_connect.require-license-key .fs-sites-list-container td{cursor:pointer}#fs_connect #delegate_to_site_admins{margin-right:15px;float:right;height:26px;vertical-align:middle;line-height:37px;font-weight:bold;border-bottom:1px dashed;text-decoration:none}#fs_connect #delegate_to_site_admins.rtl{margin-left:15px;margin-right:0}#fs_connect .fs-actions{padding:10px 20px;background:#fff;border-width:1px 0;border-style:solid;border-color:#f1f1f1}#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:" ➜"}#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:#fff;-moz-transition:background .5s ease;-o-transition:background .5s ease;-ms-transition:background .5s ease;-webkit-transition:background .5s ease;transition:background .5s ease}#fs_connect .fs-permissions .fs-license-sync-disclaimer{text-align:center;margin-top:0}#fs_connect .fs-permissions>.fs-trigger{font-size:.9em;text-decoration:none;text-align:center;display:block}#fs_connect .fs-permissions>.fs-trigger .fs-arrow::after{content:"→";width:20px;display:inline-block}#fs_connect .fs-permissions.fs-open>.fs-trigger .fs-arrow::after{content:"↓" !important}#fs_connect .fs-permissions ul li{padding-left:0;padding-right:0}@media screen and (max-width: 483px){#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:inherit;text-decoration:underline}#fs_connect .fs-header{padding:0;line-height:0;height:0;position:relative}#fs_connect .fs-header .fs-site-icon,#fs_connect .fs-header .fs-connect-logo{position:absolute;top:-8px;border-radius:50%}#fs_connect .fs-header .fs-site-icon{left:152px}#fs_connect .fs-header .fs-connect-logo{right:152px}#fs_connect .fs-header .fs-site-icon,#fs_connect .fs-header img,#fs_connect .fs-header object{width:50px;height:50px;border-radius:50%}#fs_connect .fs-header .fs-plugin-icon{position:absolute;overflow:hidden;top:-23px;left:50%;margin-left:-44px;border-radius:50%;z-index:1}#fs_connect .fs-header .fs-plugin-icon,#fs_connect .fs-header .fs-plugin-icon img{width:80px;height:80px}#fs_connect .fs-header .dashicons-wordpress-alt{font-size:40px;background:#01749a;color:#fff;width:40px;height:40px;padding:5px;border-radius:50%}#fs_connect .fs-header .dashicons-plus{position:absolute;top:50%;font-size:30px;margin-top:-10px;color:#bbb}#fs_connect .fs-header .dashicons-plus.fs-first{left:28%}#fs_connect .fs-header .dashicons-plus.fs-second{left:65%}#fs_connect .fs-header .fs-plugin-icon,#fs_connect .fs-header .fs-connect-logo,#fs_connect .fs-header .fs-site-icon{border:1px solid #efefef;padding:3px;background:#fff}#fs_connect .fs-terms{text-align:center;font-size:.85em;padding:10px 5px}#fs_connect .fs-terms,#fs_connect .fs-terms a{color:#999}#fs_connect .fs-terms a{text-decoration:none}.fs-multisite-options-container{margin-top:20px;border:1px solid #ccc;padding:5px}.fs-multisite-options-container a{text-decoration:none}.fs-multisite-options-container a:focus{box-shadow:none}.fs-multisite-options-container a.selected{font-weight:bold}.fs-multisite-options-container.fs-apply-on-all-sites{border:0 none;padding:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options{border-spacing:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options td:not(:first-child){display:none}.fs-multisite-options-container .fs-sites-list-container{display:none;overflow:auto}.fs-multisite-options-container .fs-sites-list-container table td{border-top:1px solid #ccc;padding:4px 2px}#fs_marketing_optin{display:none;margin-top:10px;border:1px solid #ccc;padding:10px;line-height:1.5em}#fs_marketing_optin .fs-message{display:block;margin-bottom:5px;font-size:1.05em;font-weight:600}#fs_marketing_optin.error{border:1px solid #d3135a;background:#fee}#fs_marketing_optin.error .fs-message{color:#d3135a}#fs_marketing_optin .fs-input-container{margin-top:5px}#fs_marketing_optin .fs-input-container label{margin-top:5px;display:block}#fs_marketing_optin .fs-input-container label input{float:left;margin:1px 0 0 0}#fs_marketing_optin .fs-input-container label:first-child{display:block;margin-bottom:2px}#fs_marketing_optin .fs-input-label{display:block;margin-left:20px}#fs_marketing_optin .fs-input-label .underlined{text-decoration:underline}.rtl #fs_marketing_optin .fs-input-container label input{float:right}.rtl #fs_marketing_optin .fs-input-label{margin-left:0;margin-right:20px}.rtl #fs_connect{border-radius:3px}.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:" »"}.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-header .fs-site-icon{right:20px;left:auto}.rtl #fs_connect .fs-header .fs-connect-logo{right:auto;left:20px}.rtl #fs_connect .fs-permissions>.fs-trigger .fs-arrow::after{content:"←"}#fs_theme_connect_wrapper{position:fixed;top:0;height:100%;width:100%;z-index:99990;background:rgba(0,0,0,.75);text-align:center;overflow-y:auto}#fs_theme_connect_wrapper:before{content:"";display:inline-block;vertical-align:middle;height:100%}#fs_theme_connect_wrapper>button.close{color:#fff;cursor:pointer;height:40px;width:40px;position:absolute;right:0;border:0;background-color:transparent;top:32px}#fs_theme_connect_wrapper #fs_connect{top:0;text-align:left;display:inline-block;vertical-align:middle;margin-top:0;margin-bottom:20px}#fs_theme_connect_wrapper #fs_connect .fs-terms,#fs_theme_connect_wrapper #fs_connect .fs-terms a{color:#c5c5c5}.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}#license_issues_link{display:block;text-align:center;font-size:.9em;margin-top:10px}.fs-tooltip-trigger{position:relative}.fs-tooltip-trigger:not(a){cursor:help}.fs-tooltip-trigger .dashicons{float:none !important}.fs-tooltip-trigger .fs-tooltip{opacity:0;visibility:hidden;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-ms-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;position:absolute;background:rgba(0,0,0,.8);color:#fff !important;font-family:"arial",serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:-17px;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(0,0,0,.2);line-height:1.3em;font-weight:bold;text-align:left;text-transform:none !important}.rtl .fs-tooltip-trigger .fs-tooltip{text-align:right;left:auto;right:-17px}.fs-tooltip-trigger .fs-tooltip::after{content:" ";display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:rgba(0,0,0,.8) transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl .fs-tooltip-trigger .fs-tooltip::after{right:21px;left:auto}.fs-tooltip-trigger:hover .fs-tooltip{visibility:visible;opacity:1}.fs-permissions .fs-permission.fs-disabled{color:#aaa}.fs-permissions .fs-permission.fs-disabled .fs-permission-description span{color:#aaa}.fs-permissions .fs-permission .fs-switch-feedback{position:absolute;right:15px;top:52px}.fs-permissions ul{height:0;overflow:hidden;margin:0}.fs-permissions ul li{padding:17px 15px;margin:0;position:relative}.fs-permissions ul li>i.dashicons{float:left;font-size:30px;width:30px;height:30px;padding:5px}.fs-permissions ul li .fs-switch{float:right}.fs-permissions ul li .fs-permission-description{margin-left:55px}.fs-permissions ul li .fs-permission-description span{font-size:14px;font-weight:500;color:#23282d}.fs-permissions ul li .fs-permission-description .fs-tooltip{font-size:13px;font-weight:bold}.fs-permissions ul li .fs-permission-description .fs-tooltip-trigger .dashicons{margin:-1px 2px 0 2px}.fs-permissions ul li .fs-permission-description p{margin:2px 0 0 0}.fs-permissions.fs-open{background:#fff}.fs-permissions.fs-open ul{overflow:initial;height:auto;margin:20px 0 10px 0}.fs-permissions .fs-switch-feedback .fs-ajax-spinner{margin-right:10px}.fs-permissions .fs-switch-feedback.success{color:#71ae00}.rtl .fs-permissions .fs-switch-feedback{right:auto;left:15px}.rtl .fs-permissions .fs-switch-feedback .fs-ajax-spinner{margin-left:10px;margin-right:0}.rtl .fs-permissions ul li .fs-permission-description{margin-right:55px;margin-left:0}.rtl .fs-permissions ul li .fs-switch{float:left}.rtl .fs-permissions ul li i.dashicons{float:right}
freemius/assets/css/admin/debug.css CHANGED
@@ -1 +1 @@
1
- .fs-switch-label{font-size:20px;line-height:31px;margin:0 5px}#fs_log_book table{font-family:Consolas,Monaco,monospace;font-size:12px}#fs_log_book table th{color:#ccc}#fs_log_book table tr{background:#232525}#fs_log_book table tr.alternate{background:#2b2b2b}#fs_log_book table tr td.fs-col--logger{color:#5a7435}#fs_log_book table tr td.fs-col--type{color:#ffc861}#fs_log_book table tr td.fs-col--function{color:#a7b7b1;font-weight:bold}#fs_log_book table tr td.fs-col--message,#fs_log_book table tr td.fs-col--message a{color:#9a73ac !important}#fs_log_book table tr td.fs-col--file{color:#d07922}#fs_log_book table tr td.fs-col--timestamp{color:#6596be}
1
+ label.fs-tag,span.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,span.fs-tag.fs-warn{background:#ffba00}label.fs-tag.fs-info,span.fs-tag.fs-info{background:#00a0d2}label.fs-tag.fs-success,span.fs-tag.fs-success{background:#46b450}label.fs-tag.fs-error,span.fs-tag.fs-error{background:#dc3232}.fs-switch-label{font-size:20px;line-height:31px;margin:0 5px}#fs_log_book table{font-family:Consolas,Monaco,monospace;font-size:12px}#fs_log_book table th{color:#ccc}#fs_log_book table tr{background:#232525}#fs_log_book table tr.alternate{background:#2b2b2b}#fs_log_book table tr td.fs-col--logger{color:#5a7435}#fs_log_book table tr td.fs-col--type{color:#ffc861}#fs_log_book table tr td.fs-col--function{color:#a7b7b1;font-weight:bold}#fs_log_book table tr td.fs-col--message,#fs_log_book table tr td.fs-col--message a{color:#9a73ac !important}#fs_log_book table tr td.fs-col--file{color:#d07922}#fs_log_book table tr td.fs-col--timestamp{color:#6596be}
freemius/assets/css/admin/dialog-boxes.css CHANGED
@@ -1,2 +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 .dashicons{vertical-align:middle}.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-success .fs-modal-header{border-bottom-color:#46b450}.fs-modal.fs-success .fs-modal-body{background-color:#f7fff7}.fs-modal.fs-warn .fs-modal-header{border-bottom-color:#ffb900}.fs-modal.fs-warn .fs-modal-body{background-color:#fff8e5}.fs-modal.fs-error .fs-modal-header{border-bottom-color:#dc3232}.fs-modal.fs-error .fs-modal-body{background-color:#ffeaea}.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;margin-bottom:-10px}.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-header .fs-close .dashicons,.fs-modal .fs-modal-header .fs-close:hover .dashicons{text-decoration:none}.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;line-height:1.5em}.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-subscription-cancellation .fs-price-increase-warning{color:red;font-weight:bold;padding:0 25px;margin-bottom:0}.fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label input{float:left;top:5px;position:relative}.rtl .fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label input{float:right}.fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label span{display:block;margin-left:24px}.rtl .fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label span{margin-left:0;margin-right:24px}.fs-modal.fs-modal-license-activation .fs-modal-body input.fs-license-key{width:100%}.fs-license-options-container table,.fs-license-options-container table select,.fs-license-options-container table .fs-available-license-key{width:100%}.fs-license-options-container table td:first-child{width:1%}.fs-license-options-container table .fs-other-license-key-container label{position:relative;top:6px;float:left;margin-right:5px}.fs-license-options-container table .fs-other-license-key-container div{overflow:hidden;width:auto;height:30px;display:block;top:2px;position:relative}.fs-license-options-container table .fs-other-license-key-container div input{margin:0}.fs-sites-list-container td{cursor:pointer}.fs-modal.fs-modal-user-change .fs-modal-body input#fs_other_email_address{width:100%}.fs-user-change-options-container table{width:100%;border-collapse:collapse}.fs-user-change-options-container table tr{display:block;margin-bottom:2px}.fs-user-change-options-container table .fs-email-address-container td{display:inline-block}.fs-user-change-options-container table .fs-email-address-container input[type="radio"]{margin-bottom:0;margin-top:0}.fs-user-change-options-container table .fs-other-email-address-container{width:100%}.fs-user-change-options-container table .fs-other-email-address-container>div{display:table;width:100%}.fs-user-change-options-container table .fs-other-email-address-container>div label,.fs-user-change-options-container table .fs-other-email-address-container>div>div{display:table-cell}.fs-user-change-options-container table .fs-other-email-address-container>div label{width:1%;padding-left:3px;padding-right:3px}.fs-user-change-options-container table .fs-other-email-address-container>div>div{width:auto}.fs-user-change-options-container table .fs-other-email-address-container>div>div input{width:100%}.fs-modal.fs-modal-developer-license-debug-mode .fs-modal-body input.fs-license-or-user-key{width:100%}.fs-multisite-options-container{margin-top:10px;border:1px solid #ccc;padding:5px}.fs-multisite-options-container a{text-decoration:none}.fs-multisite-options-container a:focus{box-shadow:none}.fs-multisite-options-container a.selected{font-weight:bold}.fs-multisite-options-container.fs-apply-on-all-sites{border:0 none;padding:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options{border-spacing:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options td:not(:first-child){display:none}.fs-multisite-options-container .fs-sites-list-container{display:none;overflow:auto}.fs-multisite-options-container .fs-sites-list-container table td{border-top:1px solid #ccc;padding:4px 2px}.fs-modal.fs-modal-license-key-resend .email-address-container{overflow:hidden;padding-right:2px}.fs-modal.fs-modal-license-key-resend.fs-freemium input.email-address{width:300px}.fs-modal.fs-modal-license-key-resend.fs-freemium label{display:block;margin-bottom:10px}.fs-modal.fs-modal-license-key-resend.fs-premium input.email-address{width:100%}.fs-modal.fs-modal-license-key-resend.fs-premium .button-container{float:right;margin-left:7px}@media (max-width: 650px){.fs-modal.fs-modal-license-key-resend.fs-premium .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}.fs-ajax-loader{position:relative;width:170px;height:20px;margin:auto}.fs-ajax-loader .fs-ajax-loader-bar{position:absolute;top:0;background-color:#0074a3;width:20px;height:20px;-webkit-animation-name:bounce_ajaxLoader;-moz-animation-name:bounce_ajaxLoader;-ms-animation-name:bounce_ajaxLoader;-o-animation-name:bounce_ajaxLoader;animation-name:bounce_ajaxLoader;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s;animation-duration:1.5s;animation-iteration-count:infinite;-o-animation-iteration-count:infinite;-ms-animation-iteration-count:infinite;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;-webkit-animation-direction:normal;-moz-animation-direction:normal;-ms-animation-direction:normal;-o-animation-direction:normal;animation-direction:normal;-moz-transform:0.3;-o-transform:0.3;-ms-transform:0.3;-webkit-transform:0.3;transform:0.3}.fs-ajax-loader .fs-ajax-loader-bar-1{left:0px;animation-delay:0.6s;-o-animation-delay:0.6s;-ms-animation-delay:0.6s;-webkit-animation-delay:0.6s;-moz-animation-delay:0.6s}.fs-ajax-loader .fs-ajax-loader-bar-2{left:19px;animation-delay:0.75s;-o-animation-delay:0.75s;-ms-animation-delay:0.75s;-webkit-animation-delay:0.75s;-moz-animation-delay:0.75s}.fs-ajax-loader .fs-ajax-loader-bar-3{left:38px;animation-delay:0.9s;-o-animation-delay:0.9s;-ms-animation-delay:0.9s;-webkit-animation-delay:0.9s;-moz-animation-delay:0.9s}.fs-ajax-loader .fs-ajax-loader-bar-4{left:57px;animation-delay:1.05s;-o-animation-delay:1.05s;-ms-animation-delay:1.05s;-webkit-animation-delay:1.05s;-moz-animation-delay:1.05s}.fs-ajax-loader .fs-ajax-loader-bar-5{left:76px;animation-delay:1.2s;-o-animation-delay:1.2s;-ms-animation-delay:1.2s;-webkit-animation-delay:1.2s;-moz-animation-delay:1.2s}.fs-ajax-loader .fs-ajax-loader-bar-6{left:95px;animation-delay:1.35s;-o-animation-delay:1.35s;-ms-animation-delay:1.35s;-webkit-animation-delay:1.35s;-moz-animation-delay:1.35s}.fs-ajax-loader .fs-ajax-loader-bar-7{left:114px;animation-delay:1.5s;-o-animation-delay:1.5s;-ms-animation-delay:1.5s;-webkit-animation-delay:1.5s;-moz-animation-delay:1.5s}.fs-ajax-loader .fs-ajax-loader-bar-8{left:133px;animation-delay:1.65s;-o-animation-delay:1.65s;-ms-animation-delay:1.65s;-webkit-animation-delay:1.65s;-moz-animation-delay:1.65s}@-moz-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-ms-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-o-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-webkit-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}.fs-modal-auto-install #request-filesystem-credentials-form h2,.fs-modal-auto-install #request-filesystem-credentials-form .request-filesystem-credentials-action-buttons{display:none}.fs-modal-auto-install #request-filesystem-credentials-form input[type=password],.fs-modal-auto-install #request-filesystem-credentials-form input[type=email],.fs-modal-auto-install #request-filesystem-credentials-form input[type=text]{-webkit-appearance:none;padding:10px 10px 5px 10px;width:300px;max-width:100%}.fs-modal-auto-install #request-filesystem-credentials-form>div,.fs-modal-auto-install #request-filesystem-credentials-form label,.fs-modal-auto-install #request-filesystem-credentials-form fieldset{width:300px;max-width:100%;margin:0 auto;display:block}.button-primary.warn{box-shadow:0 1px 0 #d2593c;text-shadow:0 -1px 1px #d2593c,1px 0 1px #d2593c,0 1px 1px #d2593c,-1px 0 1px #d2593c;background:#f56a48;border-color:#ec6544 #d2593c #d2593c}.button-primary.warn:hover{background:#fd6d4a;border-color:#d2593c}.button-primary.warn:focus{box-shadow:0 1px 0 #dd6041,0 0 2px 1px #e4a796}.button-primary.warn:active{background:#dd6041;border-color:#d2593c;box-shadow:inset 0 2px 0 #d2593c}.button-primary.warn.disabled{color:#f5b3a1 !important;background:#e76444 !important;border-color:#d85e40 !important;text-shadow:0 -1px 0 rgba(0,0,0,0.1) !important}
1
+ .fs-modal{position:fixed;overflow:auto;height:100%;width:100%;top:0;z-index:100000;display:none;background:rgba(0,0,0,.6)}@media(min-width: 961px){.fs-modal{padding-left:160px}.rtl .fs-modal{padding-left:0;padding-right:160px}}.fs-modal .dashicons{vertical-align:middle}.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-success .fs-modal-header{border-bottom-color:#46b450}.fs-modal.fs-success .fs-modal-body{background-color:#f7fff7}.fs-modal.fs-warn .fs-modal-header{border-bottom-color:#ffb900}.fs-modal.fs-warn .fs-modal-body{background-color:#fff8e5}.fs-modal.fs-error .fs-modal-header{border-bottom-color:#dc3232}.fs-modal.fs-error .fs-modal-body{background-color:#ffeaea}.fs-modal .fs-modal-body,.fs-modal .fs-modal-footer{border:0;background:#fefefe;padding:20px}.fs-modal .fs-modal-header{border-bottom:#eee solid 1px;background:#fbfbfb;padding:15px 20px;position:relative;margin-bottom:-10px}.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:.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 .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.fs-modal .fs-modal-header .fs-close:hover{color:#fff;background:#aaa}.fs-modal .fs-modal-header .fs-close .dashicons,.fs-modal .fs-modal-header .fs-close:hover .dashicons{text-decoration:none}.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;line-height:1.5em}.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:#eee solid 1px;text-align:right}.fs-modal .fs-modal-footer>.button{margin:0 7px}.fs-modal .fs-modal-footer>.button:last-of-type{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}.rtl .fs-modal .fs-modal-footer{text-align:left}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,.fs-modal.fs-modal-deactivation-feedback .feedback-from-snooze-label{float:left;line-height:30px}.rtl .fs-modal.fs-modal-deactivation-feedback .anonymous-feedback-label,.rtl .fs-modal.fs-modal-deactivation-feedback .feedback-from-snooze-label{float:right}.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-subscription-cancellation .fs-price-increase-warning{color:red;font-weight:bold;padding:0 25px;margin-bottom:0}.fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label input{float:left;top:5px;position:relative}.rtl .fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label input{float:right}.fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label span{display:block;margin-left:24px}.rtl .fs-modal.fs-modal-subscription-cancellation ul.subscription-actions label span{margin-left:0;margin-right:24px}.fs-modal.fs-modal-license-activation .fs-modal-body input.fs-license-key{width:100%}.fs-license-options-container table,.fs-license-options-container table select,.fs-license-options-container table .fs-available-license-key{width:100%}.fs-license-options-container table td:first-child{width:1%}.fs-license-options-container table .fs-other-license-key-container label{position:relative;top:6px;float:left;margin-right:5px}.fs-license-options-container table .fs-other-license-key-container div{overflow:hidden;width:auto;height:30px;display:block;top:2px;position:relative}.fs-license-options-container table .fs-other-license-key-container div input{margin:0}.fs-sites-list-container td{cursor:pointer}.fs-modal.fs-modal-user-change .fs-modal-body input#fs_other_email_address{width:100%}.fs-user-change-options-container table{width:100%;border-collapse:collapse}.fs-user-change-options-container table tr{display:block;margin-bottom:2px}.fs-user-change-options-container table .fs-email-address-container td{display:inline-block}.fs-user-change-options-container table .fs-email-address-container input[type=radio]{margin-bottom:0;margin-top:0}.fs-user-change-options-container table .fs-other-email-address-container{width:100%}.fs-user-change-options-container table .fs-other-email-address-container>div{display:table;width:100%}.fs-user-change-options-container table .fs-other-email-address-container>div label,.fs-user-change-options-container table .fs-other-email-address-container>div>div{display:table-cell}.fs-user-change-options-container table .fs-other-email-address-container>div label{width:1%;padding-left:3px;padding-right:3px}.fs-user-change-options-container table .fs-other-email-address-container>div>div{width:auto}.fs-user-change-options-container table .fs-other-email-address-container>div>div input{width:100%}.fs-modal.fs-modal-developer-license-debug-mode .fs-modal-body input.fs-license-or-user-key{width:100%}.fs-multisite-options-container{margin-top:20px;border:1px solid #ccc;padding:5px}.fs-multisite-options-container a{text-decoration:none}.fs-multisite-options-container a:focus{box-shadow:none}.fs-multisite-options-container a.selected{font-weight:bold}.fs-multisite-options-container.fs-apply-on-all-sites{border:0 none;padding:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options{border-spacing:0}.fs-multisite-options-container.fs-apply-on-all-sites .fs-all-sites-options td:not(:first-child){display:none}.fs-multisite-options-container .fs-sites-list-container{display:none;overflow:auto}.fs-multisite-options-container .fs-sites-list-container table td{border-top:1px solid #ccc;padding:4px 2px}.fs-modal.fs-modal-license-key-resend .email-address-container{overflow:hidden;padding-right:2px}.fs-modal.fs-modal-license-key-resend.fs-freemium input.email-address{width:300px}.fs-modal.fs-modal-license-key-resend.fs-freemium label{display:block;margin-bottom:10px}.fs-modal.fs-modal-license-key-resend.fs-premium input.email-address{width:100%}.fs-modal.fs-modal-license-key-resend.fs-premium .button-container{float:right;margin-left:7px}@media(max-width: 650px){.fs-modal.fs-modal-license-key-resend.fs-premium .button-container{margin-top:2px}}.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}.fs-modal.fs-modal-email-address-update .fs-modal-body input[type=text]{width:100%}.fs-modal.fs-modal-email-address-update p{margin-bottom:0}.fs-modal.fs-modal-email-address-update ul{margin:1em .5em}.fs-modal.fs-modal-email-address-update ul li label span{float:left;margin-top:0}.fs-modal.fs-modal-email-address-update ul li label span:last-child{display:block;float:none;margin-left:20px}.fs-ajax-loader{position:relative;width:170px;height:20px;margin:auto}.fs-ajax-loader .fs-ajax-loader-bar{position:absolute;top:0;background-color:#0074a3;width:20px;height:20px;-webkit-animation-name:bounce_ajaxLoader;-moz-animation-name:bounce_ajaxLoader;-ms-animation-name:bounce_ajaxLoader;-o-animation-name:bounce_ajaxLoader;animation-name:bounce_ajaxLoader;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s;animation-duration:1.5s;animation-iteration-count:infinite;-o-animation-iteration-count:infinite;-ms-animation-iteration-count:infinite;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;-webkit-animation-direction:normal;-moz-animation-direction:normal;-ms-animation-direction:normal;-o-animation-direction:normal;animation-direction:normal;-moz-transform:.3;-o-transform:.3;-ms-transform:.3;-webkit-transform:.3;transform:.3}.fs-ajax-loader .fs-ajax-loader-bar-1{left:0px;animation-delay:0.6s;-o-animation-delay:0.6s;-ms-animation-delay:0.6s;-webkit-animation-delay:0.6s;-moz-animation-delay:0.6s}.fs-ajax-loader .fs-ajax-loader-bar-2{left:19px;animation-delay:0.75s;-o-animation-delay:0.75s;-ms-animation-delay:0.75s;-webkit-animation-delay:0.75s;-moz-animation-delay:0.75s}.fs-ajax-loader .fs-ajax-loader-bar-3{left:38px;animation-delay:0.9s;-o-animation-delay:0.9s;-ms-animation-delay:0.9s;-webkit-animation-delay:0.9s;-moz-animation-delay:0.9s}.fs-ajax-loader .fs-ajax-loader-bar-4{left:57px;animation-delay:1.05s;-o-animation-delay:1.05s;-ms-animation-delay:1.05s;-webkit-animation-delay:1.05s;-moz-animation-delay:1.05s}.fs-ajax-loader .fs-ajax-loader-bar-5{left:76px;animation-delay:1.2s;-o-animation-delay:1.2s;-ms-animation-delay:1.2s;-webkit-animation-delay:1.2s;-moz-animation-delay:1.2s}.fs-ajax-loader .fs-ajax-loader-bar-6{left:95px;animation-delay:1.35s;-o-animation-delay:1.35s;-ms-animation-delay:1.35s;-webkit-animation-delay:1.35s;-moz-animation-delay:1.35s}.fs-ajax-loader .fs-ajax-loader-bar-7{left:114px;animation-delay:1.5s;-o-animation-delay:1.5s;-ms-animation-delay:1.5s;-webkit-animation-delay:1.5s;-moz-animation-delay:1.5s}.fs-ajax-loader .fs-ajax-loader-bar-8{left:133px;animation-delay:1.65s;-o-animation-delay:1.65s;-ms-animation-delay:1.65s;-webkit-animation-delay:1.65s;-moz-animation-delay:1.65s}@-moz-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-ms-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-o-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@-webkit-keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}@keyframes bounce_ajaxLoader{0%{-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1);-webkit-transform:scale(1);transform:scale(1);background-color:#0074a3}100%{-moz-transform:scale(0.3);-o-transform:scale(0.3);-ms-transform:scale(0.3);-webkit-transform:scale(0.3);transform:scale(0.3);background-color:#fff}}.fs-modal-auto-install #request-filesystem-credentials-form h2,.fs-modal-auto-install #request-filesystem-credentials-form .request-filesystem-credentials-action-buttons{display:none}.fs-modal-auto-install #request-filesystem-credentials-form input[type=password],.fs-modal-auto-install #request-filesystem-credentials-form input[type=email],.fs-modal-auto-install #request-filesystem-credentials-form input[type=text]{-webkit-appearance:none;padding:10px 10px 5px 10px;width:300px;max-width:100%}.fs-modal-auto-install #request-filesystem-credentials-form>div,.fs-modal-auto-install #request-filesystem-credentials-form label,.fs-modal-auto-install #request-filesystem-credentials-form fieldset{width:300px;max-width:100%;margin:0 auto;display:block}.button-primary.warn{box-shadow:0 1px 0 #d2593c;text-shadow:0 -1px 1px #d2593c,1px 0 1px #d2593c,0 1px 1px #d2593c,-1px 0 1px #d2593c;background:#f56a48;border-color:#ec6544 #d2593c #d2593c}.button-primary.warn:hover{background:#fd6d4a;border-color:#d2593c}.button-primary.warn:focus{box-shadow:0 1px 0 #dd6041,0 0 2px 1px #e4a796}.button-primary.warn:active{background:#dd6041;border-color:#d2593c;box-shadow:inset 0 2px 0 #d2593c}.button-primary.warn.disabled{color:#f5b3a1 !important;background:#e76444 !important;border-color:#d85e40 !important;text-shadow:0 -1px 0 rgba(0,0,0,.1) !important}
 
freemius/assets/css/admin/gdpr-optin-notice.css CHANGED
@@ -1 +1 @@
1
- .fs-notice[data-id^="gdpr_optin_actions"] .underlined{text-decoration:underline}.fs-notice[data-id^="gdpr_optin_actions"] ul .button,.fs-notice[data-id^="gdpr_optin_actions"] ul .action-description{vertical-align:middle}.fs-notice[data-id^="gdpr_optin_actions"] ul .action-description{display:inline-block;margin-left:3px}
1
+ .fs-notice[data-id^=gdpr_optin_actions] .underlined{text-decoration:underline}.fs-notice[data-id^=gdpr_optin_actions] ul .button,.fs-notice[data-id^=gdpr_optin_actions] ul .action-description{vertical-align:middle}.fs-notice[data-id^=gdpr_optin_actions] ul .action-description{display:inline-block;margin-left:3px}
freemius/assets/css/admin/optout.css ADDED
@@ -0,0 +1 @@
 
1
+ .fs-tooltip-trigger{position:relative}.fs-tooltip-trigger:not(a){cursor:help}.fs-tooltip-trigger .dashicons{float:none !important}.fs-tooltip-trigger .fs-tooltip{opacity:0;visibility:hidden;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-ms-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;position:absolute;background:rgba(0,0,0,.8);color:#fff !important;font-family:"arial",serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:-17px;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(0,0,0,.2);line-height:1.3em;font-weight:bold;text-align:left;text-transform:none !important}.rtl .fs-tooltip-trigger .fs-tooltip{text-align:right;left:auto;right:-17px}.fs-tooltip-trigger .fs-tooltip::after{content:" ";display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:rgba(0,0,0,.8) transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl .fs-tooltip-trigger .fs-tooltip::after{right:21px;left:auto}.fs-tooltip-trigger:hover .fs-tooltip{visibility:visible;opacity:1}.fs-permissions .fs-permission.fs-disabled{color:#aaa}.fs-permissions .fs-permission.fs-disabled .fs-permission-description span{color:#aaa}.fs-permissions .fs-permission .fs-switch-feedback{position:absolute;right:15px;top:52px}.fs-permissions ul{height:0;overflow:hidden;margin:0}.fs-permissions ul li{padding:17px 15px;margin:0;position:relative}.fs-permissions ul li>i.dashicons{float:left;font-size:30px;width:30px;height:30px;padding:5px}.fs-permissions ul li .fs-switch{float:right}.fs-permissions ul li .fs-permission-description{margin-left:55px}.fs-permissions ul li .fs-permission-description span{font-size:14px;font-weight:500;color:#23282d}.fs-permissions ul li .fs-permission-description .fs-tooltip{font-size:13px;font-weight:bold}.fs-permissions ul li .fs-permission-description .fs-tooltip-trigger .dashicons{margin:-1px 2px 0 2px}.fs-permissions ul li .fs-permission-description p{margin:2px 0 0 0}.fs-permissions.fs-open{background:#fff}.fs-permissions.fs-open ul{overflow:initial;height:auto;margin:20px 0 10px 0}.fs-permissions .fs-switch-feedback .fs-ajax-spinner{margin-right:10px}.fs-permissions .fs-switch-feedback.success{color:#71ae00}.rtl .fs-permissions .fs-switch-feedback{right:auto;left:15px}.rtl .fs-permissions .fs-switch-feedback .fs-ajax-spinner{margin-left:10px;margin-right:0}.rtl .fs-permissions ul li .fs-permission-description{margin-right:55px;margin-left:0}.rtl .fs-permissions ul li .fs-switch{float:left}.rtl .fs-permissions ul li i.dashicons{float:right}.fs-modal-opt-out .fs-modal-footer .fs-opt-out-button{line-height:30px;margin-right:10px}.fs-modal-opt-out .fs-permissions{margin-top:0 !important}.fs-modal-opt-out .fs-permissions .fs-permissions-section--header .fs-group-opt-out-button{float:right;line-height:1.1em}.fs-modal-opt-out .fs-permissions .fs-permissions-section--header .fs-switch-feedback{float:right;line-height:1.1em;margin-right:10px}.fs-modal-opt-out .fs-permissions .fs-permissions-section--header .fs-switch-feedback .fs-ajax-spinner{margin:-2px 0 0}.fs-modal-opt-out .fs-permissions .fs-permissions-section--header-title{font-size:1.1em;font-weight:600;text-transform:uppercase;display:block;line-height:1.1em;margin:.5em 0}.fs-modal-opt-out .fs-permissions .fs-permissions-section--desc{margin-top:0}.fs-modal-opt-out .fs-permissions hr{border:0;border-top:#eee solid 1px;margin:25px 0 20px 0}.fs-modal-opt-out .fs-permissions ul{border:1px solid #c3c4c7;border-radius:3px;margin:10px 0 0 0;box-shadow:0 1px 1px rgba(0,0,0,.04)}.fs-modal-opt-out .fs-permissions ul li{border-bottom:1px solid #d7dde1;border-left:4px solid #72aee6}.rtl .fs-modal-opt-out .fs-permissions ul li{border-left:none;border-right:4px solid #72aee6}.fs-modal-opt-out .fs-permissions ul li.fs-disabled{border-left-color:rgba(114,174,230,0)}.fs-modal-opt-out .fs-permissions ul li:last-child{border-bottom:none}
freemius/assets/css/customizer.css CHANGED
@@ -1 +1 @@
1
- #fs_customizer_upsell .fs-customizer-plan{padding:10px 20px 20px 20px;border-radius:3px;background:#fff}#fs_customizer_upsell .fs-customizer-plan h2{position:relative;margin:0;line-height:2em;text-transform:uppercase}#fs_customizer_upsell .fs-customizer-plan h2 .button-link{top:-2px}#fs_customizer_upsell .fs-feature{position:relative}#fs_customizer_upsell .dashicons-yes{color:#0085ba;font-size:2em;vertical-align:bottom;margin-left:-7px;margin-right:10px}.rtl #fs_customizer_upsell .dashicons-yes{margin-left:10px;margin-right:-7px}#fs_customizer_upsell .dashicons-editor-help{color:#bbb;cursor:help}#fs_customizer_upsell .dashicons-editor-help .fs-feature-desc{opacity:0;visibility:hidden;-moz-transition:opacity 0.3s ease-in-out;-o-transition:opacity 0.3s ease-in-out;-ms-transition:opacity 0.3s ease-in-out;-webkit-transition:opacity 0.3s ease-in-out;transition:opacity 0.3s ease-in-out;position:absolute;background:#000;color:#fff;font-family:'arial', serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:0;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-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);line-height:1.3em;font-weight:bold;text-align:left}.rtl #fs_customizer_upsell .dashicons-editor-help .fs-feature-desc{text-align:right}#fs_customizer_upsell .dashicons-editor-help .fs-feature-desc::after{content:' ';display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:#000 transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl #fs_customizer_upsell .dashicons-editor-help .fs-feature-desc::after{right:21px;left:auto}#fs_customizer_upsell .dashicons-editor-help:hover .fs-feature-desc{visibility:visible;opacity:1}#fs_customizer_upsell .button-primary{display:block;text-align:center;margin-top:10px}#fs_customizer_support{display:block !important}#fs_customizer_support .button{float:right}#fs_customizer_support .button-group{width:100%;display:block;margin-top:10px}#fs_customizer_support .button-group .button{float:none;width:50%;text-align:center}#customize-theme-controls #accordion-section-freemius_upsell{border-top:1px solid #0085ba !important;border-bottom:1px solid #0085ba !important}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title{color:#fff;background-color:#0085ba;border-left:4px solid #0085ba;transition:.15s background-color ease-in-out, .15s border-color ease-in-out;outline:none;border-bottom:none !important}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title:hover{background-color:#008ec2;border-left-color:#0073aa}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title:after{color:#fff}#customize-theme-controls #accordion-section-freemius_upsell .rtl h3.accordion-section-title{border-left:none;border-right:4px solid #0085ba}#customize-theme-controls #accordion-section-freemius_upsell .rtl h3.accordion-section-title:hover{border-right-color:#0073aa}
1
+ #fs_customizer_upsell .fs-customizer-plan{padding:10px 20px 20px 20px;border-radius:3px;background:#fff}#fs_customizer_upsell .fs-customizer-plan h2{position:relative;margin:0;line-height:2em;text-transform:uppercase}#fs_customizer_upsell .fs-customizer-plan h2 .button-link{top:-2px}#fs_customizer_upsell .fs-feature{position:relative}#fs_customizer_upsell .dashicons-yes{color:#0085ba;font-size:2em;vertical-align:bottom;margin-left:-7px;margin-right:10px}.rtl #fs_customizer_upsell .dashicons-yes{margin-left:10px;margin-right:-7px}#fs_customizer_upsell .dashicons-editor-help{color:#bbb;cursor:help}#fs_customizer_upsell .dashicons-editor-help .fs-feature-desc{opacity:0;visibility:hidden;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-ms-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;position:absolute;background:#000;color:#fff;font-family:"arial",serif;font-size:12px;padding:10px;z-index:999999;bottom:100%;margin-bottom:5px;left:0;right:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(0,0,0,.2);line-height:1.3em;font-weight:bold;text-align:left}.rtl #fs_customizer_upsell .dashicons-editor-help .fs-feature-desc{text-align:right}#fs_customizer_upsell .dashicons-editor-help .fs-feature-desc::after{content:" ";display:block;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:#000 transparent transparent transparent;position:absolute;top:100%;left:21px}.rtl #fs_customizer_upsell .dashicons-editor-help .fs-feature-desc::after{right:21px;left:auto}#fs_customizer_upsell .dashicons-editor-help:hover .fs-feature-desc{visibility:visible;opacity:1}#fs_customizer_upsell .button-primary{display:block;text-align:center;margin-top:10px}#fs_customizer_support{display:block !important}#fs_customizer_support .button{float:right}#fs_customizer_support .button-group{width:100%;display:block;margin-top:10px}#fs_customizer_support .button-group .button{float:none;width:50%;text-align:center}#customize-theme-controls #accordion-section-freemius_upsell{border-top:1px solid #0085ba !important;border-bottom:1px solid #0085ba !important}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title{color:#fff;background-color:#0085ba;border-left:4px solid #0085ba;transition:.15s background-color ease-in-out,.15s border-color ease-in-out;outline:none;border-bottom:none !important}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title:hover{background-color:#008ec2;border-left-color:#0073aa}#customize-theme-controls #accordion-section-freemius_upsell h3.accordion-section-title:after{color:#fff}#customize-theme-controls #accordion-section-freemius_upsell .rtl h3.accordion-section-title{border-left:none;border-right:4px solid #0085ba}#customize-theme-controls #accordion-section-freemius_upsell .rtl h3.accordion-section-title:hover{border-right-color:#0073aa}
freemius/config.php CHANGED
@@ -354,7 +354,7 @@
354
  is_multisite() &&
355
  ( is_network_admin() ||
356
  ( ( defined( 'DOING_AJAX' ) && DOING_AJAX &&
357
- ( isset( $_REQUEST['_fs_network_admin'] ) /*||
358
  ( ! empty( $_REQUEST['action'] ) && 'delete-plugin' === $_REQUEST['action'] )*/ )
359
  ) ||
360
  // Plugin uninstall.
@@ -385,7 +385,7 @@
385
 
386
  if ( ! defined( 'WP_FS__DEMO_MODE' ) ) {
387
  define( 'WP_FS__DEMO_MODE', false );
388
- }
389
- if ( ! defined( 'FS_SDK__SSLVERIFY' ) ) {
390
- define( 'FS_SDK__SSLVERIFY', false );
391
- }
354
  is_multisite() &&
355
  ( is_network_admin() ||
356
  ( ( defined( 'DOING_AJAX' ) && DOING_AJAX &&
357
+ ( isset( $_REQUEST['_fs_network_admin'] ) && 'true' === $_REQUEST['_fs_network_admin'] /*||
358
  ( ! empty( $_REQUEST['action'] ) && 'delete-plugin' === $_REQUEST['action'] )*/ )
359
  ) ||
360
  // Plugin uninstall.
385
 
386
  if ( ! defined( 'WP_FS__DEMO_MODE' ) ) {
387
  define( 'WP_FS__DEMO_MODE', false );
388
+ }
389
+ if ( ! defined( 'FS_SDK__SSLVERIFY' ) ) {
390
+ define( 'FS_SDK__SSLVERIFY', false );
391
+ }
freemius/includes/class-freemius-abstract.php CHANGED
@@ -37,9 +37,12 @@
37
  * `$fs->is_registered() && $fs->is_tracking_allowed()`
38
  *
39
  * @since 1.0.1
 
 
 
40
  * @return bool
41
  */
42
- abstract function is_registered();
43
 
44
  /**
45
  * Check if the user skipped connecting the account with Freemius.
@@ -61,68 +64,6 @@
61
 
62
  #endregion
63
 
64
- #----------------------------------------------------------------------------------
65
- #region Usage Tracking
66
- #----------------------------------------------------------------------------------
67
-
68
- /**
69
- * Returns TRUE if the user opted-in and didn't disconnect (opt-out).
70
- *
71
- * @author Leo Fajardo (@leorw)
72
- * @since 1.2.1.5
73
- *
74
- * @return bool
75
- */
76
- abstract function is_tracking_allowed();
77
-
78
- /**
79
- * Returns TRUE if the user never opted-in or manually opted-out.
80
- *
81
- * @author Vova Feldman (@svovaf)
82
- * @since 1.2.1.5
83
- *
84
- * @return bool
85
- */
86
- function is_tracking_prohibited() {
87
- return ! $this->is_registered() || ! $this->is_tracking_allowed();
88
- }
89
-
90
- /**
91
- * Opt-out from usage tracking.
92
- *
93
- * Note: This will not delete the account information but will stop all tracking.
94
- *
95
- * Returns:
96
- * 1. FALSE - If the user never opted-in.
97
- * 2. TRUE - If successfully opted-out.
98
- * 3. object - API Result on failure.
99
- *
100
- * @author Leo Fajardo (@leorw)
101
- * @since 1.2.1.5
102
- *
103
- * @return bool|object
104
- */
105
- abstract function stop_tracking();
106
-
107
- /**
108
- * Opt-in back into usage tracking.
109
- *
110
- * Note: This will only work if the user opted-in previously.
111
- *
112
- * Returns:
113
- * 1. FALSE - If the user never opted-in.
114
- * 2. TRUE - If successfully opted-in back to usage tracking.
115
- * 3. object - API result on failure.
116
- *
117
- * @author Leo Fajardo (@leorw)
118
- * @since 1.2.1.5
119
- *
120
- * @return bool|object
121
- */
122
- abstract function allow_tracking();
123
-
124
- #endregion
125
-
126
  #----------------------------------------------------------------------------------
127
  #region Module Type
128
  #----------------------------------------------------------------------------------
37
  * `$fs->is_registered() && $fs->is_tracking_allowed()`
38
  *
39
  * @since 1.0.1
40
+ *
41
+ * @param bool $ignore_anonymous_state Since 2.5.1
42
+ *
43
  * @return bool
44
  */
45
+ abstract function is_registered( $ignore_anonymous_state = false );
46
 
47
  /**
48
  * Check if the user skipped connecting the account with Freemius.
64
 
65
  #endregion
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  #----------------------------------------------------------------------------------
68
  #region Module Type
69
  #----------------------------------------------------------------------------------
freemius/includes/class-freemius.php CHANGED
@@ -377,6 +377,8 @@
377
  const REASON_DIDNT_WORK_AS_EXPECTED = 14;
378
  const REASON_TEMPORARY_DEACTIVATION = 15;
379
 
 
 
380
  /**
381
  * @author Leo Fajardo (@leorw)
382
  * @since 2.3.1
@@ -392,7 +394,8 @@
392
  */
393
  private $_pricing_js_path = null;
394
 
395
- #endregion
 
396
 
397
  /* Ctor
398
  ------------------------------------------------------------------------------------------------------------------*/
@@ -408,8 +411,10 @@
408
  * @param bool $is_init Since 1.2.1 Is initiation sequence.
409
  */
410
  private function __construct( $module_id, $slug = false, $is_init = false ) {
 
 
411
  if ( $is_init && is_numeric( $module_id ) && is_string( $slug ) ) {
412
- $this->store_id_slug_type_path_map( $module_id, $slug );
413
  }
414
 
415
  $this->_module_id = $module_id;
@@ -424,7 +429,7 @@
424
 
425
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $this->get_unique_affix(), WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
426
 
427
- $this->_plugin_main_file_path = $this->_find_caller_plugin_file( $is_init );
428
  $this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
429
  $this->_plugin_basename = $this->get_plugin_basename();
430
  $this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
@@ -519,7 +524,10 @@
519
  * @author Leo Fajardo (@leorw)
520
  * @since 1.2.2
521
  */
522
- ( is_object( $this->_plugin ) ? $this->_plugin->title : $this->get_plugin_name() ),
 
 
 
523
  $this->get_unique_affix()
524
  );
525
 
@@ -933,82 +941,27 @@
933
  * @param string $sdk_version
934
  */
935
  function _sdk_version_update( $sdk_prev_version, $sdk_version ) {
936
- /**
937
- * @since 1.1.7.3 Fixed unwanted connectivity test cleanup.
938
- */
939
  if ( empty( $sdk_prev_version ) ) {
940
  return;
941
  }
942
 
943
- if ( version_compare( $sdk_prev_version, '2.1.0', '<' ) &&
944
- version_compare( $sdk_version, '2.1.0', '>=' )
945
- ) {
946
- $this->_storage->handle_gdpr_admin_notice = true;
947
- }
948
-
949
- if ( version_compare( $sdk_prev_version, '2.0.0', '<' ) &&
950
- version_compare( $sdk_version, '2.0.0', '>=' )
951
- ) {
952
- $this->migrate_to_subscriptions_collection();
953
-
954
- $this->consolidate_licenses();
955
-
956
- // Clear trial_plan since it's now loaded from the plans collection when needed.
957
- $this->_storage->remove( 'trial_plan', true, false );
958
- }
959
-
960
- if ( version_compare( $sdk_prev_version, '1.2.3', '<' ) &&
961
- version_compare( $sdk_version, '1.2.3', '>=' )
962
- ) {
963
- /**
964
- * Starting from version 1.2.3, paths are stored as relative instead of absolute and some of them can be
965
- * invalid.
966
- *
967
- * @author Leo Fajardo (@leorw)
968
- */
969
- $this->remove_invalid_paths();
970
- }
971
-
972
- if ( version_compare( $sdk_prev_version, '1.1.5', '<' ) &&
973
- version_compare( $sdk_version, '1.1.5', '>=' )
974
  ) {
975
- // On version 1.1.5 merged connectivity and is_on data.
976
- if ( isset( $this->_storage->connectivity_test ) ) {
977
- if ( ! isset( $this->_storage->is_on ) ) {
978
- unset( $this->_storage->connectivity_test );
979
- } else {
980
- $connectivity_data = $this->_storage->connectivity_test;
981
- $connectivity_data['is_active'] = $this->_storage->is_on['is_active'];
982
- $connectivity_data['timestamp'] = $this->_storage->is_on['timestamp'];
983
-
984
- // Override.
985
- $this->_storage->connectivity_test = $connectivity_data;
986
 
987
- // Remove previous structure.
988
- unset( $this->_storage->is_on );
989
- }
990
 
 
991
  }
992
  }
993
-
994
- if (
995
- version_compare( $sdk_prev_version, '2.2.1', '<' ) &&
996
- version_compare( $sdk_version, '2.2.1', '>=' )
997
- ) {
998
- /**
999
- * Clear the file cache without storing the previous path since it could be a wrong path. For example,
1000
- * in the versions of the SDK lower than 2.2.1, it's possible for the path of an add-on to be the same
1001
- * as the parent plugin's when the add-on was auto-installed since the relevant method names were not
1002
- * skipped in the logic that determines the right path in the `get_caller_main_file_and_type` method
1003
- * (e.g. `try_activate_plugin`). Since it was an auto-installation, the caller was the parent plugin
1004
- * and so its path was used. In case the stored path is wrong, clearing the cache will resolve issues
1005
- * related to data mix-up between plugins (e.g. titles and versions of an add-on and its parent plugin).
1006
- *
1007
- * @author Leo Fajardo (@leorw)
1008
- * @since 2.2.1
1009
- */
1010
- $this->clear_module_main_file_cache( false );
1011
- }
1012
  }
1013
 
1014
  /**
@@ -1059,102 +1012,6 @@
1059
  }
1060
  }
1061
 
1062
- /**
1063
- * @author Leo Fajardo (@leorw)
1064
- * @since 2.0.0
1065
- */
1066
- private function migrate_to_subscriptions_collection() {
1067
- if ( ! is_object( $this->_site ) ) {
1068
- return;
1069
- }
1070
-
1071
- if ( isset( $this->_storage->subscription ) && is_object( $this->_storage->subscription ) ) {
1072
- $this->_storage->subscriptions = array( fs_get_entity( $this->_storage->subscription, FS_Subscription::get_class_name() ) );
1073
- }
1074
- }
1075
-
1076
- /**
1077
- * @author Leo Fajardo (@leorw)
1078
- * @since 2.0.0
1079
- */
1080
- private function consolidate_licenses() {
1081
- $plugin_licenses = self::get_account_option( 'licenses', WP_FS__MODULE_TYPE_PLUGIN );
1082
- if ( isset( $plugin_licenses[ $this->_slug ] ) ) {
1083
- $plugin_licenses = $plugin_licenses[ $this->_slug ];
1084
- } else {
1085
- $plugin_licenses = array();
1086
- }
1087
-
1088
- $theme_licenses = self::get_account_option( 'licenses', WP_FS__MODULE_TYPE_THEME );
1089
- if ( isset( $theme_licenses[ $this->_slug ] ) ) {
1090
- $theme_licenses = $theme_licenses[ $this->_slug ];
1091
- } else {
1092
- $theme_licenses = array();
1093
- }
1094
-
1095
- if ( empty( $plugin_licenses ) && empty( $theme_licenses ) ) {
1096
- return;
1097
- }
1098
-
1099
- $all_licenses = array();
1100
- $user_id_license_ids_map = array();
1101
-
1102
- foreach ( $plugin_licenses as $user_id => $user_licenses ) {
1103
- if ( is_array( $user_licenses ) ) {
1104
- if ( ! isset( $user_license_ids[ $user_id ] ) ) {
1105
- $user_id_license_ids_map[ $user_id ] = array();
1106
- }
1107
-
1108
- foreach ( $user_licenses as $user_license ) {
1109
- $all_licenses[] = $user_license;
1110
- $user_id_license_ids_map[ $user_id ][] = $user_license->id;
1111
- }
1112
- }
1113
- }
1114
-
1115
- foreach ( $theme_licenses as $user_id => $user_licenses ) {
1116
- if ( is_array( $user_licenses ) ) {
1117
- if ( ! isset( $user_license_ids[ $user_id ] ) ) {
1118
- $user_id_license_ids_map[ $user_id ] = array();
1119
- }
1120
-
1121
- foreach ( $user_licenses as $user_license ) {
1122
- $all_licenses[] = $user_license;
1123
- $user_id_license_ids_map[ $user_id ][] = $user_license->id;
1124
- }
1125
- }
1126
- }
1127
-
1128
- self::store_user_id_license_ids_map(
1129
- $user_id_license_ids_map,
1130
- $this->_module_id
1131
- );
1132
-
1133
- $this->_store_licenses( true, $this->_module_id, $all_licenses );
1134
- }
1135
-
1136
- /**
1137
- * Remove invalid paths.
1138
- *
1139
- * @author Leo Fajardo (@leorw)
1140
- * @since 1.2.3
1141
- */
1142
- private function remove_invalid_paths() {
1143
- // Remove invalid path that is still associated with the current slug if there's any.
1144
- $file_slug_map = self::$_accounts->get_option( 'file_slug_map', array() );
1145
- foreach ( $file_slug_map as $plugin_basename => $slug ) {
1146
- if ( $slug === $this->_slug &&
1147
- $plugin_basename !== $this->_plugin_basename &&
1148
- ! file_exists( $this->get_absolute_path( $plugin_basename ) )
1149
- ) {
1150
- unset( $file_slug_map[ $plugin_basename ] );
1151
- self::$_accounts->set_option( 'file_slug_map', $file_slug_map, true );
1152
-
1153
- break;
1154
- }
1155
- }
1156
- }
1157
-
1158
  /**
1159
  * @author Vova Feldman (@svovaf)
1160
  * @since 1.2.2.7
@@ -1491,46 +1348,6 @@
1491
  }
1492
  }
1493
 
1494
- /**
1495
- * Add special parameter to WP admin AJAX calls so when we
1496
- * process AJAX calls we can identify its source properly.
1497
- *
1498
- * @author Leo Fajardo (@leorw)
1499
- * @since 2.0.0
1500
- */
1501
- static function _enrich_ajax_url() {
1502
- $admin_param = is_network_admin() ?
1503
- '_fs_network_admin' :
1504
- '_fs_blog_admin';
1505
- ?>
1506
- <script type="text/javascript">
1507
- (function ($) {
1508
- $(document).ajaxSend(function (event, jqxhr, settings) {
1509
- if (settings.url &&
1510
- -1 < settings.url.indexOf('admin-ajax.php') &&
1511
- ! ( settings.url.indexOf( '<?php echo $admin_param ?>' ) > 0 )
1512
- ) {
1513
- if (
1514
- 'string' === typeof settings.data &&
1515
- settings.data.indexOf( 'action=heartbeat' ) > 0
1516
- ) {
1517
- return;
1518
- }
1519
-
1520
- if (settings.url.indexOf('?') > 0) {
1521
- settings.url += '&';
1522
- } else {
1523
- settings.url += '?';
1524
- }
1525
-
1526
- settings.url += '<?php echo $admin_param ?>=true';
1527
- }
1528
- });
1529
- })(jQuery);
1530
- </script>
1531
- <?php
1532
- }
1533
-
1534
  /**
1535
  * Opens the support forum subemenu item in a new browser page.
1536
  *
@@ -1641,8 +1458,10 @@
1641
  }
1642
 
1643
  if ( $this->is_plugin() ) {
1644
- if ( $this->_is_network_active ) {
1645
  add_action( 'wpmu_new_blog', array( $this, '_after_new_blog_callback' ), 10, 6 );
 
 
1646
  }
1647
 
1648
  register_deactivation_hook( $this->_plugin_main_file_path, array( &$this, '_deactivate_plugin_hook' ) );
@@ -1652,7 +1471,12 @@
1652
  add_action( 'deactivate_blog', array( &$this, '_after_site_deactivated_callback' ) );
1653
  add_action( 'archive_blog', array( &$this, '_after_site_deactivated_callback' ) );
1654
  add_action( 'make_spam_blog', array( &$this, '_after_site_deactivated_callback' ) );
1655
- add_action( 'deleted_blog', array( &$this, '_after_site_deleted_callback' ), 10, 2 );
 
 
 
 
 
1656
 
1657
  add_action( 'activate_blog', array( &$this, '_after_site_reactivated_callback' ) );
1658
  add_action( 'unarchive_blog', array( &$this, '_after_site_reactivated_callback' ) );
@@ -1677,6 +1501,7 @@
1677
  add_action( 'admin_init', array( &$this, '_add_premium_version_upgrade_selection' ) );
1678
  add_action( 'admin_init', array( &$this, '_add_beta_mode_update_handler' ) );
1679
  add_action( 'admin_init', array( &$this, '_add_user_change_option' ) );
 
1680
 
1681
  $this->add_ajax_action( 'update_billing', array( &$this, '_update_billing_ajax_action' ) );
1682
  $this->add_ajax_action( 'start_trial', array( &$this, '_start_trial_ajax_action' ) );
@@ -2048,7 +1873,13 @@
2048
  return;
2049
  }
2050
 
2051
- $this->_add_tracking_links();
 
 
 
 
 
 
2052
 
2053
  if ( self::is_plugins_page() && $this->is_plugin() ) {
2054
  $this->hook_plugin_action_links();
@@ -2094,20 +1925,27 @@
2094
  /**
2095
  * Leverage backtrace to find caller plugin file path.
2096
  *
2097
- * @author Vova Feldman (@svovaf)
2098
- * @since 1.0.6
2099
- *
2100
- * @param bool $is_init Is initiation sequence.
2101
  *
2102
  * @return string
 
 
 
2103
  */
2104
- private function _find_caller_plugin_file( $is_init = false ) {
2105
  // Try to load the cached value of the file path.
2106
  if ( isset( $this->_storage->plugin_main_file ) ) {
2107
  $plugin_main_file = $this->_storage->plugin_main_file;
2108
  if ( ! empty( $plugin_main_file->path ) ) {
2109
  $absolute_path = $this->get_absolute_path( $plugin_main_file->path );
2110
  if ( file_exists( $absolute_path ) ) {
 
 
 
 
 
 
2111
  return $absolute_path;
2112
  }
2113
  }
@@ -2148,12 +1986,11 @@
2148
  * Only the original instantiator that calls dynamic_init can modify the module's path.
2149
  */
2150
  // Find caller module.
2151
- $id_slug_type_path_map = self::$_accounts->get_option( 'id_slug_type_path_map', array() );
2152
  $this->_storage->plugin_main_file = (object) array(
2153
- 'path' => $id_slug_type_path_map[ $this->_module_id ]['path'],
2154
  );
2155
 
2156
- return $this->get_absolute_path( $id_slug_type_path_map[ $this->_module_id ]['path'] );
2157
  }
2158
 
2159
  /**
@@ -2215,6 +2052,8 @@
2215
  * @param number $module_id
2216
  * @param string $slug
2217
  *
 
 
2218
  * @since 1.2.2
2219
  */
2220
  private function store_id_slug_type_path_map( $module_id, $slug ) {
@@ -2236,20 +2075,52 @@
2236
  $store_option = true;
2237
  }
2238
 
2239
- if ( empty( $id_slug_type_path_map[ $module_id ]['path'] ) ||
2240
- /**
2241
- * This verification is for cases when suddenly the same module
2242
- * is installed but with a different folder name.
2243
- *
2244
- * @author Vova Feldman (@svovaf)
2245
- * @since 1.2.3
2246
- */
2247
- ! file_exists( $this->get_absolute_path(
2248
- $id_slug_type_path_map[ $module_id ]['path'],
2249
- $id_slug_type_path_map[ $module_id ]['type']
2250
- ) )
2251
- ) {
2252
- $caller_main_file_and_type = $this->get_caller_main_file_and_type();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2253
 
2254
  $id_slug_type_path_map[ $module_id ]['type'] = $caller_main_file_and_type->module_type;
2255
  $id_slug_type_path_map[ $module_id ]['path'] = $caller_main_file_and_type->path;
@@ -2260,6 +2131,8 @@
2260
  if ( $store_option ) {
2261
  self::$_accounts->set_option( 'id_slug_type_path_map', $id_slug_type_path_map, true );
2262
  }
 
 
2263
  }
2264
 
2265
  /**
@@ -2273,8 +2146,10 @@
2273
  * add-ons are relying on loading the SDK from the parent module, and also allows themes including the
2274
  * SDK an internal file instead of directly from functions.php.
2275
  * @since 1.2.1.7 Knows how to handle cases when an add-on includes the parent module logic.
 
 
2276
  */
2277
- private function get_caller_main_file_and_type() {
2278
  self::require_plugin_essentials();
2279
 
2280
  $all_plugins = fs_get_plugins( true );
@@ -2413,10 +2288,12 @@
2413
  }
2414
  }
2415
 
2416
- return (object) array(
2417
  'module_type' => $module_type,
2418
  'path' => $caller_file_candidate
2419
  );
 
 
2420
  }
2421
 
2422
  #----------------------------------------------------------------------------------
@@ -2433,6 +2310,13 @@
2433
  * @since 1.1.2
2434
  */
2435
  function _add_deactivation_feedback_dialog_box() {
 
 
 
 
 
 
 
2436
  $subscription_cancellation_dialog_box_template_params = $this->apply_filters( 'show_deactivation_subscription_cancellation', true ) ?
2437
  $this->_get_subscription_cancellation_dialog_box_template_params() :
2438
  array();
@@ -2440,7 +2324,7 @@
2440
  /**
2441
  * @since 2.3.0 Developers can optionally hide the deactivation feedback form using the 'show_deactivation_feedback_form' filter.
2442
  */
2443
- $show_deactivation_feedback_form = true;
2444
  if ( $this->has_filter( 'show_deactivation_feedback_form' ) ) {
2445
  $show_deactivation_feedback_form = $this->apply_filters( 'show_deactivation_feedback_form', true );
2446
  } else if ( $this->is_addon() ) {
@@ -2545,7 +2429,7 @@
2545
  $reason_temporary_deactivation = array(
2546
  'id' => self::REASON_TEMPORARY_DEACTIVATION,
2547
  'text' => sprintf(
2548
- $this->get_text_inline( "It's a temporary %s. I'm just debugging an issue.", 'reason-temporary-x' ),
2549
  strtolower( $this->is_plugin() ?
2550
  $this->get_text_inline( 'Deactivation', 'deactivation' ) :
2551
  $this->get_text_inline( 'Theme Switch', 'theme-switch' )
@@ -2710,6 +2594,14 @@
2710
 
2711
  $this->_storage->store( 'uninstall_reason', $reason );
2712
 
 
 
 
 
 
 
 
 
2713
  /**
2714
  * If the module type is "theme", trigger the uninstall event here (on theme deactivation) since themes do
2715
  * not support uninstall hook.
@@ -2731,6 +2623,73 @@
2731
  exit;
2732
  }
2733
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2734
  /**
2735
  * @author Leo Fajardo (@leorw)
2736
  * @since 2.1.4
@@ -2927,6 +2886,13 @@
2927
  return self::instance( $addon_id );
2928
  }
2929
 
 
 
 
 
 
 
 
2930
  #endregion ------------------------------------------------------------------
2931
 
2932
  /**
@@ -3437,7 +3403,9 @@
3437
  add_action( 'plugins_loaded', array( 'Freemius', '_load_textdomain' ), 1 );
3438
  }
3439
 
3440
- add_action( 'admin_footer', array( 'Freemius', '_enrich_ajax_url' ) );
 
 
3441
  add_action( 'admin_footer', array( 'Freemius', '_open_support_forum_in_new_page' ) );
3442
 
3443
  if ( self::is_plugins_page() || self::is_themes_page() ) {
@@ -3456,48 +3424,197 @@
3456
  self::$_statics_loaded = true;
3457
  }
3458
 
 
 
 
 
3459
  /**
3460
  * @author Leo Fajardo (@leorw)
 
3461
  *
3462
- * @since 2.1.3
 
 
3463
  */
3464
- private static function migrate_options_to_network() {
3465
- self::migrate_accounts_to_network();
3466
-
3467
- // Migrate API options from site level to network level.
3468
- $api_network_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true, true );
3469
- $api_network_options->migrate_to_network();
3470
-
3471
- // Migrate API cache to network level storage.
3472
- FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME )->migrate_to_network();
3473
 
3474
- self::$_accounts->set_option( 'ms_migration_complete', true, true );
3475
  }
3476
 
3477
- #----------------------------------------------------------------------------------
3478
- #region Localization
3479
- #----------------------------------------------------------------------------------
3480
-
3481
  /**
3482
- * Load framework's text domain.
 
3483
  *
3484
- * @author Vova Feldman (@svovaf)
3485
- * @since 1.2.1
3486
  */
3487
- static function _load_textdomain() {
3488
- if ( ! is_admin() ) {
3489
- return;
3490
  }
3491
 
3492
- global $fs_active_plugins;
3493
 
3494
- // Works both for plugins and themes.
3495
- load_plugin_textdomain(
3496
- 'freemius',
3497
- false,
3498
- $fs_active_plugins->newest->sdk_path . '/languages/'
3499
- );
3500
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3501
 
3502
  #endregion
3503
 
@@ -3692,6 +3809,10 @@
3692
 
3693
  switch_to_blog( $current_blog_id );
3694
  }
 
 
 
 
3695
  } else if ( fs_request_is_action( 'simulate_trial' ) ) {
3696
  check_admin_referer( 'simulate_trial' );
3697
 
@@ -3740,55 +3861,69 @@
3740
  }
3741
 
3742
  /**
3743
- * @author Vova Feldman (@svovaf)
3744
- * @since 1.0.8
 
 
3745
  */
3746
- static function _debug_page_render() {
3747
  self::$_static_logger->entrance();
3748
 
 
 
 
 
 
 
 
3749
  if ( ! is_multisite() ) {
3750
- $all_plugins_installs = self::get_all_sites( WP_FS__MODULE_TYPE_PLUGIN );
3751
- $all_themes_installs = self::get_all_sites( WP_FS__MODULE_TYPE_THEME );
 
 
 
 
 
3752
  } else {
3753
  $sites = self::get_sites();
3754
 
3755
- $all_plugins_installs = array();
3756
- $all_themes_installs = array();
3757
-
3758
  foreach ( $sites as $site ) {
3759
  $blog_id = self::get_site_blog_id( $site );
3760
 
3761
- $plugins_installs = self::get_all_sites( WP_FS__MODULE_TYPE_PLUGIN, $blog_id );
3762
-
3763
- foreach ( $plugins_installs as $slug => $install ) {
3764
- if ( ! isset( $all_plugins_installs[ $slug ] ) ) {
3765
- $all_plugins_installs[ $slug ] = array();
3766
- }
3767
-
3768
- $install->blog_id = $blog_id;
3769
 
3770
- $all_plugins_installs[ $slug ][] = $install;
3771
- }
 
 
3772
 
3773
- $themes_installs = self::get_all_sites( WP_FS__MODULE_TYPE_THEME, $blog_id );
3774
 
3775
- foreach ( $themes_installs as $slug => $install ) {
3776
- if ( ! isset( $all_themes_installs[ $slug ] ) ) {
3777
- $all_themes_installs[ $slug ] = array();
3778
  }
3779
 
3780
- $install->blog_id = $blog_id;
3781
-
3782
- $all_themes_installs[ $slug ][] = $install;
3783
  }
3784
  }
3785
  }
3786
 
 
 
 
 
 
 
 
 
 
 
 
 
3787
  $licenses_by_module_type = self::get_all_licenses_by_module_type();
3788
 
3789
  $vars = array(
3790
- 'plugin_sites' => $all_plugins_installs,
3791
- 'theme_sites' => $all_themes_installs,
3792
  'users' => self::get_all_users(),
3793
  'addons' => self::get_all_addons(),
3794
  'account_addons' => self::get_all_account_addons(),
@@ -3820,6 +3955,10 @@
3820
  function is_on() {
3821
  self::$_static_logger->entrance();
3822
 
 
 
 
 
3823
  if ( isset( $this->_is_on ) ) {
3824
  return $this->_is_on;
3825
  }
@@ -3908,18 +4047,24 @@
3908
 
3909
  $is_update = $this->apply_filters( 'is_plugin_update', $this->is_plugin_update() );
3910
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3911
  return $this->get_api_plugin_scope()->ping(
3912
  $this->get_anonymous_id( $blog_id ),
3913
- array(
3914
- 'is_update' => json_encode( $is_update ),
3915
- 'version' => $version,
3916
- 'sdk' => $this->version,
3917
- 'is_admin' => json_encode( is_admin() ),
3918
- 'is_ajax' => json_encode( self::is_ajax() ),
3919
- 'is_cron' => json_encode( self::is_cron() ),
3920
- 'is_gdpr_test' => $is_gdpr_test,
3921
- 'is_http' => json_encode( WP_FS__IS_HTTP_REQUEST ),
3922
- )
3923
  );
3924
  }
3925
 
@@ -4056,7 +4201,7 @@
4056
  $unique_id = self::$_accounts->get_option( 'unique_id', null, $blog_id );
4057
 
4058
  if ( empty( $unique_id ) || ! is_string( $unique_id ) ) {
4059
- $key = fs_strip_url_protocol( get_site_url( $blog_id ) );
4060
 
4061
  $secure_auth = defined( 'SECURE_AUTH_KEY' ) ? SECURE_AUTH_KEY : '';
4062
  if ( empty( $secure_auth ) ||
@@ -4085,6 +4230,17 @@
4085
  return $unique_id;
4086
  }
4087
 
 
 
 
 
 
 
 
 
 
 
 
4088
  /**
4089
  * @author Vova Feldman (@svovaf)
4090
  * @since 1.1.7.4
@@ -4233,11 +4389,16 @@
4233
  $install_previous_desc = $this->esc_html_inline( 'Uninstall this version and install the previous one.', 'install-previous-desc' );
4234
  $fix_issue_title = $this->esc_html_inline( 'Yes - I\'m giving you a chance to fix it', 'fix-issue-title' );
4235
  $fix_issue_desc = $this->esc_html_inline( '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.', 'fix-issue-desc' );
4236
- /* translators: %s: product title (e.g. "Awesome Plugin" requires an access to...) */
4237
- $x_requires_access_to_api = $this->esc_html_inline( '%s requires an access to our API.', 'x-requires-access-to-api' );
4238
  $sysadmin_title = $this->esc_html_inline( 'I\'m a system administrator', 'sysadmin-title' );
4239
  $happy_to_resolve_issue_asap = $this->esc_html_inline( '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.', 'happy-to-resolve-issue-asap' );
4240
 
 
 
 
 
 
4241
  $message = false;
4242
  if ( is_object( $api_result ) &&
4243
  isset( $api_result->error ) &&
@@ -4869,7 +5030,7 @@
4869
 
4870
  /**
4871
  * This should be executed even if Freemius is off for the core module,
4872
- * otherwise, the add-ons dialogbox won't work properly. This is esepcially
4873
  * relevant when the developer decided to turn FS off for existing users.
4874
  *
4875
  * @author Vova Feldman (@svovaf)
@@ -4907,22 +5068,25 @@
4907
  * @since 1.1.7.3
4908
  *
4909
  */
4910
- if ( $this->is_registered() ) {
4911
- if ( ! $this->is_sync_cron_on() && $this->is_tracking_allowed() ) {
4912
- $this->schedule_sync_cron();
4913
- }
4914
  }
4915
 
4916
  /**
4917
  * Check if requested for manual blocking background sync.
4918
  */
4919
  if ( fs_request_has( 'background_sync' ) ) {
 
 
 
4920
  $this->run_manual_sync();
4921
  }
4922
  }
4923
  }
4924
 
4925
  if ( $this->is_registered() ) {
 
 
4926
  $this->hook_callback_to_install_sync();
4927
  }
4928
 
@@ -4937,6 +5101,28 @@
4937
  }
4938
 
4939
  if ( $this->is_user_in_admin() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4940
  if ( $this->is_addon() ) {
4941
  if ( ! $this->is_parent_plugin_installed() ) {
4942
  $parent_name = $this->get_option( $plugin_info, 'parent_name', null );
@@ -5041,7 +5227,7 @@
5041
  * because the updater has some logic that needs to be executed
5042
  * during AJAX calls.
5043
  *
5044
- * Currently we need to hook to the `http_request_host_is_external` filter.
5045
  * In the future, there might be additional logic added.
5046
  *
5047
  * @author Vova Feldman
@@ -5060,7 +5246,8 @@
5060
  */
5061
  ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this->premium_plugin_basename() ) ) )
5062
  ) &&
5063
- $this->has_release_on_freemius()
 
5064
  ) {
5065
  FS_Plugin_Updater::instance( $this );
5066
  }
@@ -5129,150 +5316,70 @@
5129
  }
5130
 
5131
  /**
5132
- * @author Leo Fajardo (@leorw)
 
 
5133
  *
5134
- * @since 1.2.1.5
5135
  */
5136
- function _stop_tracking_callback() {
5137
  $this->_logger->entrance();
5138
 
5139
- $this->check_ajax_referer( 'stop_tracking' );
5140
-
5141
- $result = $this->stop_tracking( fs_is_network_admin() );
5142
-
5143
- if ( true === $result ) {
5144
- self::shoot_ajax_success();
5145
- }
5146
-
5147
- $this->_logger->api_error( $result );
5148
-
5149
- self::shoot_ajax_failure(
5150
- sprintf( $this->get_text_inline( 'Unexpected API error. Please contact the %s\'s author with the following error.', 'unexpected-api-error' ), $this->_module_type ) .
5151
- ( $this->is_api_error( $result ) && isset( $result->error ) ?
5152
- $result->error->message :
5153
- var_export( $result, true ) )
5154
  );
5155
- }
5156
-
5157
- /**
5158
- * @author Leo Fajardo (@leorw)
5159
- * @since 1.2.1.5
5160
- */
5161
- function _allow_tracking_callback() {
5162
- $this->_logger->entrance();
5163
-
5164
- $this->check_ajax_referer( 'allow_tracking' );
5165
 
5166
- $result = $this->allow_tracking( fs_is_network_admin() );
5167
-
5168
- if ( true === $result ) {
5169
- self::shoot_ajax_success();
5170
  }
5171
 
5172
- $this->_logger->api_error( $result );
5173
-
5174
- self::shoot_ajax_failure(
5175
- sprintf( $this->get_text_inline( 'Unexpected API error. Please contact the %s\'s author with the following error.', 'unexpected-api-error' ), $this->_module_type ) .
5176
- ( $this->is_api_error( $result ) && isset( $result->error ) ?
5177
- $result->error->message :
5178
- var_export( $result, true ) )
5179
- );
5180
- }
5181
-
5182
- /**
5183
- * Opt-out from usage tracking.
5184
- *
5185
- * Note: This will not delete the account information but will stop all tracking.
5186
- *
5187
- * Returns:
5188
- * 1. FALSE - If the user never opted-in.
5189
- * 2. TRUE - If successfully opted-out.
5190
- * 3. object - API result on failure.
5191
- *
5192
- * @author Leo Fajardo (@leorw)
5193
- * @since 1.2.1.5
5194
- *
5195
- * @return bool|object
5196
- */
5197
- function stop_site_tracking() {
5198
- $this->_logger->entrance();
5199
-
5200
- if ( ! $this->is_registered() ) {
5201
- // User never opted-in.
5202
- return false;
5203
- }
5204
 
5205
- if ( $this->is_tracking_prohibited() ) {
5206
- // Already disconnected.
5207
- return true;
5208
  }
5209
 
5210
- // Send update to FS.
5211
- $result = $this->get_api_site_scope()->call( '/?fields=is_disconnected', 'put', array(
5212
- 'is_disconnected' => true
5213
- ) );
5214
-
5215
- if ( ! $this->is_api_result_entity( $result ) ||
5216
- ! isset( $result->is_disconnected ) ||
5217
- ! $result->is_disconnected
5218
  ) {
5219
  $this->_logger->api_error( $result );
5220
 
5221
  return $result;
5222
  }
5223
 
5224
- $this->_site->is_disconnected = $result->is_disconnected;
5225
- $this->_store_site();
5226
-
5227
- $this->clear_sync_cron();
5228
-
5229
- // Successfully disconnected.
5230
  return true;
5231
  }
5232
 
5233
  /**
5234
- * Opt-out network from usage tracking.
 
 
5235
  *
5236
- * Note: This will not delete the account information but will stop all tracking.
5237
- *
5238
- * Returns:
5239
- * 1. FALSE - If the user never opted-in.
5240
- * 2. TRUE - If successfully opted-out.
5241
- * 3. object - API result on failure.
5242
- *
5243
- * @author Leo Fajardo (@leorw)
5244
- * @since 1.2.1.5
5245
- *
5246
- * @return bool|object
5247
  */
5248
- function stop_network_tracking() {
 
 
 
 
5249
  $this->_logger->entrance();
5250
 
5251
- if ( ! $this->is_registered() ) {
5252
- // User never opted-in.
5253
- return false;
5254
- }
5255
-
5256
  $install_id_2_blog_id = array();
5257
- $installs_map = $this->get_blog_install_map();
5258
-
5259
- $opt_out_all = true;
5260
 
5261
- $params = array();
5262
- foreach ( $installs_map as $blog_id => $install ) {
5263
- if ( $install->is_tracking_prohibited() ) {
5264
- // Already opted-out.
5265
- continue;
5266
- }
5267
 
 
5268
  if ( $this->is_site_delegated_connection( $blog_id ) ) {
5269
- // Opt-out only from non-delegated installs.
5270
- $opt_out_all = false;
5271
  continue;
5272
  }
5273
 
5274
- $params[] = array( 'id' => $install->id );
5275
-
5276
  $install_id_2_blog_id[ $install->id ] = $blog_id;
5277
  }
5278
 
@@ -5280,171 +5387,188 @@
5280
  return true;
5281
  }
5282
 
5283
- $params[] = array( 'is_disconnected' => true );
 
 
 
 
5284
 
5285
  // Send update to FS.
5286
- $result = $this->get_current_or_network_user_api_scope()->call( "/plugins/{$this->_module_id}/installs.json", 'put', $params );
 
 
 
 
5287
 
5288
- if ( ! $this->is_api_result_object( $result, 'installs' ) ) {
5289
  $this->_logger->api_error( $result );
5290
 
5291
  return $result;
5292
  }
5293
 
5294
- foreach ( $result->installs as $r_install ) {
5295
- $blog_id = $install_id_2_blog_id[ $r_install->id ];
5296
- $install = $installs_map[ $blog_id ];
5297
- $install->is_disconnected = $r_install->is_disconnected;
5298
- $this->_store_site( true, $blog_id, $install );
5299
- }
5300
-
5301
- $this->clear_sync_cron( $opt_out_all );
5302
-
5303
- // Successfully disconnected.
5304
  return true;
5305
  }
5306
 
5307
  /**
5308
- * Opt-out from usage tracking.
5309
- *
5310
- * Note: This will not delete the account information but will stop all tracking.
5311
- *
5312
- * Returns:
5313
- * 1. FALSE - If the user never opted-in.
5314
- * 2. TRUE - If successfully opted-out.
5315
- * 3. object - API result on failure.
5316
- *
5317
- * @author Leo Fajardo (@leorw)
5318
- * @since 1.2.1.5
5319
- *
5320
- * @param bool $is_network_action
5321
  *
5322
- * @return bool|object
5323
  */
5324
- function stop_tracking( $is_network_action = false ) {
5325
- $this->_logger->entrance();
 
 
 
 
 
 
 
 
 
 
 
 
5326
 
5327
- return $is_network_action ?
5328
- $this->stop_network_tracking() :
5329
- $this->stop_site_tracking();
5330
  }
5331
 
5332
  /**
5333
- * Opt-in back into usage tracking.
5334
- *
5335
- * Note: This will only work if the user opted-in previously.
5336
- *
5337
- * Returns:
5338
- * 1. FALSE - If the user never opted-in.
5339
- * 2. TRUE - If successfully opted-in back to usage tracking.
5340
- * 3. object - API result on failure.
5341
- *
5342
- * @author Leo Fajardo (@leorw)
5343
- * @since 1.2.1.5
5344
- *
5345
- * @return bool|object
5346
  */
5347
- function allow_site_tracking() {
5348
  $this->_logger->entrance();
5349
 
5350
- if ( ! $this->is_registered() ) {
5351
- // User never opted-in.
5352
- return false;
5353
- }
5354
 
5355
- if ( $this->is_tracking_allowed() ) {
5356
- // Tracking already allowed.
5357
- return true;
5358
  }
5359
 
5360
- $result = $this->get_api_site_scope()->call( '/?is_disconnected', 'put', array(
5361
- 'is_disconnected' => false
5362
- ) );
5363
-
5364
- if ( ! $this->is_api_result_entity( $result ) ||
5365
- ! isset( $result->is_disconnected ) ||
5366
- $result->is_disconnected
5367
- ) {
5368
- $this->_logger->api_error( $result );
5369
 
5370
- return $result;
 
5371
  }
5372
 
5373
- $this->_site->is_disconnected = $result->is_disconnected;
5374
- $this->_store_site();
5375
 
5376
- $this->schedule_sync_cron();
5377
 
5378
- // Successfully reconnected.
5379
- return true;
 
 
 
5380
  }
5381
 
5382
  /**
5383
- * Opt-in network back into usage tracking.
5384
- *
5385
- * Note: This will only work if the user opted-in previously.
5386
- *
5387
- * Returns:
5388
- * 1. FALSE - If the user never opted-in.
5389
- * 2. TRUE - If successfully opted-in back to usage tracking.
5390
- * 3. object - API result on failure.
5391
- *
5392
- * @author Leo Fajardo (@leorw)
5393
- * @since 1.2.1.5
5394
  *
5395
- * @return bool|object
5396
  */
5397
- function allow_network_tracking() {
5398
- $this->_logger->entrance();
5399
-
5400
- if ( ! $this->is_registered() ) {
5401
  // User never opted-in.
5402
  return false;
5403
  }
5404
 
5405
- $install_id_2_blog_id = array();
5406
- $installs_map = $this->get_blog_install_map();
5407
-
5408
- $params = array();
5409
- foreach ( $installs_map as $blog_id => $install ) {
5410
- if ( $install->is_tracking_allowed() ) {
5411
- continue;
5412
- }
5413
-
5414
- $params[] = array( 'id' => $install->id );
5415
-
5416
- $install_id_2_blog_id[ $install->id ] = $blog_id;
5417
  }
5418
 
5419
- if ( empty( $install_id_2_blog_id ) ) {
5420
- return true;
 
 
 
 
 
 
 
 
5421
  }
5422
 
5423
- $params[] = array( 'is_disconnected' => false );
 
5424
 
5425
- // Send update to FS.
5426
- $result = $this->get_current_or_network_user_api_scope()->call( "/plugins/{$this->_module_id}/installs.json", 'put', $params );
 
 
 
 
 
 
 
 
 
 
5427
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5428
 
5429
- if ( ! $this->is_api_result_object( $result, 'installs' ) ) {
5430
- $this->_logger->api_error( $result );
 
5431
 
5432
- return $result;
5433
- }
 
 
 
 
 
5434
 
5435
- foreach ( $result->installs as $r_install ) {
5436
- $blog_id = $install_id_2_blog_id[ $r_install->id ];
5437
- $install = $installs_map[ $blog_id ];
5438
- $install->is_disconnected = $r_install->is_disconnected;
5439
- $this->_store_site( true, $blog_id, $install );
5440
  }
5441
 
5442
- $this->schedule_sync_cron();
 
 
 
 
5443
 
5444
- // Successfully reconnected.
5445
  return true;
5446
  }
5447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5448
  /**
5449
  * Opt-in back into usage tracking.
5450
  *
@@ -5458,16 +5582,18 @@
5458
  * @author Leo Fajardo (@leorw)
5459
  * @since 1.2.1.5
5460
  *
5461
- * @param bool $is_network_action
5462
  *
5463
  * @return bool|object
5464
  */
5465
- function allow_tracking( $is_network_action = false ) {
5466
  $this->_logger->entrance();
5467
 
5468
- return $is_network_action ?
5469
- $this->allow_network_tracking() :
5470
- $this->allow_site_tracking();
 
 
5471
  }
5472
 
5473
  /**
@@ -5488,8 +5614,7 @@
5488
 
5489
  if ( ! fs_is_network_admin() || $is_context_single_site ) {
5490
  if ( $this->is_tracking_prohibited() ) {
5491
- $this->_site->is_disconnected = false;
5492
- $this->_store_site();
5493
  }
5494
  } else {
5495
  $installs_map = $this->get_blog_install_map();
@@ -5497,73 +5622,69 @@
5497
  /**
5498
  * @var FS_Site $install
5499
  */
5500
- if ( $install->is_tracking_prohibited() ) {
5501
- $install->is_disconnected = false;
5502
- $this->_store_site( true, $blog_id, $install );
5503
  }
5504
  }
5505
  }
5506
  }
5507
 
5508
  /**
5509
- * @author Vova Feldman (@svovaf)
5510
- * @since 2.3.2
5511
  *
5512
- * @return bool
 
 
 
 
5513
  */
5514
- function is_extensions_tracking_allowed() {
5515
- return ( true === $this->apply_filters(
5516
- 'is_extensions_tracking_allowed',
5517
- $this->_storage->get( 'is_extensions_tracking_allowed', null )
5518
- ) );
5519
- }
5520
 
5521
- /**
5522
- * @author Vova Feldman (@svovaf)
5523
- * @since 2.3.2
5524
- */
5525
- function _update_tracking_permission_callback() {
5526
- $this->_logger->entrance();
5527
 
5528
- $this->check_ajax_referer( 'update_tracking_permission' );
 
 
5529
 
5530
- $is_enabled = fs_request_get_bool( 'is_enabled', null );
 
 
 
 
 
 
 
5531
 
5532
- if ( ! is_bool( $is_enabled ) ) {
5533
- self::shoot_ajax_failure();
 
5534
  }
5535
 
5536
- $permission = fs_request_get( 'permission' );
 
 
 
 
 
 
 
 
 
 
 
5537
 
5538
- switch ( $permission ) {
5539
- case 'extensions':
5540
- $this->update_extensions_tracking_flag( $is_enabled );
5541
- break;
5542
- default:
5543
  $permission = 'no_match';
5544
- }
5545
 
5546
- if ( 'no_match' === $permission ) {
5547
- self::shoot_ajax_failure();
5548
  }
5549
 
5550
- self::shoot_ajax_success( array(
5551
- 'permissions' => array(
5552
- $permission => $is_enabled,
5553
- )
5554
- ) );
5555
- }
5556
-
5557
- /**
5558
- * @author Leo Fajardo (@leorw)
5559
- * @since 2.3.2
5560
- *
5561
- * @param bool|null $is_enabled
5562
- */
5563
- function update_extensions_tracking_flag( $is_enabled ) {
5564
- if ( is_bool( $is_enabled ) ) {
5565
- $this->_storage->store( 'is_extensions_tracking_allowed', $is_enabled );
5566
- }
5567
  }
5568
 
5569
  /**
@@ -5769,8 +5890,7 @@
5769
  if ( $this->is_activation_mode() ) {
5770
  if ( ! is_admin() ) {
5771
  /**
5772
- * If in activation mode, don't execute Freemius outside of the
5773
- * admin dashboard.
5774
  *
5775
  * @author Vova Feldman (@svovaf)
5776
  * @since 1.1.7.3
@@ -6317,7 +6437,25 @@
6317
  if ( ! isset( $this->_is_anonymous ) ) {
6318
  if ( $this->is_network_anonymous() ) {
6319
  $this->_is_anonymous = true;
6320
- } else if ( ! fs_is_network_admin() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6321
  if ( ! isset( $this->_storage->is_anonymous ) ) {
6322
  // Not skipped.
6323
  $this->_is_anonymous = false;
@@ -6373,6 +6511,18 @@
6373
  return $this->_storage->get( 'is_pending_activation', false );
6374
  }
6375
 
 
 
 
 
 
 
 
 
 
 
 
 
6376
  /**
6377
  * Check if plugin must be WordPress.org compliant.
6378
  *
@@ -6449,9 +6599,11 @@
6449
  private function get_cron_blog_id( $name ) {
6450
  $this->_logger->entrance( $name );
6451
 
6452
- /**
6453
- * @var object $cron_data
6454
- */
 
 
6455
  $cron_data = $this->get_cron_data( $name );
6456
 
6457
  return ( is_object( $cron_data ) && is_numeric( $cron_data->blog_id ) ) ?
@@ -6562,18 +6714,23 @@
6562
  return 0;
6563
  }
6564
 
6565
- if ( $this->_is_network_active &&
6566
- is_numeric( $this->_storage->network_install_blog_id ) &&
6567
- $except_blog_id != $this->_storage->network_install_blog_id &&
6568
- self::is_site_active( $this->_storage->network_install_blog_id )
6569
- ) {
6570
- // Try to run cron from the main network blog.
6571
- $install = $this->get_install_by_blog_id( $this->_storage->network_install_blog_id );
6572
 
6573
- if ( is_object( $install ) &&
6574
- ( $this->is_premium() || $install->is_tracking_allowed() )
 
 
6575
  ) {
6576
- return $this->_storage->network_install_blog_id;
 
 
 
 
 
 
 
 
6577
  }
6578
  }
6579
 
@@ -6582,7 +6739,7 @@
6582
  foreach ( $installs as $blog_id => $install ) {
6583
  if ( $except_blog_id != $blog_id &&
6584
  self::is_site_active( $blog_id ) &&
6585
- ( $this->is_premium() || $install->is_tracking_allowed() )
6586
  ) {
6587
  return $blog_id;
6588
  }
@@ -6614,7 +6771,7 @@
6614
  /**
6615
  * @var FS_Site $install
6616
  */
6617
- if ( $install->is_tracking_allowed() ) {
6618
  $clear_cron = false;
6619
  break;
6620
  }
@@ -6625,14 +6782,7 @@
6625
  return;
6626
  }
6627
 
6628
- /**
6629
- * @var object $cron_data
6630
- */
6631
- $cron_data = $this->get_cron_data( $name );
6632
-
6633
- $cron_blog_id = is_object( $cron_data ) && isset( $cron_data->blog_id ) ?
6634
- $cron_data->blog_id :
6635
- 0;
6636
 
6637
  $this->clear_cron_data( $name );
6638
 
@@ -6669,14 +6819,7 @@
6669
  return false;
6670
  }
6671
 
6672
- /**
6673
- * @var object $cron_data
6674
- */
6675
- $cron_data = $this->get_cron_data( $name );
6676
-
6677
- $cron_blog_id = is_object( $cron_data ) && isset( $cron_data->blog_id ) ?
6678
- $cron_data->blog_id :
6679
- 0;
6680
 
6681
  if ( 0 < $cron_blog_id ) {
6682
  switch_to_blog( $cron_blog_id );
@@ -6787,7 +6930,7 @@
6787
  } else {
6788
  $installs = $this->get_blog_install_map();
6789
  foreach ( $installs as $blog_id => $install ) {
6790
- if ( $this->is_premium() || $install->is_tracking_allowed() ) {
6791
  if ( ! isset( $users_2_blog_ids[ $install->user_id ] ) ) {
6792
  $users_2_blog_ids[ $install->user_id ] = array();
6793
  }
@@ -6852,8 +6995,6 @@
6852
  * @since 1.1.7.3
6853
  */
6854
  private function run_manual_sync() {
6855
- self::require_pluggable_essentials();
6856
-
6857
  if ( ! $this->is_user_admin() ) {
6858
  return;
6859
  }
@@ -6937,6 +7078,24 @@
6937
  return $this->is_cron_on( 'sync' );
6938
  }
6939
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6940
  /**
6941
  * @author Vova Feldman (@svovaf)
6942
  * @since 1.1.7.3
@@ -7043,6 +7202,10 @@
7043
  * @param int $except_blog_id Since 2.0.0 when running in a multisite network environment, the cron execution is consolidated. This param allows excluding excluded specified blog ID from being the cron executor.
7044
  */
7045
  private function schedule_install_sync( $except_blog_id = 0 ) {
 
 
 
 
7046
  $this->schedule_cron( 'install_sync', 'install_sync', 'single', WP_FS__SCRIPT_START_TIME, false, $except_blog_id );
7047
  }
7048
 
@@ -7131,13 +7294,20 @@
7131
  /**
7132
  * Show a notice that activation is currently pending.
7133
  *
 
 
7134
  * @author Vova Feldman (@svovaf)
7135
  * @since 1.0.7
7136
  *
7137
  * @param bool|string $email
7138
  * @param bool $is_pending_trial Since 1.2.1.5
 
7139
  */
7140
- function _add_pending_activation_notice( $email = false, $is_pending_trial = false ) {
 
 
 
 
7141
  if ( ! is_string( $email ) ) {
7142
  $current_user = self::_get_current_wp_user();
7143
  $email = $current_user->user_email;
@@ -7193,6 +7363,20 @@
7193
  /**
7194
  * Don't redirect if activating multiple plugins at once (bulk activation).
7195
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7196
  } else if ( ! $is_migration ) {
7197
  $this->_redirect_on_activation_hook();
7198
  return;
@@ -7206,7 +7390,7 @@
7206
  if ( fs_request_is_action( $this->get_unique_affix() . '_skip_activation' ) ) {
7207
  check_admin_referer( $this->get_unique_affix() . '_skip_activation' );
7208
 
7209
- $this->skip_connection( null, fs_is_network_admin() );
7210
 
7211
  fs_redirect( $this->get_after_activation_url( 'after_skip_url' ) );
7212
  }
@@ -7379,8 +7563,6 @@
7379
 
7380
  fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
7381
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
7382
-
7383
- fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
7384
  }
7385
 
7386
  /**
@@ -7416,14 +7598,14 @@
7416
  <?php
7417
  echo $this->apply_filters( 'optin_pointer_execute', "
7418
 
7419
- optin.pointer('open');
7420
 
7421
- // Tag the opt-in pointer with custom class.
7422
- $('.wp-pointer #fs_connect')
7423
- .parents('.wp-pointer.wp-pointer-top')
7424
- .addClass('fs-opt-in-pointer');
7425
 
7426
- ", 'element', 'optin' ) ?>
7427
  }
7428
  }
7429
  });
@@ -7439,7 +7621,7 @@
7439
  *
7440
  * @return string
7441
  */
7442
- function current_page_url() {
7443
  $url = 'http';
7444
 
7445
  if ( isset( $_SERVER["HTTPS"] ) ) {
@@ -7471,7 +7653,7 @@
7471
  }
7472
 
7473
  /* Events
7474
- ------------------------------------------------------------------------------------------------------------------*/
7475
  /**
7476
  * Delete site install from Database.
7477
  *
@@ -7635,12 +7817,21 @@
7635
 
7636
  /**
7637
  * @author Leo Fajardo (@leorw)
7638
- * @since 1.2.2
 
 
 
 
 
 
 
 
 
 
7639
  *
7640
- * @return string
7641
  */
7642
- private function can_activate_previous_theme() {
7643
- $slug = $this->get_previous_theme_slug();
7644
  if ( false !== $slug && current_user_can( 'switch_themes' ) ) {
7645
  $theme_instance = wp_get_theme( $slug );
7646
 
@@ -7737,6 +7928,10 @@
7737
  ( current_filter() !== ( 'activate_' . $this->_free_plugin_basename ) ) :
7738
  $this->is_premium();
7739
 
 
 
 
 
7740
  $this->_logger->info( 'Activating ' . ( $is_premium_version_activation ? 'premium' : 'free' ) . ' plugin version.' );
7741
 
7742
  if ( $this->is_plugin() ) {
@@ -7803,7 +7998,9 @@
7803
  $plugin_version = $this->_storage->is_anonymous_ms['version'];
7804
  $network = true;
7805
  } else {
7806
- $plugin_version = $this->_storage->is_anonymous['version'];
 
 
7807
  $network = false;
7808
  }
7809
 
@@ -7951,7 +8148,7 @@
7951
  );
7952
  } else {
7953
  // Activate the license.
7954
- $install = $this->get_api_site_scope()->call(
7955
  '/',
7956
  'put',
7957
  array( 'license_key' => $this->apply_filters( 'license_key', $license->secret_key ) )
@@ -8610,6 +8807,20 @@
8610
  $this->_is_anonymous = $is_anonymous;
8611
  }
8612
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8613
  /**
8614
  * @author Vova Feldman (@svovaf)
8615
  * @since 2.0.0
@@ -8626,9 +8837,17 @@
8626
  * @uses Freemius::is_network_anonymous() to check if the super-admin network skipped.
8627
  * @uses Freemius::is_network_delegated_connection() to check if the super-admin network delegated the connection to the site admins.
8628
  */
8629
- function _after_new_blog_callback( $blog_id, $user_id, $domain, $path, $network_id, $meta ) {
8630
  $this->_logger->entrance();
8631
 
 
 
 
 
 
 
 
 
8632
  if ( $this->is_premium() &&
8633
  $this->is_network_connected() &&
8634
  is_object( $this->_license ) &&
@@ -8662,9 +8881,13 @@
8662
  }
8663
  }
8664
 
 
 
8665
  $this->switch_to_blog( $current_blog_id );
8666
 
8667
- if ( is_object( $this->_site ) ) {
 
 
8668
  // Already connected (with or without a license), so no need to continue.
8669
  return;
8670
  }
@@ -8697,6 +8920,8 @@
8697
  false
8698
  );
8699
 
 
 
8700
  $this->switch_to_blog( $current_blog_id );
8701
  } else {
8702
  /**
@@ -8707,8 +8932,8 @@
8707
  $has_delegated_site = false;
8708
 
8709
  $sites = self::get_sites();
8710
- foreach ( $sites as $site ) {
8711
- $blog_id = self::get_site_blog_id( $site );
8712
 
8713
  if ( $this->is_site_delegated_connection( $blog_id ) ) {
8714
  $has_delegated_site = true;
@@ -8722,19 +8947,74 @@
8722
  $this->skip_site_connection( $blog_id );
8723
  }
8724
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8725
  }
8726
 
8727
  /**
8728
  * @author Vova Feldman (@svovaf)
8729
  * @since 1.1.3
8730
  *
8731
- * @param bool|int $network_or_blog_id Since 2.0.0.
8732
  */
8733
- private function reset_anonymous_mode( $network_or_blog_id = 0 ) {
8734
- if ( true === $network_or_blog_id ) {
8735
- unset( $this->_storage->is_anonymous_ms );
8736
- } else {
8737
- $this->_storage->remove( 'is_anonymous', true, $network_or_blog_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8738
  }
8739
 
8740
  /**
@@ -8745,11 +9025,7 @@
8745
  * @author Leo Fajardo (@leorw)
8746
  * @since 1.2.2
8747
  */
8748
- if ( ! $this->_is_network_active ||
8749
- 0 === $network_or_blog_id ||
8750
- get_current_blog_id() == $network_or_blog_id ||
8751
- ( true === $network_or_blog_id && fs_is_network_admin() )
8752
- ) {
8753
  $this->_is_anonymous = null;
8754
  }
8755
  }
@@ -8795,44 +9071,42 @@
8795
  * @author Vova Feldman (@svovaf)
8796
  * @since 1.1.1
8797
  *
8798
- * @param array|null $sites Since 2.0.0. Specific sites.
8799
- * @param bool $skip_all_network Since 2.0.0. If true, skip connection for all sites.
8800
  */
8801
- function skip_connection( $sites = null, $skip_all_network = false ) {
8802
  $this->_logger->entrance();
8803
 
8804
  $this->_admin_notices->remove_sticky( 'connect_account' );
8805
 
8806
- if ( $skip_all_network ) {
8807
  $this->set_anonymous_mode( true, true );
8808
- }
8809
 
8810
- if ( ! $skip_all_network && empty( $sites ) ) {
8811
- $this->skip_site_connection();
8812
- } else {
8813
- $uids = array();
 
 
 
 
 
 
 
 
8814
 
8815
- if ( $skip_all_network ) {
8816
- $this->set_anonymous_mode( true, true );
 
8817
 
8818
- $sites = self::get_sites();
8819
- foreach ( $sites as $site ) {
8820
- $blog_id = self::get_site_blog_id( $site );
8821
- $this->skip_site_connection( $blog_id, false );
8822
- $uids[] = $this->get_anonymous_id( $blog_id );
8823
- }
8824
- } else if ( ! empty( $sites ) ) {
8825
- foreach ( $sites as $site ) {
8826
- $uids[] = $site['uid'];
8827
- $this->skip_site_connection( $site['blog_id'], false );
8828
  }
8829
  }
 
8830
 
8831
- // Send anonymous skip event.
8832
- // No user identified info nor any tracking will be sent after the user skips the opt-in.
8833
- $this->get_api_plugin_scope()->call( 'skip.json', 'put', array(
8834
- 'uids' => $uids,
8835
- ) );
8836
  }
8837
 
8838
  $this->network_upgrade_mode_completed();
@@ -8847,18 +9121,12 @@
8847
  * @param int|null $blog_id
8848
  * @param bool $send_skip
8849
  */
8850
- private function skip_site_connection( $blog_id = null, $send_skip = true ) {
8851
  $this->_logger->entrance();
8852
 
8853
  $this->_admin_notices->remove_sticky( 'connect_account', $blog_id );
8854
 
8855
  $this->set_anonymous_mode( true, $blog_id );
8856
-
8857
- if ( $send_skip ) {
8858
- $this->get_api_plugin_scope()->call( 'skip.json', 'put', array(
8859
- 'uids' => array( $this->get_anonymous_id( $blog_id ) ),
8860
- ) );
8861
- }
8862
  }
8863
 
8864
  /**
@@ -9230,7 +9498,7 @@
9230
  * @param string[] $override
9231
  * @param bool $include_plugins Since 1.1.8 by default include plugin changes.
9232
  * @param bool $include_themes Since 1.1.8 by default include plugin changes.
9233
- * @param bool $include_blog_data Since 2.3.0 by default include the current blog's data (language, charset, title, and URL).
9234
  *
9235
  * @return array
9236
  */
@@ -9240,7 +9508,10 @@
9240
  $include_themes = true,
9241
  $include_blog_data = true
9242
  ) {
9243
- if ( $this->is_extensions_tracking_allowed() ) {
 
 
 
9244
  if ( ! defined( 'WP_FS__TRACK_PLUGINS' ) || false !== WP_FS__TRACK_PLUGINS ) {
9245
  /**
9246
  * @since 1.1.8 Also send plugin updates.
@@ -9268,21 +9539,23 @@
9268
 
9269
  $versions = $this->get_versions();
9270
 
9271
- $blog_data = $include_blog_data ?
9272
- array(
9273
- 'language' => get_bloginfo( 'language' ),
9274
- 'charset' => get_bloginfo( 'charset' ),
9275
- 'title' => get_bloginfo( 'name' ),
9276
- 'url' => get_site_url(),
9277
- ) :
9278
- array();
 
 
 
9279
 
9280
  return array_merge( $versions, $blog_data, array(
9281
  'version' => $this->get_plugin_version(),
9282
  'is_premium' => $this->is_premium(),
9283
  // Special params.
9284
  'is_active' => true,
9285
- 'is_disconnected' => $this->is_tracking_prohibited(),
9286
  'is_uninstalled' => false,
9287
  ), $override );
9288
  }
@@ -9297,6 +9570,7 @@
9297
  *
9298
  * @param string[] string $override
9299
  * @param bool $only_diff
 
9300
  * @param bool $include_plugins Since 1.1.8 by default include plugin changes.
9301
  * @param bool $include_themes Since 1.1.8 by default include plugin changes.
9302
  *
@@ -9305,6 +9579,7 @@
9305
  private function get_installs_data_for_api(
9306
  array $override,
9307
  $only_diff = false,
 
9308
  $include_plugins = true,
9309
  $include_themes = true
9310
  ) {
@@ -9342,6 +9617,10 @@
9342
 
9343
  $sites = self::get_sites();
9344
 
 
 
 
 
9345
  foreach ( $sites as $site ) {
9346
  $blog_id = self::get_site_blog_id( $site );
9347
 
@@ -9353,19 +9632,64 @@
9353
  continue;
9354
  }
9355
 
9356
- if ( ! $this->is_premium() && $install->is_tracking_prohibited() ) {
9357
  // Don't send updates regarding opted-out installs.
9358
  continue;
9359
  }
9360
 
9361
- $install_data = $this->get_site_info( $site );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9362
 
9363
- $uid = $install_data['uid'];
 
 
 
 
 
9364
 
9365
  unset( $install_data['blog_id'] );
9366
  unset( $install_data['uid'] );
 
 
9367
 
9368
- $install_data['is_disconnected'] = $install->is_disconnected;
9369
  $install_data['is_active'] = $this->is_active_for_site( $blog_id );
9370
  $install_data['is_uninstalled'] = $install->is_uninstalled;
9371
 
@@ -9388,18 +9712,26 @@
9388
  $is_common_diff_for_any_site = $is_common_diff_for_any_site || $is_common_diff;
9389
  }
9390
 
9391
- if ( ! empty( $install_data ) || $is_common_diff ) {
9392
  // Add install ID and site unique ID.
9393
  $install_data['id'] = $install->id;
9394
  $install_data['uid'] = $uid;
 
9395
 
9396
- $installs_data[] = $install_data;
 
 
9397
  }
9398
  }
9399
  }
9400
 
9401
  restore_current_blog();
9402
 
 
 
 
 
 
9403
  if ( 0 < count( $installs_data ) && ( $is_common_diff_for_any_site || ! $only_diff ) ) {
9404
  if ( ! $only_diff ) {
9405
  $installs_data[] = $common;
@@ -9437,8 +9769,12 @@
9437
  if ( ( is_bool( $install->{$p} ) || ! empty( $install->{$p} ) ) &&
9438
  $install->{$p} != $v
9439
  ) {
9440
- $install->{$p} = $v;
9441
- $diff[ $p ] = $v;
 
 
 
 
9442
  }
9443
  } else {
9444
  $special[ $p ] = $v;
@@ -9463,6 +9799,78 @@
9463
  return $diff;
9464
  }
9465
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9466
  /**
9467
  * Update install only if changed.
9468
  *
@@ -9471,10 +9879,11 @@
9471
  *
9472
  * @param string[] string $override
9473
  * @param bool $flush
 
9474
  *
9475
  * @return false|object|string
9476
  */
9477
- private function send_install_update( $override = array(), $flush = false ) {
9478
  $this->_logger->entrance();
9479
 
9480
  $check_properties = $this->get_install_data_for_api( $override );
@@ -9485,7 +9894,6 @@
9485
  $params = $this->get_install_diff_for_api( $check_properties, $this->_site, $override );
9486
  }
9487
 
9488
- $keepalive_only_update = false;
9489
  if ( empty( $params ) ) {
9490
  $keepalive_only_update = $this->should_send_keepalive_update();
9491
 
@@ -9500,10 +9908,9 @@
9500
  }
9501
  }
9502
 
9503
- if ( ! $keepalive_only_update ) {
9504
  /**
9505
- * Do not update the last install sync timestamp after a keepalive-only call since there were no actual
9506
- * updates sent.
9507
  *
9508
  * @author Leo Fajardo (@leorw)
9509
  * @since 2.2.3
@@ -9519,11 +9926,11 @@
9519
  $this->set_keepalive_timestamp();
9520
 
9521
  // Send updated values to FS.
9522
- $site = $this->get_api_site_scope()->call( '/', 'put', $params );
9523
 
9524
- if ( ! $keepalive_only_update && $this->is_api_result_entity( $site ) ) {
9525
  /**
9526
- * Do not clear scheduled sync after a keepalive-only call since there were no actual updates sent.
9527
  *
9528
  * @author Leo Fajardo (@leorw)
9529
  * @since 2.2.3
@@ -9545,37 +9952,29 @@
9545
  *
9546
  * @param string[] string $override
9547
  * @param bool $flush
 
9548
  *
9549
  * @return false|object|string
9550
  */
9551
- private function send_installs_update( $override = array(), $flush = false ) {
9552
  $this->_logger->entrance();
9553
 
9554
- $installs_data = $this->get_installs_data_for_api( $override, ! $flush );
 
 
 
 
 
 
9555
 
9556
- $keepalive_only_update = false;
9557
- if ( empty( $installs_data ) ) {
9558
- /**
9559
- * Pass `true` to use the network level storage since the update is for many installs.
9560
- *
9561
- * @author Leo Fajardo (@leorw)
9562
- * @since 2.2.3
9563
- */
9564
- $keepalive_only_update = $this->should_send_keepalive_update( true );
9565
 
9566
- if ( ! $keepalive_only_update ) {
9567
- /**
9568
- * There are no updates to send including keepalive.
9569
- *
9570
- * @author Leo Fajardo (@leorw)
9571
- * @since 2.2.3
9572
- */
9573
- return false;
9574
- }
9575
  }
9576
 
9577
- if ( ! $keepalive_only_update ) {
9578
- // Update last install sync timestamp if there were actual updates sent (i.e., not a keepalive-only call).
9579
  $this->set_cron_execution_timestamp( 'install_sync' );
9580
  }
9581
 
@@ -9590,8 +9989,8 @@
9590
  // Send updated values to FS.
9591
  $result = $this->get_api_user_scope()->call( "/plugins/{$this->_plugin->id}/installs.json", 'put', $installs_data );
9592
 
9593
- if ( ! $keepalive_only_update && $this->is_api_result_object( $result, 'installs' ) ) {
9594
- // I successfully sent installs update (there was an actual update sent and it's not just a keepalive-only call), clear scheduled sync if exist.
9595
  $this->clear_install_sync_cron();
9596
  }
9597
 
@@ -9641,10 +10040,10 @@
9641
  * @param string[] string $override
9642
  * @param bool $flush
9643
  */
9644
- private function sync_install( $override = array(), $flush = false ) {
9645
  $this->_logger->entrance();
9646
 
9647
- $site = $this->send_install_update( $override, $flush );
9648
 
9649
  if ( false === $site ) {
9650
  // No sync required.
@@ -9673,7 +10072,7 @@
9673
  private function sync_installs( $override = array(), $flush = false ) {
9674
  $this->_logger->entrance();
9675
 
9676
- $result = $this->send_installs_update( $override, $flush );
9677
 
9678
  if ( false === $result ) {
9679
  // No sync required.
@@ -9828,8 +10227,8 @@
9828
  // Send uninstall event.
9829
  $this->send_installs_update( $params );
9830
  } else {
9831
- // Send uninstall event.
9832
- $this->send_install_update( $params );
9833
  }
9834
  }
9835
 
@@ -9926,7 +10325,17 @@
9926
  return;
9927
  }
9928
 
9929
- $fs->_uninstall_plugin_event();
 
 
 
 
 
 
 
 
 
 
9930
 
9931
  $fs->do_action( 'after_uninstall' );
9932
  }
@@ -10037,7 +10446,7 @@
10037
  * @return string
10038
  */
10039
  function get_premium_slug() {
10040
- return is_object( $this->_plugin ) ?
10041
  $this->_plugin->premium_slug :
10042
  "{$this->_slug}-premium";
10043
  }
@@ -10090,6 +10499,28 @@
10090
  null;
10091
  }
10092
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10093
  /**
10094
  * @author Vova Feldman (@svovaf)
10095
  * @since 1.2.1.5
@@ -10134,7 +10565,7 @@
10134
  function get_eula_url() {
10135
  return $this->apply_filters(
10136
  'eula_url',
10137
- "https://freemius.com/terms/{$this->_plugin->id}/{$this->_slug}/"
10138
  );
10139
  }
10140
 
@@ -10322,7 +10753,7 @@
10322
  #endregion ------------------------------------------------------------------
10323
 
10324
  /* Account
10325
- ------------------------------------------------------------------------------------------------------------------*/
10326
 
10327
  /**
10328
  * Find plugin's slug by plugin's basename.
@@ -10386,9 +10817,14 @@
10386
  */
10387
  private static function get_all_sites(
10388
  $module_type = WP_FS__MODULE_TYPE_PLUGIN,
10389
- $blog_id = null
 
10390
  ) {
10391
- $sites = self::get_account_option( 'sites', $module_type, $blog_id );
 
 
 
 
10392
 
10393
  if ( ! is_array( $sites ) ) {
10394
  $sites = array();
@@ -10748,10 +11184,20 @@
10748
  *
10749
  * @author Vova Feldman (@svovaf)
10750
  * @since 1.0.1
 
 
 
10751
  * @return bool
10752
  */
10753
- function is_registered() {
10754
- return is_object( $this->_user );
 
 
 
 
 
 
 
10755
  }
10756
 
10757
  /**
@@ -10762,8 +11208,34 @@
10762
  *
10763
  * @return bool
10764
  */
10765
- function is_tracking_allowed() {
10766
- return ( is_object( $this->_site ) && $this->_site->is_tracking_allowed() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10767
  }
10768
 
10769
  /**
@@ -10799,13 +11271,59 @@
10799
  }
10800
 
10801
  /**
10802
- * @author Vova Feldman (@svovaf)
10803
- * @since 1.0.3
10804
- *
10805
- * @return FS_Site
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10806
  */
10807
- function get_site() {
10808
- return $this->_site;
 
 
 
 
 
 
10809
  }
10810
 
10811
  /**
@@ -12089,7 +12607,7 @@
12089
  } else {
12090
  $url = is_object( $site ) ?
12091
  $site->siteurl :
12092
- get_site_url( $blog_id );
12093
 
12094
  $disconnected_site_ids[] = $blog_id;
12095
  }
@@ -12462,7 +12980,21 @@
12462
  } else if ( $is_whitelabeled_flag ) {
12463
  $is_whitelabeled = true;
12464
  } else {
12465
- $addon_ids = $this->get_updated_account_addons();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12466
  $installed_addons = $this->get_installed_addons();
12467
  foreach ( $installed_addons as $fs_addon ) {
12468
  $addon_ids[] = $fs_addon->get_id();
@@ -12891,6 +13423,75 @@
12891
  fs_require_template( 'forms/resend-key.php', $vars );
12892
  }
12893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12894
  /**
12895
  * Returns a collection of IDs of installs that are associated with the context product and its add-ons, and activated with foreign licenses.
12896
  *
@@ -13098,10 +13699,15 @@
13098
  ( $is_network_admin && $this->is_network_active() && ! $this->is_network_delegated_connection() ) ||
13099
  ( ! $is_network_admin && ( ! $this->is_network_active() || $this->is_delegated_connection() ) )
13100
  ) {
13101
- /**
13102
- * @since 1.2.0 Add license action link only on plugins page.
13103
- */
13104
- $this->_add_license_action_link();
 
 
 
 
 
13105
  }
13106
  }
13107
 
@@ -13273,7 +13879,7 @@
13273
  self::shoot_ajax_failure();
13274
  }
13275
 
13276
- $site = $this->get_api_site_scope()->call(
13277
  '',
13278
  'put',
13279
  array(
@@ -13326,7 +13932,8 @@
13326
  fs_request_get( 'blog_id', null ),
13327
  fs_request_get( 'module_id', null, 'post' ),
13328
  fs_request_get( 'user_id', null ),
13329
- fs_request_get_bool( 'is_extensions_tracking_allowed', null )
 
13330
  );
13331
 
13332
  if (
@@ -13571,6 +14178,9 @@
13571
  * @param null|int $blog_id
13572
  * @param null|number $plugin_id
13573
  * @param null|number $license_owner_id
 
 
 
13574
  *
13575
  * @return array {
13576
  * @var bool $success
@@ -13585,7 +14195,8 @@
13585
  $blog_id = null,
13586
  $plugin_id = null,
13587
  $license_owner_id = null,
13588
- $is_extensions_tracking_allowed = null
 
13589
  ) {
13590
  $this->_logger->entrance();
13591
 
@@ -13605,7 +14216,10 @@
13605
  $this :
13606
  $this->get_addon_instance( $plugin_id );
13607
 
13608
- $this->update_extensions_tracking_flag( $is_extensions_tracking_allowed );
 
 
 
13609
 
13610
  $error = false;
13611
  $next_page = false;
@@ -13770,8 +14384,8 @@
13770
  }
13771
  }
13772
 
13773
- $all_sites = self::get_sites();
13774
- $pending_sites = array();
13775
 
13776
  /**
13777
  * Check if there are any sites that are not connected, skipped, nor delegated. For every site that falls into that category, if the product is freemium, skip the connection. If the product is premium only, delegate the connection to the site administrator.
@@ -13801,14 +14415,14 @@
13801
  continue;
13802
  }
13803
 
13804
- $pending_sites[] = self::get_site_info( $site );
13805
  }
13806
 
13807
- if ( ! empty( $pending_sites ) ) {
13808
  if ( $fs->is_freemium() && $fs->is_enable_anonymous() ) {
13809
- $fs->skip_connection( $pending_sites );
13810
  } else {
13811
- $fs->delegate_connection( $pending_sites );
13812
  }
13813
  }
13814
  }
@@ -13886,7 +14500,7 @@
13886
 
13887
  $addon_info = $fs->_get_addon_info( $addon_id, $is_installed );
13888
 
13889
- if ( ! $addon_info['is_connected'] ) {
13890
  // Add-on is not associated with an install entity.
13891
  continue;
13892
  }
@@ -13944,11 +14558,11 @@
13944
  $this->delegate_connection();
13945
  } else {
13946
  if ( ! empty( $sites_by_action['delegate'] ) ) {
13947
- $this->delegate_connection( $sites_by_action['delegate'] );
13948
  }
13949
 
13950
  if ( ! empty( $sites_by_action['skip'] ) ) {
13951
- $this->skip_connection( $sites_by_action['skip'] );
13952
  }
13953
 
13954
  if ( empty( $sites_by_action['allow'] ) ) {
@@ -14266,15 +14880,37 @@
14266
  return $this->_plugin->has_affiliate_program();
14267
  }
14268
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14269
  /**
14270
  * @author Leo Fajardo (@leorw)
14271
  * @since 1.2.4
14272
  */
14273
  private function fetch_affiliate_terms() {
14274
  if ( ! is_object( $this->plugin_affiliate_terms ) ) {
14275
- $plugins_api = $this->get_api_plugin_scope();
 
 
 
 
 
 
14276
  $affiliate_terms = $plugins_api->get( '/aff.json?type=affiliation', false );
14277
 
 
 
 
14278
  if ( ! $this->is_api_result_entity( $affiliate_terms ) ) {
14279
  return;
14280
  }
@@ -14292,8 +14928,10 @@
14292
  $application_data = $this->_storage->affiliate_application_data;
14293
  $flush = ( ! isset( $application_data['status'] ) || 'pending' === $application_data['status'] );
14294
 
 
 
14295
  $users_api = $this->get_api_user_scope();
14296
- $result = $users_api->get( "/plugins/{$this->_plugin->id}/aff/{$this->plugin_affiliate_terms->id}/affiliates.json", $flush );
14297
  if ( $this->is_api_result_object( $result, 'affiliates' ) ) {
14298
  if ( ! empty( $result->affiliates ) ) {
14299
  $affiliate = new FS_Affiliate( $result->affiliates[0] );
@@ -14393,15 +15031,17 @@
14393
  var_export( $next_page, true )
14394
  );
14395
  } else if ( $this->is_pending_activation() ) {
14396
- self::shoot_ajax_failure( $this->get_text_inline( 'Account is pending activation.', 'account-is-pending-activation' ) );
14397
  }
14398
  }
14399
 
14400
  $this->fetch_affiliate_terms();
14401
 
 
 
14402
  $api = $this->get_api_user_scope();
14403
  $result = $api->call(
14404
- ( "/plugins/{$this->_plugin->id}/aff/{$this->plugin_affiliate_terms->id}/affiliates.json" ),
14405
  'post',
14406
  $affiliate
14407
  );
@@ -14863,6 +15503,16 @@
14863
  return ( defined( 'DOING_CRON' ) && DOING_CRON );
14864
  }
14865
 
 
 
 
 
 
 
 
 
 
 
14866
  /**
14867
  * Check if a real user is visiting the admin dashboard.
14868
  *
@@ -14876,7 +15526,7 @@
14876
  is_admin() &&
14877
  ! self::is_ajax() &&
14878
  ! self::is_cron() &&
14879
- ( 'admin-post.php' !== self::get_current_page() )
14880
  );
14881
  }
14882
 
@@ -15028,20 +15678,20 @@
15028
  * @author Leo Fajardo (@leorw)
15029
  * @since 2.0.0
15030
  *
15031
- * @param array|null $sites
15032
  */
15033
- private function delegate_connection( $sites = null ) {
15034
  $this->_logger->entrance();
15035
 
15036
  $this->_admin_notices->remove_sticky( 'connect_account' );
15037
 
15038
- if ( is_null( $sites ) ) {
15039
  // All sites delegation.
15040
- $this->_storage->store( 'is_delegated_connection', true, true, true );
15041
  } else {
15042
  // Specified sites delegation.
15043
- foreach ( $sites as $site ) {
15044
- $this->delegate_site_connection( $site['blog_id'] );
15045
  }
15046
  }
15047
 
@@ -15057,7 +15707,7 @@
15057
  * @param int $blog_id
15058
  */
15059
  private function delegate_site_connection( $blog_id ) {
15060
- $this->_storage->store( 'is_delegated_connection', true, $blog_id, true );
15061
  }
15062
 
15063
  /**
@@ -15097,7 +15747,7 @@
15097
  }
15098
 
15099
  /**
15100
- * Check if delegated the connection. When running within the the network admin,
15101
  * and haven't specified the blog ID, checks if network level delegated. If running
15102
  * within a site admin or specified a blog ID, check if delegated the connection for
15103
  * the current context site.
@@ -15157,12 +15807,17 @@
15157
  }
15158
 
15159
  /**
 
 
15160
  * @author Leo Fajardo (@leorw)
15161
  * @since 2.0.0
15162
  *
 
 
 
15163
  * @return array Active & public sites collection.
15164
  */
15165
- static function get_sites() {
15166
  if ( ! is_multisite() ) {
15167
  return array();
15168
  }
@@ -15184,27 +15839,11 @@
15184
  'mature' => 0,
15185
  'spam' => 0,
15186
  'deleted' => 0,
 
 
15187
  );
15188
 
15189
- if ( function_exists( 'get_sites' ) ) {
15190
- // For WP 4.6 and above.
15191
- return get_sites( $args );
15192
- } else if ( function_exists( 'wp_' . 'get_sites' ) ) {
15193
- // For WP 3.7 to WP 4.5.
15194
- /**
15195
- * This is a hack suggested previously proposed by the TRT. Our SDK is compliant with older WP versions and we'd like to keep it that way.
15196
- *
15197
- * @todo Remove this hack once this false-positive error is removed from the Theme Sniffer.
15198
- *
15199
- * @since 2.3.3
15200
- * @author Vova Feldman (@svovaf)
15201
- */
15202
- $fn = 'wp_' . 'get_sites';
15203
- return $fn( $args );
15204
- } else {
15205
- // For WP 3.6 and below.
15206
- return get_blog_list( 0, 'all' );
15207
- }
15208
  }
15209
 
15210
  /**
@@ -15253,7 +15892,7 @@
15253
  $address_to_blog_map = array();
15254
  foreach ( $sites as $site ) {
15255
  $blog_id = self::get_site_blog_id( $site );
15256
- $address = trailingslashit( fs_strip_url_protocol( get_site_url( $blog_id ) ) );
15257
  $address_to_blog_map[ $address ] = $blog_id;
15258
  }
15259
 
@@ -15289,6 +15928,42 @@
15289
  return $install_map;
15290
  }
15291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15292
  /**
15293
  * Gets a map of module IDs that the given user has opted-in to.
15294
  *
@@ -15373,11 +16048,16 @@
15373
  *
15374
  * @param int $blog_id
15375
  * @param FS_Site $install
 
15376
  *
15377
  * @return bool Since 2.3.1 returns if a switch was made.
15378
  */
15379
- function switch_to_blog( $blog_id, FS_Site $install = null ) {
15380
- if ( ! is_numeric( $blog_id ) || $blog_id == $this->_context_is_network_or_blog_id ) {
 
 
 
 
15381
  return false;
15382
  }
15383
 
@@ -15441,7 +16121,7 @@
15441
  unset( $this->_site_api );
15442
  unset( $this->_user_api );
15443
 
15444
- return false;
15445
  }
15446
 
15447
  /**
@@ -15470,21 +16150,41 @@
15470
  $site['blog_id'] );
15471
  }
15472
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15473
  /**
15474
  * @author Leo Fajardo (@leorw)
15475
  * @since 2.0.0
15476
  *
15477
  * @param array|WP_Site|null $site
 
15478
  *
15479
  * @return array
15480
  */
15481
- function get_site_info( $site = null ) {
15482
  $this->_logger->entrance();
15483
 
15484
  $switched = false;
15485
 
 
 
15486
  if ( is_null( $site ) ) {
15487
- $url = get_site_url();
15488
  $name = get_bloginfo( 'name' );
15489
  $blog_id = null;
15490
  } else {
@@ -15496,26 +16196,44 @@
15496
  }
15497
 
15498
  if ( $site instanceof WP_Site ) {
15499
- $url = $site->siteurl;
15500
- $name = $site->blogname;
 
15501
  } else {
15502
- $url = get_site_url( $blog_id );
15503
  $name = get_bloginfo( 'name' );
15504
  }
15505
  }
15506
 
 
 
 
 
 
 
 
 
15507
  $info = array(
15508
- 'uid' => $this->get_anonymous_id( $blog_id ),
15509
- 'url' => $url,
15510
- 'title' => $name,
15511
- 'language' => get_bloginfo( 'language' ),
15512
- 'charset' => get_bloginfo( 'charset' ),
15513
  );
15514
 
 
 
 
 
 
 
 
 
15515
  if ( is_numeric( $blog_id ) ) {
15516
  $info['blog_id'] = $blog_id;
15517
  }
15518
 
 
 
 
 
15519
  if ( $switched ) {
15520
  restore_current_blog();
15521
  }
@@ -15738,6 +16456,10 @@
15738
  }
15739
  }
15740
 
 
 
 
 
15741
  if ( $this->is_sync_cron_scheduled() &&
15742
  $context_blog_id == $this->get_sync_cron_blog_id()
15743
  ) {
@@ -15771,6 +16493,10 @@
15771
 
15772
  $this->update_multisite_data_after_site_deactivation( $context_blog_id );
15773
 
 
 
 
 
15774
  $current_blog_id = get_current_blog_id();
15775
 
15776
  $this->switch_to_blog( $context_blog_id );
@@ -15804,6 +16530,10 @@
15804
 
15805
  $this->update_multisite_data_after_site_deactivation( $context_blog_id );
15806
 
 
 
 
 
15807
  $current_blog_id = get_current_blog_id();
15808
 
15809
  $this->switch_to_blog( $context_blog_id );
@@ -15821,6 +16551,20 @@
15821
  $this->switch_to_blog( $current_blog_id );
15822
  }
15823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15824
  /**
15825
  * Executed after site re-activation.
15826
  *
@@ -15935,9 +16679,17 @@
15935
  * @return bool
15936
  */
15937
  function is_product_settings_page() {
 
 
 
 
 
 
 
15938
  return fs_starts_with(
15939
- fs_request_get( 'page', '', 'get' ),
15940
- $this->_menu->get_slug()
 
15941
  );
15942
  }
15943
 
@@ -16017,10 +16769,11 @@
16017
  *
16018
  * @param bool|string $topic
16019
  * @param bool|string $message
 
16020
  *
16021
  * @return string
16022
  */
16023
- function contact_url( $topic = false, $message = false ) {
16024
  $params = array();
16025
  if ( is_string( $topic ) ) {
16026
  $params['topic'] = $topic;
@@ -16029,6 +16782,10 @@
16029
  $params['message'] = $message;
16030
  }
16031
 
 
 
 
 
16032
  if ( $this->is_addon() ) {
16033
  $params['addon_id'] = $this->get_id();
16034
 
@@ -16067,7 +16824,7 @@
16067
  }
16068
 
16069
  /* Logger
16070
- ------------------------------------------------------------------------------------------------------------------*/
16071
  /**
16072
  * @param string $id
16073
  * @param bool $prefix_slug
@@ -16092,7 +16849,7 @@
16092
  }
16093
 
16094
  /* Security
16095
- ------------------------------------------------------------------------------------------------------------------*/
16096
  private static function _encrypt( $str ) {
16097
  if ( is_null( $str ) ) {
16098
  return null;
@@ -16312,20 +17069,6 @@
16312
  ) {
16313
  // Load site.
16314
  $this->_site = $site;
16315
-
16316
- // Load plans.
16317
- $this->_plans = $plans[ $this->_slug ];
16318
- if ( ! is_array( $this->_plans ) || empty( $this->_plans ) ) {
16319
- $this->_sync_plans();
16320
- } else {
16321
- for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
16322
- if ( $this->_plans[ $i ] instanceof FS_Plugin_Plan ) {
16323
- $this->_plans[ $i ] = self::decrypt_entity( $this->_plans[ $i ] );
16324
- } else {
16325
- unset( $this->_plans[ $i ] );
16326
- }
16327
- }
16328
- }
16329
  }
16330
 
16331
  $user = null;
@@ -16354,7 +17097,30 @@
16354
  /**
16355
  * This is a special fault tolerance mechanism to handle a scenario that the user data is missing.
16356
  */
16357
- $user = $this->sync_user_by_current_install();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16358
  }
16359
 
16360
  $this->_user = ( $user instanceof FS_User ) ?
@@ -16368,6 +17134,23 @@
16368
  }
16369
 
16370
  if ( is_object( $this->_site ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16371
  $this->_license = $this->_get_license_by_id( $this->_site->license_id );
16372
 
16373
  if ( $this->_site->version != $this->get_plugin_version() ) {
@@ -16386,6 +17169,15 @@
16386
  if ( $this->is_theme() ) {
16387
  $this->_register_account_hooks();
16388
  }
 
 
 
 
 
 
 
 
 
16389
  }
16390
 
16391
  /**
@@ -16465,17 +17257,129 @@
16465
  */
16466
  private function get_versions() {
16467
  $versions = array();
16468
- $versions['platform_version'] = get_bloginfo( 'version' );
16469
- $versions['sdk_version'] = $this->version;
16470
- $versions['programming_language_version'] = phpversion();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16471
 
16472
- foreach ( $versions as $k => $version ) {
16473
- if ( is_string( $versions[ $k ] ) && ! empty( $versions[ $k ] ) ) {
16474
- $versions[ $k ] = substr( $versions[ $k ], 0, 16 );
16475
- }
 
 
 
16476
  }
16477
 
16478
- return $versions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16479
  }
16480
 
16481
  /**
@@ -16530,23 +17434,22 @@
16530
  $versions = $this->get_versions();
16531
 
16532
  $params = array_merge( $versions, array(
16533
- 'user_firstname' => $current_user->user_firstname,
16534
- 'user_lastname' => $current_user->user_lastname,
16535
- 'user_nickname' => $current_user->user_nicename,
16536
- 'user_email' => $current_user->user_email,
16537
- 'user_ip' => WP_FS__REMOTE_ADDR,
16538
- 'plugin_slug' => $this->_slug,
16539
- 'plugin_id' => $this->get_id(),
16540
- 'plugin_public_key' => $this->get_public_key(),
16541
- 'plugin_version' => $this->get_plugin_version(),
16542
- 'return_url' => fs_nonce_url( $return_url, $activation_action ),
16543
- 'account_url' => fs_nonce_url( $this->_get_admin_page_url(
16544
  'account',
16545
  array( 'fs_action' => 'sync_user' )
16546
  ), 'sync_user' ),
16547
- 'is_premium' => $this->is_premium(),
16548
- 'is_active' => true,
16549
- 'is_uninstalled' => false,
 
16550
  ) );
16551
 
16552
  if ( $this->is_addon() ) {
@@ -16567,12 +17470,17 @@
16567
 
16568
  $site = $this->get_site_info( $site );
16569
 
16570
- $params = array_merge( $params, array(
 
 
 
 
 
 
 
 
16571
  'site_uid' => $site['uid'],
16572
  'site_url' => $site['url'],
16573
- 'site_name' => $site['title'],
16574
- 'language' => $site['language'],
16575
- 'charset' => $site['charset'],
16576
  ) );
16577
  }
16578
 
@@ -16597,6 +17505,10 @@
16597
  );
16598
  }
16599
 
 
 
 
 
16600
  return array_merge( $params, $override_with );
16601
  }
16602
 
@@ -16615,9 +17527,10 @@
16615
  * In this case, the user and site info will be sent to the server but no
16616
  * data will be saved to the WP installation's database.
16617
  * @param number|bool $trial_plan_id
16618
- * @param bool $is_disconnected Whether or not to opt in without tracking.
16619
  * @param null|bool $is_marketing_allowed
16620
  * @param array $sites If network-level opt-in, an array of containing details of sites.
 
16621
  *
16622
  * @return string|object
16623
  * @use WP_Error
@@ -16631,7 +17544,8 @@
16631
  $trial_plan_id = false,
16632
  $is_disconnected = false,
16633
  $is_marketing_allowed = null,
16634
- $sites = array()
 
16635
  ) {
16636
  $this->_logger->entrance();
16637
 
@@ -16655,7 +17569,7 @@
16655
  $fs_user,
16656
  false,
16657
  $trial_plan_id,
16658
- true,
16659
  true,
16660
  $sites
16661
  );
@@ -16723,13 +17637,15 @@
16723
  $params['is_marketing_allowed'] = $is_marketing_allowed;
16724
  }
16725
 
16726
- $params['is_disconnected'] = $is_disconnected;
16727
- $params['format'] = 'json';
 
 
16728
 
16729
  $request = array(
16730
  'method' => 'POST',
16731
  'body' => $params,
16732
- 'timeout' => WP_FS__DEBUG_SDK ? 60 : 30,
16733
  );
16734
 
16735
  $url = $this->add_show_pending( WP_FS__ADDRESS . '/action/service/user/install/' );
@@ -16815,7 +17731,8 @@
16815
  true ),
16816
  false,
16817
  $filtered_license_key,
16818
- ! empty( $params['trial_plan_id'] )
 
16819
  );
16820
  } else if ( isset( $decoded->install_secret_key ) ) {
16821
  return $this->install_with_new_user(
@@ -16828,6 +17745,9 @@
16828
  ( isset( $decoded->is_extensions_tracking_allowed ) && ! is_null( $decoded->is_extensions_tracking_allowed ) ?
16829
  $decoded->is_extensions_tracking_allowed :
16830
  null ),
 
 
 
16831
  $decoded->install_id,
16832
  $decoded->install_public_key,
16833
  $decoded->install_secret_key,
@@ -16844,6 +17764,9 @@
16844
  ( isset( $decoded->is_extensions_tracking_allowed ) && ! is_null( $decoded->is_extensions_tracking_allowed ) ?
16845
  $decoded->is_extensions_tracking_allowed :
16846
  null ),
 
 
 
16847
  $decoded->installs,
16848
  false
16849
  );
@@ -16941,15 +17864,11 @@
16941
  $this->_admin_notices->remove_sticky( 'connect_account' );
16942
 
16943
  if ( $this->is_pending_activation() || ! $this->has_settings_menu() ) {
16944
- // Remove pending activation sticky notice (if still exist).
16945
- $this->_admin_notices->remove_sticky( 'activation_pending' );
16946
-
16947
- // Remove plugin from pending activation mode.
16948
- unset( $this->_storage->is_pending_activation );
16949
 
16950
  if ( ! $this->is_paying_or_trial() ) {
16951
  $this->_admin_notices->add_sticky(
16952
- sprintf( $this->get_text_inline( '%s activation was successfully completed.', 'plugin-x-activation-message' ), '<b>' . $this->get_plugin_name() . '</b>' ),
16953
  'activation_complete'
16954
  );
16955
  }
@@ -17071,6 +17990,7 @@
17071
  fs_request_get( 'user_secret_key' ),
17072
  fs_request_get_bool( 'is_marketing_allowed', null ),
17073
  fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
 
17074
  $pending_sites_info['blog_ids'],
17075
  $pending_sites_info['license_key'],
17076
  $pending_sites_info['trial_plan_id']
@@ -17082,6 +18002,7 @@
17082
  fs_request_get( 'user_secret_key' ),
17083
  fs_request_get_bool( 'is_marketing_allowed', null ),
17084
  fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
 
17085
  fs_request_get( 'install_id' ),
17086
  fs_request_get( 'install_public_key' ),
17087
  fs_request_get( 'install_secret_key' ),
@@ -17090,7 +18011,13 @@
17090
  );
17091
  }
17092
  } else if ( fs_request_has( 'pending_activation' ) ) {
17093
- $this->set_pending_confirmation( fs_request_get( 'user_email' ), true );
 
 
 
 
 
 
17094
  }
17095
  }
17096
  }
@@ -17138,6 +18065,7 @@
17138
  * @param string $user_secret_key
17139
  * @param bool|null $is_marketing_allowed
17140
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
 
17141
  * @param number $install_id
17142
  * @param string $install_public_key
17143
  * @param string $install_secret_key
@@ -17152,6 +18080,7 @@
17152
  $user_secret_key,
17153
  $is_marketing_allowed,
17154
  $is_extensions_tracking_allowed,
 
17155
  $install_id,
17156
  $install_public_key,
17157
  $install_secret_key,
@@ -17185,7 +18114,7 @@
17185
  $site->secret_key = $install_secret_key;
17186
 
17187
  $this->_site = $site;
17188
- $site_result = $this->get_api_site_scope()->get();
17189
  $site = new FS_Site( $site_result );
17190
  $this->_site = $site;
17191
 
@@ -17193,7 +18122,10 @@
17193
  $this->disable_opt_in_notice_and_lock_user();
17194
  }
17195
 
17196
- $this->update_extensions_tracking_flag( $is_extensions_tracking_allowed );
 
 
 
17197
 
17198
  return $this->setup_account(
17199
  $this->_user,
@@ -17214,6 +18146,7 @@
17214
  * @param string $user_secret_key
17215
  * @param bool|null $is_marketing_allowed
17216
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
 
17217
  * @param array $site_ids
17218
  * @param bool $license_key
17219
  * @param bool $trial_plan_id
@@ -17227,6 +18160,7 @@
17227
  $user_secret_key,
17228
  $is_marketing_allowed,
17229
  $is_extensions_tracking_allowed,
 
17230
  $site_ids,
17231
  $license_key = false,
17232
  $trial_plan_id = false,
@@ -17238,7 +18172,10 @@
17238
  $this->disable_opt_in_notice_and_lock_user();
17239
  }
17240
 
17241
- $this->update_extensions_tracking_flag( $is_extensions_tracking_allowed );
 
 
 
17242
 
17243
  $sites = array();
17244
  foreach ( $site_ids as $site_id ) {
@@ -17259,6 +18196,7 @@
17259
  * @param string $user_secret_key
17260
  * @param bool|null $is_marketing_allowed
17261
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
 
17262
  * @param object[] $installs
17263
  * @param bool $redirect
17264
  * @param bool $auto_install Since 1.2.1.7 If `true` and setting up an account with a valid license, will redirect (or return a URL) to the account page with a special parameter to trigger the auto installation processes.
@@ -17271,6 +18209,7 @@
17271
  $user_secret_key,
17272
  $is_marketing_allowed,
17273
  $is_extensions_tracking_allowed,
 
17274
  array $installs,
17275
  $redirect = true,
17276
  $auto_install = false
@@ -17281,7 +18220,10 @@
17281
  $this->disable_opt_in_notice_and_lock_user();
17282
  }
17283
 
17284
- $this->update_extensions_tracking_flag( $is_extensions_tracking_allowed );
 
 
 
17285
 
17286
  $install_ids = array();
17287
 
@@ -17289,12 +18231,13 @@
17289
  $install_ids[] = $install->id;
17290
  }
17291
 
17292
- $left = count( $install_ids );
17293
- $offset = 0;
 
17294
 
17295
  $installs = array();
17296
  while ( $left > 0 ) {
17297
- $result = $this->get_api_user_scope()->get( "/plugins/{$this->_module_id}/installs.json?ids=" . implode( ',', array_slice( $install_ids, $offset, 25 ) ) );
17298
 
17299
  if ( ! $this->is_api_result_object( $result, 'installs' ) ) {
17300
  // @todo Handle API error.
@@ -17302,7 +18245,8 @@
17302
 
17303
  $installs = array_merge( $installs, $result->installs );
17304
 
17305
- $left -= 25;
 
17306
  }
17307
 
17308
  foreach ( $installs as &$install ) {
@@ -17332,7 +18276,8 @@
17332
  $email = false,
17333
  $redirect = true,
17334
  $license_key = false,
17335
- $is_pending_trial = false
 
17336
  ) {
17337
  if ( $this->_ignore_pending_mode ) {
17338
  /**
@@ -17342,12 +18287,12 @@
17342
  * @author Vova Feldman
17343
  * @since 1.2.1.6
17344
  */
17345
- $this->skip_connection( null, fs_is_network_admin() );
17346
  } else {
17347
  // Install must be activated via email since
17348
  // user with the same email already exist.
17349
  $this->_storage->is_pending_activation = true;
17350
- $this->_add_pending_activation_notice( $email, $is_pending_trial );
17351
  }
17352
 
17353
  if ( ! empty( $license_key ) ) {
@@ -17362,8 +18307,8 @@
17362
 
17363
  $next_page = $this->get_after_activation_url( 'after_pending_connect_url' );
17364
 
17365
- // Reload the page with with pending activation message.
17366
  if ( $redirect ) {
 
17367
  fs_redirect( $next_page );
17368
  }
17369
 
@@ -17392,7 +18337,10 @@
17392
  */
17393
  $license_key = fs_request_get( 'license_secret_key' );
17394
 
17395
- $this->update_extensions_tracking_flag( fs_request_get_bool( 'is_extensions_tracking_allowed', null ) );
 
 
 
17396
 
17397
  $this->install_with_current_user( $license_key );
17398
  }
@@ -17410,7 +18358,7 @@
17410
  *
17411
  * @return object|string If redirect is `false`, returns the next page the user should be redirected to, or the API error object if failed to install.
17412
  */
17413
- private function install_with_current_user(
17414
  $license_key = false,
17415
  $trial_plan_id = false,
17416
  $sites = array(),
@@ -17793,9 +18741,6 @@
17793
  $this->send_installs_update();
17794
  }
17795
 
17796
- // Switch install context back to the first install.
17797
- $this->_site = $first_install;
17798
-
17799
  $current_blog = get_current_blog_id();
17800
 
17801
  foreach ( $blog_2_install_map as $blog_id => $install ) {
@@ -17804,7 +18749,12 @@
17804
  $this->do_action( 'after_account_connection', $this->_user, $install );
17805
  }
17806
 
17807
- $this->switch_to_blog( $current_blog );
 
 
 
 
 
17808
 
17809
  $this->do_action( 'after_network_account_connection', $this->_user, $blog_2_install_map );
17810
  }
@@ -17852,9 +18802,7 @@
17852
  $parent_fs->_admin_notices->remove_sticky( 'connect_account' );
17853
 
17854
  if ( $parent_fs->is_pending_activation() ) {
17855
- $parent_fs->_admin_notices->remove_sticky( 'activation_pending' );
17856
-
17857
- unset( $parent_fs->_storage->is_pending_activation );
17858
  }
17859
 
17860
  // Get user information based on parent's plugin.
@@ -17908,6 +18856,10 @@
17908
  // return;
17909
  // }
17910
 
 
 
 
 
17911
  /**
17912
  * When running from a site admin with a network activated module and the connection
17913
  * was NOT delegated and the user still haven't skipped or opted-in, then hide the
@@ -18862,7 +19814,7 @@
18862
  *
18863
  * @return string
18864
  */
18865
- private static function get_ajax_action_static( $tag, $module_id = null ) {
18866
  $action = "fs_{$tag}";
18867
 
18868
  if ( ! empty( $module_id ) ) {
@@ -18885,10 +19837,10 @@
18885
  * @uses do_action()
18886
  */
18887
  function do_action( $tag, $arg = '' ) {
18888
- $this->_logger->entrance( $tag );
18889
-
18890
  $args = func_get_args();
18891
 
 
 
18892
  call_user_func_array( 'do_action', array_merge(
18893
  array( $this->get_action_tag( $tag ) ),
18894
  array_slice( $args, 1 ) )
@@ -19028,6 +19980,30 @@
19028
  wp_send_json( $result );
19029
  }
19030
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19031
  /**
19032
  * Apply filter, specific for the current context plugin.
19033
  *
@@ -19042,9 +20018,10 @@
19042
  * @uses apply_filters()
19043
  */
19044
  function apply_filters( $tag, $value ) {
 
 
19045
  $this->_logger->entrance( $tag );
19046
 
19047
- $args = func_get_args();
19048
  array_unshift( $args, $this->get_unique_affix() );
19049
 
19050
  return call_user_func_array( 'fs_apply_filter', $args );
@@ -19105,7 +20082,7 @@
19105
  }
19106
 
19107
  /* Account Page
19108
- ------------------------------------------------------------------------------------------------------------------*/
19109
  /**
19110
  * Update site information.
19111
  *
@@ -19116,7 +20093,7 @@
19116
  * @param null|int $network_level_or_blog_id Since 2.0.0
19117
  * @param \FS_Site $site Since 2.0.0
19118
  */
19119
- private function _store_site( $store = true, $network_level_or_blog_id = null, FS_Site $site = null ) {
19120
  $this->_logger->entrance();
19121
 
19122
  if ( is_null( $site ) ) {
@@ -19131,9 +20108,12 @@
19131
 
19132
  $site_clone = clone $site;
19133
 
19134
- $sites = self::get_all_sites( $this->_module_type, $network_level_or_blog_id );
19135
 
19136
- if ( is_object( $this->_user ) && $this->_user->id != $site->user_id ) {
 
 
 
19137
  $this->sync_user_by_current_install( $site->user_id );
19138
 
19139
  $prev_stored_user_id = $this->_storage->get( 'prev_user_id', false, $network_level_or_blog_id );
@@ -19158,7 +20138,26 @@
19158
 
19159
  $sites[ $this->_slug ] = $site_clone;
19160
 
19161
- $this->set_account_option( 'sites', $sites, $store, $network_level_or_blog_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19162
  }
19163
 
19164
  /**
@@ -20399,10 +21398,10 @@
20399
  $this->switch_to_blog( $current_blog_id );
20400
  }
20401
 
20402
- $result = $this->send_install_update( array(), true );
20403
  $is_valid = $this->is_api_result_entity( $result );
20404
  } else {
20405
- $result = $this->send_installs_update( array(), true );
20406
  $is_valid = $this->is_api_result_object( $result, 'installs' );
20407
  }
20408
 
@@ -20412,7 +21411,7 @@
20412
  $this->switch_to_blog( $this->_storage->network_install_blog_id );
20413
  }
20414
 
20415
- // Show API messages only if not background sync or if paying customer.
20416
  if ( ! $background || $this->is_paying() ) {
20417
  // Try to ping API to see if not blocked.
20418
  if ( ! FS_Api::test() ) {
@@ -20422,25 +21421,49 @@
20422
  * @author Vova Feldman (@svovaf)
20423
  * @since 1.1.6 Only show message related to one of the Freemius powered plugins. Once it will be resolved it will fix the issue for all plugins anyways. There's no point to scare users with multiple error messages.
20424
  */
20425
- $api = $this->get_api_site_scope();
20426
 
20427
  if ( ! self::$_global_admin_notices->has_sticky( 'api_blocked' ) ) {
20428
- self::$_global_admin_notices->add(
20429
- sprintf(
20430
- $this->get_text_inline( 'Your server is blocking the access to Freemius\' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s', 'server-blocking-access' ),
20431
- $this->get_plugin_name(),
20432
- '<b>' . implode( ', ', $this->apply_filters( 'api_domains', array(
20433
- 'api.freemius.com',
20434
- 'wp.freemius.com'
20435
- ) ) ) . '</b>'
20436
- ) . '<br> ' . $this->get_text_inline( 'Error received from the server:', 'server-error-message' ) . var_export( $result->error, true ),
20437
- $this->get_text_x_inline( 'Oops', 'exclamation', 'oops' ) . '...',
20438
- 'error',
20439
- $background,
20440
- 'api_blocked'
20441
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20442
  }
20443
- } else {
20444
  // Authentication params are broken.
20445
  $this->_admin_notices->add(
20446
  $this->get_text_inline( 'It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again.', 'wrong-authentication-param-message' ) . '<br> ' . $this->get_text_inline( 'Error received from the server:', 'server-error-message' ) . var_export( $result->error, true ),
@@ -20454,6 +21477,9 @@
20454
  return;
20455
  }
20456
 
 
 
 
20457
  if ( $is_site_level_sync ) {
20458
  $site = new FS_Site( $result );
20459
  } else {
@@ -20645,7 +21671,7 @@
20645
  }
20646
 
20647
  if ( ! $this->is_addon() &&
20648
- $this->_site->is_beta() !== $site->is_beta
20649
  ) {
20650
  // Beta flag updated.
20651
  $this->_site = $site;
@@ -21200,8 +22226,7 @@
21200
  if ( ! $this->is_api_result_entity( $plan ) ) {
21201
  // Some API error while trying to start the trial.
21202
  $this->_admin_notices->add(
21203
- sprintf( $this->get_text_inline( 'Unexpected API error. Please contact the %s\'s author with the following error.', 'unexpected-api-error' ), $this->_module_type )
21204
- . ' ' . var_export( $plan, true ),
21205
  $oops_text,
21206
  'error'
21207
  );
@@ -21379,13 +22404,18 @@
21379
  ) {
21380
  $this->_logger->entrance();
21381
 
 
 
 
 
21382
  $switch_to_blog_id = null;
21383
 
21384
  /**
21385
  * @since 1.1.7.3 Check for plugin updates from Freemius only if opted-in.
21386
  * @since 1.1.7.4 Also check updates for add-ons.
21387
  */
21388
- if ( ! $this->is_registered() &&
 
21389
  ! $this->_is_addon_id( $addon_id )
21390
  ) {
21391
  if ( ! is_multisite() ) {
@@ -21395,6 +22425,10 @@
21395
  $installs_map = $this->get_blog_install_map();
21396
 
21397
  foreach ( $installs_map as $blog_id => $install ) {
 
 
 
 
21398
  /**
21399
  * @var FS_Site $install
21400
  */
@@ -21491,9 +22525,11 @@
21491
  private function get_latest_download_api_url( $plugin_id = false ) {
21492
  $this->_logger->entrance();
21493
 
21494
- return $this->get_api_site_scope()->get_signed_url(
21495
  $this->_get_latest_version_endpoint( $plugin_id, 'zip' )
21496
  );
 
 
21497
  }
21498
 
21499
  /**
@@ -21688,7 +22724,6 @@
21688
  private function update_email( $new_email ) {
21689
  $this->_logger->entrance();
21690
 
21691
-
21692
  $api = $this->get_api_user_scope();
21693
  $user = $api->call( "?plugin_id={$this->_plugin->id}&fields=id,email,is_verified", 'put', array(
21694
  'email' => $new_email,
@@ -21704,7 +22739,6 @@
21704
  $this->_store_user();
21705
  } else {
21706
  // handle different error cases.
21707
-
21708
  }
21709
 
21710
  return $user;
@@ -21780,15 +22814,32 @@
21780
  * @uses FS_Api
21781
  *
21782
  * @param string $candidate_email
 
21783
  *
21784
  * @return bool Is ownership change successfully initiated.
21785
  */
21786
- private function init_change_owner( $candidate_email ) {
21787
  $this->_logger->entrance();
21788
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21789
  $api = $this->get_api_site_scope();
21790
  $result = $api->call( "/users/{$this->_user->id}.json", 'put', array(
21791
  'email' => $candidate_email,
 
 
21792
  'after_confirm_url' => $this->_get_admin_page_url(
21793
  'account',
21794
  array( 'fs_action' => 'change_owner' )
@@ -21810,28 +22861,113 @@
21810
  private function complete_change_owner() {
21811
  $this->_logger->entrance();
21812
 
21813
- $site_result = $this->get_api_site_scope( true )->get();
21814
- $site = new FS_Site( $site_result );
21815
- $this->_site = $site;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21816
 
21817
- $user = new FS_User();
21818
- $user->id = fs_request_get( 'user_id' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21819
 
21820
  // Validate install's user and given user.
21821
  if ( $user->id != $this->_site->user_id ) {
 
 
21822
  return false;
21823
  }
21824
 
21825
- $user->public_key = fs_request_get( 'user_public_key' );
21826
- $user->secret_key = fs_request_get( 'user_secret_key' );
21827
 
21828
  // Fetch new user information.
21829
- $this->_user = $user;
21830
  $user_result = $this->get_api_user_scope( true )->get();
21831
  $user = new FS_User( $user_result );
21832
  $this->_user = $user;
21833
 
21834
- $this->_set_account( $user, $site );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21835
 
21836
  return true;
21837
  }
@@ -22076,26 +23212,23 @@
22076
 
22077
  if ( $is_parent_plugin_action ) {
22078
  if ( $is_network_action && ! empty( $blog_id ) ) {
22079
- if ( $this->is_registered() ) {
22080
- if ( $this->is_tracking_prohibited() ) {
22081
- if ( $this->allow_site_tracking() ) {
22082
  $this->_admin_notices->add(
22083
- sprintf( $this->get_text_inline( 'We appreciate your help in making the %s better by letting us track some usage data.', 'opt-out-message-appreciation' ), $this->_module_type ),
22084
  $this->get_text_inline( 'Thank you!', 'thank-you' )
22085
  );
22086
  }
22087
  } else {
22088
- if ( $this->stop_site_tracking() ) {
 
 
22089
  $this->_admin_notices->add(
22090
  sprintf(
22091
- $this->get_text_inline( 'We will no longer be sending any usage data of %s on %s to %s.', 'opted-out-successfully' ),
22092
- $this->get_plugin_title(),
22093
- fs_strip_url_protocol( get_site_url( $blog_id ) ),
22094
- sprintf(
22095
- '<a href="%s" target="_blank" rel="noopener">%s</a>',
22096
- 'https://freemius.com',
22097
- 'freemius.com'
22098
- )
22099
  )
22100
  );
22101
  }
@@ -22243,10 +23376,15 @@
22243
  $state = fs_request_get( 'state', 'init' );
22244
  switch ( $state ) {
22245
  case 'init':
22246
- $candidate_email = fs_request_get( 'candidate_email', '' );
 
22247
 
22248
- if ( $this->init_change_owner( $candidate_email ) ) {
22249
- $this->_admin_notices->add( sprintf( $this->get_text_inline( '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.', 'change-owner-request-sent-x' ), '<b>' . $this->_user->email . '</b>' ) );
 
 
 
 
22250
  }
22251
  break;
22252
  case 'owner_confirmed':
@@ -22269,37 +23407,6 @@
22269
 
22270
  return;
22271
 
22272
- case 'update_email':
22273
- check_admin_referer( 'update_email' );
22274
-
22275
- $new_email = fs_request_get( 'fs_email_' . $this->get_unique_affix(), '' );
22276
- $result = $this->update_email( $new_email );
22277
-
22278
- if ( isset( $result->error ) ) {
22279
- switch ( $result->error->code ) {
22280
- case 'user_exist':
22281
- $this->_admin_notices->add(
22282
- $this->get_text_inline( 'Sorry, we could not complete the email update. Another user with the same email is already registered.', 'user-exist-message' ) . ' ' .
22283
- sprintf( $this->get_text_inline( 'If you would like to give up the ownership of the %s\'s account to %s click the Change Ownership button.', 'user-exist-message_ownership' ), $this->_module_type, '<b>' . $new_email . '</b>' ) .
22284
- sprintf(
22285
- '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s &nbsp;&#10140;</button></a>',
22286
- $this->get_account_url( 'change_owner', array(
22287
- 'state' => 'init',
22288
- 'candidate_email' => $new_email
22289
- ) ),
22290
- $this->get_text_inline( 'Change Ownership', 'change-ownership' )
22291
- ),
22292
- $oops_text,
22293
- 'error'
22294
- );
22295
- break;
22296
- }
22297
- } else {
22298
- $this->_admin_notices->add( $this->get_text_inline( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.', 'email-updated-message' ) );
22299
- }
22300
-
22301
- return;
22302
-
22303
  case 'update_user_name':
22304
  check_admin_referer( 'update_user_name' );
22305
 
@@ -22461,7 +23568,26 @@
22461
 
22462
  fs_enqueue_local_style( 'fs_affiliation', '/admin/affiliation.css' );
22463
 
22464
- $vars = array( 'id' => $this->_module_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22465
  echo $this->apply_filters( "/forms/affiliation.php", fs_get_template( '/forms/affiliation.php', $vars ) );
22466
  }
22467
 
@@ -22562,7 +23688,7 @@
22562
  }
22563
 
22564
  /* Pricing & Upgrade
22565
- ------------------------------------------------------------------------------------------------------------------*/
22566
  /**
22567
  * Render pricing page.
22568
  *
@@ -22704,7 +23830,17 @@
22704
  }
22705
 
22706
  static function _clean_admin_content_section_hook() {
22707
- self::_hide_admin_notices();
 
 
 
 
 
 
 
 
 
 
22708
 
22709
  // Hide footer.
22710
  echo '<style>#wpfooter { display: none !important; }</style>';
@@ -22721,17 +23857,17 @@
22721
  }
22722
 
22723
  /* CSS & JavaScript
22724
- ------------------------------------------------------------------------------------------------------------------*/
22725
  /* function _enqueue_script($handle, $src) {
22726
- $url = plugins_url( substr( WP_FS__DIR_JS, strlen( $this->_plugin_dir_path ) ) . '/assets/js/' . $src );
22727
 
22728
- $this->_logger->entrance( 'script = ' . $url );
22729
 
22730
- wp_enqueue_script( $handle, $url );
22731
- }*/
22732
 
22733
  /* SDK
22734
- ------------------------------------------------------------------------------------------------------------------*/
22735
  private $_user_api;
22736
 
22737
  /**
@@ -22743,7 +23879,7 @@
22743
  *
22744
  * @return FS_Api
22745
  */
22746
- private function get_api_user_scope( $flush = false ) {
22747
  if ( ! isset( $this->_user_api ) || $flush ) {
22748
  $this->_user_api = $this->get_api_user_scope_by_user( $this->_user );
22749
  }
@@ -22822,13 +23958,56 @@
22822
  $this->_site->public_key,
22823
  ! $this->is_live(),
22824
  $this->_site->secret_key,
22825
- $this->get_sdk_version()
 
22826
  );
22827
  }
22828
 
22829
  return $this->_site_api;
22830
  }
22831
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22832
  private $_plugin_api;
22833
 
22834
  /**
@@ -23264,7 +24443,7 @@
23264
  }
23265
 
23266
  /* Action Links
23267
- ------------------------------------------------------------------------------------------------------------------*/
23268
  private $_action_links_hooked = false;
23269
  private $_action_links = array();
23270
 
@@ -23435,15 +24614,6 @@
23435
 
23436
  $this->_logger->entrance();
23437
 
23438
- /**
23439
- * @author Vova Feldman (@svovaf)
23440
- * @since 2.3.2 Allow opting out from usage-tracking for paid products too by giving the appropriate warning letting the user know the automatic updates mechanism cannot function without an ongoing connection to the licensing and updates engine.
23441
- */
23442
- /*if ( $this->is_premium() ) {
23443
- // Don't add opt-in/out for premium code base.
23444
- return;
23445
- }*/
23446
-
23447
  if ( $this->is_only_premium() && $this->is_free_plan() ) {
23448
  // Don't add tracking links for premium-only products that were opted-in by relation (add-on or a parent product) before activating any license.
23449
  return;
@@ -23451,10 +24621,13 @@
23451
 
23452
  if (
23453
  $this->is_addon() &&
23454
- ! $this->is_only_premium() &&
23455
- $this->_parent->is_anonymous()
23456
  ) {
23457
- return;
 
 
 
 
23458
  }
23459
 
23460
  if ( fs_is_network_admin() ) {
@@ -23503,23 +24676,15 @@
23503
  }
23504
  }
23505
 
23506
- if ( $this->add_ajax_action( 'stop_tracking', array( &$this, '_stop_tracking_callback' ) ) ) {
23507
- return;
23508
- }
23509
-
23510
- if ( $this->add_ajax_action( 'allow_tracking', array( &$this, '_allow_tracking_callback' ) ) ) {
23511
- return;
23512
- }
23513
-
23514
- if ( $this->add_ajax_action( 'update_tracking_permission', array( &$this, '_update_tracking_permission_callback' ) ) ) {
23515
  return;
23516
  }
23517
 
23518
  $link_text_id = '';
23519
  $url = '#';
23520
 
23521
- if ( $this->is_registered() ) {
23522
- if ( $this->is_tracking_allowed() ) {
23523
  $link_text_id = $this->get_text_inline( 'Opt Out', 'opt-out' );
23524
  } else {
23525
  $link_text_id = $this->get_text_inline( 'Opt In', 'opt-in' );
@@ -23716,9 +24881,12 @@
23716
  */
23717
  private function is_premium_version_installed() {
23718
  $premium_plugin_basename = $this->premium_plugin_basename();
23719
- $premium_plugin = get_plugins( '/' . dirname( $premium_plugin_basename ) );
23720
 
23721
- return ! empty( $premium_plugin );
 
 
 
 
23722
  }
23723
 
23724
  /**
@@ -23754,7 +24922,9 @@
23754
  * @author Leo Fajardo (@leorw)
23755
  * @since 2.2.1
23756
  */
23757
- $premium_plugin_basename = $this->premium_plugin_basename();
 
 
23758
 
23759
  return sprintf(
23760
  /* translators: %1$s: Product title; %2$s: Plan title */
@@ -23763,7 +24933,9 @@
23763
  $plan_title,
23764
  sprintf(
23765
  '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s</button></a>',
23766
- wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $premium_plugin_basename, 'activate-plugin_' . $premium_plugin_basename ),
 
 
23767
  esc_html( sprintf(
23768
  /* translators: %s: Plan title */
23769
  $this->get_text_inline( 'Activate %s features', 'activate-x-features' ),
@@ -23788,7 +24960,7 @@
23788
  ) ),
23789
  $deactivation_step,
23790
  $this->get_text_inline( 'Upload and activate the downloaded version', 'upload-and-activate' ),
23791
- $this->apply_filters( 'upload_and_install_video_url', '//bit.ly/upload-wp-' . $this->_module_type . 's' ),
23792
  $this->get_text_inline( 'How to upload and activate?', 'howto-upload-activate' )
23793
  );
23794
  }
@@ -24241,8 +25413,10 @@
24241
  function _tabs_capture() {
24242
  $this->_logger->entrance();
24243
 
24244
- if ( ! $this->is_product_settings_page() ||
24245
- ! $this->is_matching_url( $this->main_menu_url() )
 
 
24246
  ) {
24247
  return;
24248
  }
@@ -24296,8 +25470,10 @@
24296
  function _store_tabs_styles() {
24297
  $this->_logger->entrance();
24298
 
24299
- if ( ! $this->is_product_settings_page() ||
24300
- ! $this->is_matching_url( $this->main_menu_url() )
 
 
24301
  ) {
24302
  return;
24303
  }
377
  const REASON_DIDNT_WORK_AS_EXPECTED = 14;
378
  const REASON_TEMPORARY_DEACTIVATION = 15;
379
 
380
+ #endregion
381
+
382
  /**
383
  * @author Leo Fajardo (@leorw)
384
  * @since 2.3.1
394
  */
395
  private $_pricing_js_path = null;
396
 
397
+ const VERSION_MAX_CHARS = 16;
398
+ const LANGUAGE_MAX_CHARS = 8;
399
 
400
  /* Ctor
401
  ------------------------------------------------------------------------------------------------------------------*/
411
  * @param bool $is_init Since 1.2.1 Is initiation sequence.
412
  */
413
  private function __construct( $module_id, $slug = false, $is_init = false ) {
414
+ $main_file = false;
415
+
416
  if ( $is_init && is_numeric( $module_id ) && is_string( $slug ) ) {
417
+ $main_file = $this->store_id_slug_type_path_map( $module_id, $slug );
418
  }
419
 
420
  $this->_module_id = $module_id;
429
 
430
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $this->get_unique_affix(), WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
431
 
432
+ $this->_plugin_main_file_path = $this->_find_caller_plugin_file( $is_init, $main_file );
433
  $this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
434
  $this->_plugin_basename = $this->get_plugin_basename();
435
  $this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
524
  * @author Leo Fajardo (@leorw)
525
  * @since 1.2.2
526
  */
527
+ ( is_object( $this->_plugin ) && isset( $this->_plugin->title ) ?
528
+ $this->_plugin->title :
529
+ $this->get_plugin_name()
530
+ ),
531
  $this->get_unique_affix()
532
  );
533
 
941
  * @param string $sdk_version
942
  */
943
  function _sdk_version_update( $sdk_prev_version, $sdk_version ) {
 
 
 
944
  if ( empty( $sdk_prev_version ) ) {
945
  return;
946
  }
947
 
948
+ if (
949
+ version_compare( $sdk_prev_version, '2.5.1', '<' ) &&
950
+ version_compare( $sdk_version, '2.5.1', '>=' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951
  ) {
952
+ if ( $this->is_registered( true ) ) {
953
+ /**
954
+ * Migrate to new permissions layer.
955
+ */
956
+ require_once WP_FS__DIR_INCLUDES . '/supplements/fs-migration-2.5.1.php';
 
 
 
 
 
 
957
 
958
+ $install_by_blog_id = is_multisite() ?
959
+ $this->get_blog_install_map() :
960
+ array( 0 => $this->_site );
961
 
962
+ fs_migrate_251( $this, $install_by_blog_id );
963
  }
964
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
965
  }
966
 
967
  /**
1012
  }
1013
  }
1014
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1015
  /**
1016
  * @author Vova Feldman (@svovaf)
1017
  * @since 1.2.2.7
1348
  }
1349
  }
1350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1351
  /**
1352
  * Opens the support forum subemenu item in a new browser page.
1353
  *
1458
  }
1459
 
1460
  if ( $this->is_plugin() ) {
1461
+ if ( version_compare( $GLOBALS['wp_version'], '5.1', '<' ) ) {
1462
  add_action( 'wpmu_new_blog', array( $this, '_after_new_blog_callback' ), 10, 6 );
1463
+ } else {
1464
+ add_action( 'wp_initialize_site', array( $this, '_after_wp_initialize_site_callback' ), 11, 2 );
1465
  }
1466
 
1467
  register_deactivation_hook( $this->_plugin_main_file_path, array( &$this, '_deactivate_plugin_hook' ) );
1471
  add_action( 'deactivate_blog', array( &$this, '_after_site_deactivated_callback' ) );
1472
  add_action( 'archive_blog', array( &$this, '_after_site_deactivated_callback' ) );
1473
  add_action( 'make_spam_blog', array( &$this, '_after_site_deactivated_callback' ) );
1474
+
1475
+ if ( version_compare( $GLOBALS['wp_version'], '5.1', '<' ) ) {
1476
+ add_action( 'deleted_blog', array( $this, '_after_site_deleted_callback' ), 10, 2 );
1477
+ } else {
1478
+ add_action( 'wp_delete_site', array( $this, '_after_wpsite_deleted_callback' ) );
1479
+ }
1480
 
1481
  add_action( 'activate_blog', array( &$this, '_after_site_reactivated_callback' ) );
1482
  add_action( 'unarchive_blog', array( &$this, '_after_site_reactivated_callback' ) );
1501
  add_action( 'admin_init', array( &$this, '_add_premium_version_upgrade_selection' ) );
1502
  add_action( 'admin_init', array( &$this, '_add_beta_mode_update_handler' ) );
1503
  add_action( 'admin_init', array( &$this, '_add_user_change_option' ) );
1504
+ add_action( 'admin_init', array( &$this, '_add_email_address_update_option' ) );
1505
 
1506
  $this->add_ajax_action( 'update_billing', array( &$this, '_update_billing_ajax_action' ) );
1507
  $this->add_ajax_action( 'start_trial', array( &$this, '_start_trial_ajax_action' ) );
1873
  return;
1874
  }
1875
 
1876
+ if (
1877
+ ( self::is_plugins_page() && $this->is_plugin() ) ||
1878
+ ( self::is_themes_page() && $this->is_theme() ) ||
1879
+ fs_request_is_action_secure( $this->get_unique_affix() . '_reconnect' )
1880
+ ) {
1881
+ $this->_add_tracking_links();
1882
+ }
1883
 
1884
  if ( self::is_plugins_page() && $this->is_plugin() ) {
1885
  $this->hook_plugin_action_links();
1925
  /**
1926
  * Leverage backtrace to find caller plugin file path.
1927
  *
1928
+ * @param bool $is_init Is initiation sequence.
1929
+ * @param string $main_file Since 2.5.0 expects the module's main file path to potentially purge the cached path.
 
 
1930
  *
1931
  * @return string
1932
+ * @since 1.0.6
1933
+ *
1934
+ * @author Vova Feldman (@svovaf)
1935
  */
1936
+ private function _find_caller_plugin_file( $is_init = false, $main_file = '' ) {
1937
  // Try to load the cached value of the file path.
1938
  if ( isset( $this->_storage->plugin_main_file ) ) {
1939
  $plugin_main_file = $this->_storage->plugin_main_file;
1940
  if ( ! empty( $plugin_main_file->path ) ) {
1941
  $absolute_path = $this->get_absolute_path( $plugin_main_file->path );
1942
  if ( file_exists( $absolute_path ) ) {
1943
+ if ( $is_init && $absolute_path !== $this->get_absolute_path( $main_file ) ) {
1944
+ // Update cached path if not matching the actual path.
1945
+ $plugin_main_file->path = $main_file;
1946
+ $this->_storage->plugin_main_file = $plugin_main_file;
1947
+ }
1948
+
1949
  return $absolute_path;
1950
  }
1951
  }
1986
  * Only the original instantiator that calls dynamic_init can modify the module's path.
1987
  */
1988
  // Find caller module.
 
1989
  $this->_storage->plugin_main_file = (object) array(
1990
+ 'path' => $main_file,
1991
  );
1992
 
1993
+ return $this->get_absolute_path( $main_file );
1994
  }
1995
 
1996
  /**
2052
  * @param number $module_id
2053
  * @param string $slug
2054
  *
2055
+ * @return string Since 2.5.0 return the module's main file path.
2056
+ *
2057
  * @since 1.2.2
2058
  */
2059
  private function store_id_slug_type_path_map( $module_id, $slug ) {
2075
  $store_option = true;
2076
  }
2077
 
2078
+ $find_caller = empty( $id_slug_type_path_map[ $module_id ]['path'] );
2079
+
2080
+ if ( ! $find_caller ) {
2081
+ /**
2082
+ * This verification is for cases when suddenly the same module
2083
+ * is installed but with a different folder name.
2084
+ *
2085
+ * @author Vova Feldman (@svovaf)
2086
+ * @since 1.2.3
2087
+ */
2088
+ $find_caller = ! file_exists( $this->get_absolute_path(
2089
+ $id_slug_type_path_map[ $module_id ]['path'],
2090
+ $id_slug_type_path_map[ $module_id ]['type']
2091
+ ) );
2092
+ }
2093
+
2094
+ foreach ( $id_slug_type_path_map as $id => $data ) {
2095
+ if ( empty( $id ) ) {
2096
+ // Remove maps with empty module ID.
2097
+ unset( $id_slug_type_path_map[ $id ] );
2098
+ $store_option = true;
2099
+ continue;
2100
+ }
2101
+
2102
+ /**
2103
+ * If the module's main file path is identical to the main file path of another module then it means that the cached path of the current module or the other one with the same path is wrong, and therefore, we need to recalculate those paths.
2104
+ *
2105
+ * @author Vova Feldman (@svovaf)
2106
+ * @since 2.5.0
2107
+ */
2108
+ if ( ! $find_caller ) {
2109
+ if ( $id == $module_id ) {
2110
+ continue;
2111
+ }
2112
+
2113
+ if (
2114
+ isset( $data['path'] ) &&
2115
+ $data['path'] === $id_slug_type_path_map[ $module_id ]['path']
2116
+ ) {
2117
+ $find_caller = true;
2118
+ }
2119
+ }
2120
+ }
2121
+
2122
+ if ( $find_caller ) {
2123
+ $caller_main_file_and_type = $this->get_caller_main_file_and_type( $module_id );
2124
 
2125
  $id_slug_type_path_map[ $module_id ]['type'] = $caller_main_file_and_type->module_type;
2126
  $id_slug_type_path_map[ $module_id ]['path'] = $caller_main_file_and_type->path;
2131
  if ( $store_option ) {
2132
  self::$_accounts->set_option( 'id_slug_type_path_map', $id_slug_type_path_map, true );
2133
  }
2134
+
2135
+ return $id_slug_type_path_map[ $module_id ]['path'];
2136
  }
2137
 
2138
  /**
2146
  * add-ons are relying on loading the SDK from the parent module, and also allows themes including the
2147
  * SDK an internal file instead of directly from functions.php.
2148
  * @since 1.2.1.7 Knows how to handle cases when an add-on includes the parent module logic.
2149
+ *
2150
+ * @param number $module_id @since 2.5.0
2151
  */
2152
+ private function get_caller_main_file_and_type( $module_id ) {
2153
  self::require_plugin_essentials();
2154
 
2155
  $all_plugins = fs_get_plugins( true );
2288
  }
2289
  }
2290
 
2291
+ $caller_main_file_and_type = (object) array(
2292
  'module_type' => $module_type,
2293
  'path' => $caller_file_candidate
2294
  );
2295
+
2296
+ return apply_filters( "fs_{$module_id}_caller_main_file_and_type", $caller_main_file_and_type );
2297
  }
2298
 
2299
  #----------------------------------------------------------------------------------
2310
  * @since 1.1.2
2311
  */
2312
  function _add_deactivation_feedback_dialog_box() {
2313
+ if (
2314
+ $this->is_clone() ||
2315
+ ( is_object( $this->_site ) && ! $this->is_registered() )
2316
+ ) {
2317
+ return;
2318
+ }
2319
+
2320
  $subscription_cancellation_dialog_box_template_params = $this->apply_filters( 'show_deactivation_subscription_cancellation', true ) ?
2321
  $this->_get_subscription_cancellation_dialog_box_template_params() :
2322
  array();
2324
  /**
2325
  * @since 2.3.0 Developers can optionally hide the deactivation feedback form using the 'show_deactivation_feedback_form' filter.
2326
  */
2327
+ $show_deactivation_feedback_form = ! self::is_deactivation_snoozed();
2328
  if ( $this->has_filter( 'show_deactivation_feedback_form' ) ) {
2329
  $show_deactivation_feedback_form = $this->apply_filters( 'show_deactivation_feedback_form', true );
2330
  } else if ( $this->is_addon() ) {
2429
  $reason_temporary_deactivation = array(
2430
  'id' => self::REASON_TEMPORARY_DEACTIVATION,
2431
  'text' => sprintf(
2432
+ $this->get_text_inline( "It's a temporary %s - I'm troubleshooting an issue", 'reason-temporary-x' ),
2433
  strtolower( $this->is_plugin() ?
2434
  $this->get_text_inline( 'Deactivation', 'deactivation' ) :
2435
  $this->get_text_inline( 'Theme Switch', 'theme-switch' )
2594
 
2595
  $this->_storage->store( 'uninstall_reason', $reason );
2596
 
2597
+ if ( self::REASON_TEMPORARY_DEACTIVATION == $reason->id ) {
2598
+ $snooze_period = fs_request_get( 'snooze_period' );
2599
+
2600
+ if ( is_numeric( $snooze_period ) && 0 < $snooze_period ) {
2601
+ self::snooze_deactivation_form( (int) $snooze_period );
2602
+ }
2603
+ }
2604
+
2605
  /**
2606
  * If the module type is "theme", trigger the uninstall event here (on theme deactivation) since themes do
2607
  * not support uninstall hook.
2623
  exit;
2624
  }
2625
 
2626
+ #--------------------------------------------------------------------------------
2627
+ #region Deactivation Feedback Snoozing
2628
+ #--------------------------------------------------------------------------------
2629
+
2630
+ /**
2631
+ * @author Vova Feldman (@svovaf)
2632
+ * @since 2.4.3
2633
+ *
2634
+ * @param int $period
2635
+ *
2636
+ * @return bool True if the value was set, false otherwise.
2637
+ */
2638
+ private static function snooze_deactivation_form( $period ) {
2639
+ return ( 0 < $period && self::reset_deactivation_snoozing( $period ) );
2640
+ }
2641
+
2642
+ /**
2643
+ * Check if deactivation feedback form is snoozed.
2644
+ *
2645
+ * @author Vova Feldman (@svovaf)
2646
+ * @since 2.4.3
2647
+ *
2648
+ * @return bool
2649
+ */
2650
+ static function is_deactivation_snoozed() {
2651
+ $is_snoozed = ( ! is_multisite() || fs_is_network_admin() ) ?
2652
+ get_transient( 'fs_snooze_period' ) :
2653
+ get_site_transient( 'fs_snooze_period' );
2654
+
2655
+
2656
+ return ( 'true' === $is_snoozed );
2657
+ }
2658
+
2659
+ /**
2660
+ * Reset deactivation snoozing. When `$period` is `0` will stop deactivation snoozing by deleting the transients. Otherwise, will set the transients for the selected period.
2661
+ *
2662
+ * @param int $period Period in seconds.
2663
+ *
2664
+ * @author Vova Feldman (@svovaf)
2665
+ * @since 2.4.3
2666
+ */
2667
+ private static function reset_deactivation_snoozing( $period = 0 ) {
2668
+ $value = ( 0 === $period ) ? null : 'true';
2669
+
2670
+ if ( ! is_multisite() || fs_is_network_admin() ) {
2671
+ return set_transient( 'fs_snooze_period', $value, $period );
2672
+ } else {
2673
+ return set_site_transient( 'fs_snooze_period', $value, $period );
2674
+ }
2675
+ }
2676
+
2677
+ /**
2678
+ * The deactivation snooze expiration UNIX timestamp (in sec).
2679
+ *
2680
+ * @author Vova Feldman (@svovaf)
2681
+ * @since 2.4.3
2682
+ *
2683
+ * @return int
2684
+ */
2685
+ static function deactivation_snooze_expires_at() {
2686
+ return ( ! is_multisite() || fs_is_network_admin() ) ?
2687
+ (int) get_option( '_transient_timeout_fs_snooze_period' ) :
2688
+ (int) get_site_option( '_site_transient_timeout_fs_snooze_period' );
2689
+ }
2690
+
2691
+ #endregion
2692
+
2693
  /**
2694
  * @author Leo Fajardo (@leorw)
2695
  * @since 2.1.4
2886
  return self::instance( $addon_id );
2887
  }
2888
 
2889
+ /**
2890
+ * @return Freemius[]
2891
+ */
2892
+ static function _get_all_instances() {
2893
+ return self::$_instances;
2894
+ }
2895
+
2896
  #endregion ------------------------------------------------------------------
2897
 
2898
  /**
3403
  add_action( 'plugins_loaded', array( 'Freemius', '_load_textdomain' ), 1 );
3404
  }
3405
 
3406
+ $clone_manager = FS_Clone_Manager::instance();
3407
+ add_action( 'init', array( $clone_manager, '_init' ) );
3408
+
3409
  add_action( 'admin_footer', array( 'Freemius', '_open_support_forum_in_new_page' ) );
3410
 
3411
  if ( self::is_plugins_page() || self::is_themes_page() ) {
3424
  self::$_statics_loaded = true;
3425
  }
3426
 
3427
+ #--------------------------------------------------------------------------------
3428
+ #region Clone
3429
+ #--------------------------------------------------------------------------------
3430
+
3431
  /**
3432
  * @author Leo Fajardo (@leorw)
3433
+ * @since 2.5.0
3434
  *
3435
+ * @param bool $only_if_manual_resolution_is_not_hidden
3436
+ *
3437
+ * @return bool
3438
  */
3439
+ private function is_unresolved_clone( $only_if_manual_resolution_is_not_hidden = false ) {
3440
+ if ( ! $this->is_clone( $only_if_manual_resolution_is_not_hidden ) ) {
3441
+ return false;
3442
+ }
 
 
 
 
 
3443
 
3444
+ return FS_Clone_Manager::instance()->has_temporary_duplicate_mode_expired();
3445
  }
3446
 
 
 
 
 
3447
  /**
3448
+ * @author Leo Fajardo (@leorw)
3449
+ * @since 2.5.0
3450
  *
3451
+ * @param bool $only_if_manual_resolution_is_not_hidden
 
3452
  */
3453
+ function is_clone( $only_if_manual_resolution_is_not_hidden = false ) {
3454
+ if ( ! is_object( $this->_site ) ) {
3455
+ return false;
3456
  }
3457
 
3458
+ $blog_id = null;
3459
 
3460
+ if (
3461
+ fs_is_network_admin() &&
3462
+ FS_Site::is_valid_id( $this->_storage->network_install_blog_id )
3463
+ ) {
3464
+ // Ensure that we're comparing the network install's URL with the relevant subsite's URL.
3465
+ $blog_id = $this->_storage->network_install_blog_id;
3466
+ }
3467
+
3468
+ $site_url = Freemius::get_unfiltered_site_url( $blog_id, true, true );
3469
+
3470
+ if ( ! $this->_site->is_clone( $site_url ) ) {
3471
+ return false;
3472
+ }
3473
+
3474
+ return (
3475
+ ! $only_if_manual_resolution_is_not_hidden ||
3476
+ ! FS_Clone_Manager::instance()->should_hide_manual_resolution()
3477
+ );
3478
+ }
3479
+
3480
+ /**
3481
+ * @author Leo Fajardo (@leorw)
3482
+ * @since 2.5.0
3483
+ *
3484
+ * @param int|null $blog_id
3485
+ * @param bool $strip_protocol
3486
+ * @param bool $add_trailing_slash
3487
+ *
3488
+ * @return string
3489
+ */
3490
+ static function get_unfiltered_site_url( $blog_id = null, $strip_protocol = false, $add_trailing_slash = false ) {
3491
+ global $wp_filter;
3492
+
3493
+ $site_url_filters = array(
3494
+ 'site_url' => null,
3495
+ 'pre_option_siteurl' => null,
3496
+ 'default_option_siteurl' => null,
3497
+ 'option_siteurl' => null,
3498
+ );
3499
+
3500
+ // Detach all URL-related filters to get the actual site's URL (stripped of potential manipulations by multilingual plugins).
3501
+ foreach ( $site_url_filters as $hook_name => $site_url_filter ) {
3502
+ if ( ! empty( $wp_filter[ $hook_name ] ) ) {
3503
+ $site_url_filters[ $hook_name ] = $wp_filter[ $hook_name ];
3504
+ unset( $wp_filter[ $hook_name ] );
3505
+ }
3506
+ }
3507
+
3508
+ $url = get_site_url( $blog_id );
3509
+
3510
+ // Re-attach the filters back.
3511
+ foreach ( $site_url_filters as $hook_name => $site_url_filter ) {
3512
+ if ( ! empty( $site_url_filter ) ) {
3513
+ $wp_filter[ $hook_name ] = $site_url_filter;
3514
+ }
3515
+ }
3516
+
3517
+ if ( $strip_protocol ) {
3518
+ $url = fs_strip_url_protocol( $url );
3519
+ }
3520
+
3521
+ if ( $add_trailing_slash ) {
3522
+ $url = trailingslashit( $url );
3523
+ }
3524
+
3525
+ return $url;
3526
+ }
3527
+
3528
+ /**
3529
+ * @author Leo Fajardo (@leorw)
3530
+ * @since 2.5.0
3531
+ *
3532
+ * @param number $site_id
3533
+ */
3534
+ function fetch_install_by_id( $site_id ) {
3535
+ return $this->get_current_or_network_user_api_scope()->get( "/installs/{$site_id}.json" );
3536
+ }
3537
+
3538
+ /**
3539
+ * @author Leo Fajardo (@leorw)
3540
+ * @since 2.5.0
3541
+ *
3542
+ * @return string|object|bool
3543
+ */
3544
+ function _handle_long_term_duplicate() {
3545
+ $this->_logger->entrance();
3546
+
3547
+ $this->delete_current_install( false );
3548
+
3549
+ $license_key = false;
3550
+
3551
+ if (
3552
+ is_object( $this->_license ) &&
3553
+ ! $this->_license->is_utilized(
3554
+ ( WP_FS__IS_LOCALHOST_FOR_SERVER || FS_Site::is_localhost_by_address( self::get_unfiltered_site_url() ) )
3555
+ )
3556
+ ) {
3557
+ $license_key = $this->_license->secret_key;
3558
+ }
3559
+
3560
+ return $this->opt_in(
3561
+ false,
3562
+ false,
3563
+ false,
3564
+ $license_key,
3565
+ false,
3566
+ false,
3567
+ false,
3568
+ null,
3569
+ array(),
3570
+ false
3571
+ );
3572
+ }
3573
+
3574
+ #endregion
3575
+
3576
+ /**
3577
+ * @author Leo Fajardo (@leorw)
3578
+ *
3579
+ * @since 2.1.3
3580
+ */
3581
+ private static function migrate_options_to_network() {
3582
+ self::migrate_accounts_to_network();
3583
+
3584
+ // Migrate API options from site level to network level.
3585
+ $api_network_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true, true );
3586
+ $api_network_options->migrate_to_network();
3587
+
3588
+ // Migrate API cache to network level storage.
3589
+ FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME )->migrate_to_network();
3590
+
3591
+ self::$_accounts->set_option( 'ms_migration_complete', true, true );
3592
+ }
3593
+
3594
+ #----------------------------------------------------------------------------------
3595
+ #region Localization
3596
+ #----------------------------------------------------------------------------------
3597
+
3598
+ /**
3599
+ * Load framework's text domain.
3600
+ *
3601
+ * @author Vova Feldman (@svovaf)
3602
+ * @since 1.2.1
3603
+ */
3604
+ static function _load_textdomain() {
3605
+ if ( ! is_admin() ) {
3606
+ return;
3607
+ }
3608
+
3609
+ global $fs_active_plugins;
3610
+
3611
+ // Works both for plugins and themes.
3612
+ load_plugin_textdomain(
3613
+ 'freemius',
3614
+ false,
3615
+ $fs_active_plugins->newest->sdk_path . '/languages/'
3616
+ );
3617
+ }
3618
 
3619
  #endregion
3620
 
3809
 
3810
  switch_to_blog( $current_blog_id );
3811
  }
3812
+ } else if ( fs_request_is_action( 'reset_deactivation_snoozing' ) ) {
3813
+ check_admin_referer( 'reset_deactivation_snoozing' );
3814
+
3815
+ self::reset_deactivation_snoozing();
3816
  } else if ( fs_request_is_action( 'simulate_trial' ) ) {
3817
  check_admin_referer( 'simulate_trial' );
3818
 
3861
  }
3862
 
3863
  /**
3864
+ * @author Leo Fajardo (@leorw)
3865
+ * @since 2.5.0
3866
+ *
3867
+ * @return array
3868
  */
3869
+ static function get_all_modules_sites() {
3870
  self::$_static_logger->entrance();
3871
 
3872
+ $sites_by_type = array(
3873
+ WP_FS__MODULE_TYPE_PLUGIN => array(),
3874
+ WP_FS__MODULE_TYPE_THEME => array(),
3875
+ );
3876
+
3877
+ $module_types = array_keys( $sites_by_type );
3878
+
3879
  if ( ! is_multisite() ) {
3880
+ foreach ( $module_types as $type ) {
3881
+ $sites_by_type[ $type ] = self::get_all_sites( $type );
3882
+
3883
+ foreach ( $sites_by_type[ $type ] as $slug => $install ) {
3884
+ $sites_by_type[ $type ][ $slug ] = array( $install );
3885
+ }
3886
+ }
3887
  } else {
3888
  $sites = self::get_sites();
3889
 
 
 
 
3890
  foreach ( $sites as $site ) {
3891
  $blog_id = self::get_site_blog_id( $site );
3892
 
3893
+ foreach ( $module_types as $type ) {
3894
+ $installs = self::get_all_sites( $type, $blog_id );
 
 
 
 
 
 
3895
 
3896
+ foreach ( $installs as $slug => $install ) {
3897
+ if ( ! isset( $sites_by_type[ $type ][ $slug ] ) ) {
3898
+ $sites_by_type[ $type ][ $slug ] = array();
3899
+ }
3900
 
3901
+ $install->blog_id = $blog_id;
3902
 
3903
+ $sites_by_type[ $type ][ $slug ][] = $install;
 
 
3904
  }
3905
 
 
 
 
3906
  }
3907
  }
3908
  }
3909
 
3910
+ return $sites_by_type;
3911
+ }
3912
+
3913
+ /**
3914
+ * @author Vova Feldman (@svovaf)
3915
+ * @since 1.0.8
3916
+ */
3917
+ static function _debug_page_render() {
3918
+ self::$_static_logger->entrance();
3919
+
3920
+ $all_modules_sites = self::get_all_modules_sites();
3921
+
3922
  $licenses_by_module_type = self::get_all_licenses_by_module_type();
3923
 
3924
  $vars = array(
3925
+ 'plugin_sites' => $all_modules_sites[ WP_FS__MODULE_TYPE_PLUGIN ],
3926
+ 'theme_sites' => $all_modules_sites[ WP_FS__MODULE_TYPE_THEME ],
3927
  'users' => self::get_all_users(),
3928
  'addons' => self::get_all_addons(),
3929
  'account_addons' => self::get_all_account_addons(),
3955
  function is_on() {
3956
  self::$_static_logger->entrance();
3957
 
3958
+ if ( is_object( $this->_site ) && ! $this->is_registered() ) {
3959
+ return false;
3960
+ }
3961
+
3962
  if ( isset( $this->_is_on ) ) {
3963
  return $this->_is_on;
3964
  }
4047
 
4048
  $is_update = $this->apply_filters( 'is_plugin_update', $this->is_plugin_update() );
4049
 
4050
+ $params = array(
4051
+ 'is_update' => json_encode( $is_update ),
4052
+ 'version' => $version,
4053
+ 'sdk' => $this->version,
4054
+ 'is_admin' => json_encode( is_admin() ),
4055
+ 'is_ajax' => json_encode( self::is_ajax() ),
4056
+ 'is_cron' => json_encode( self::is_cron() ),
4057
+ 'is_gdpr_test' => $is_gdpr_test,
4058
+ 'is_http' => json_encode( WP_FS__IS_HTTP_REQUEST ),
4059
+ );
4060
+
4061
+ if ( is_multisite() && function_exists( 'get_network' ) ) {
4062
+ $params['network_uid'] = $this->get_anonymous_network_id();
4063
+ }
4064
+
4065
  return $this->get_api_plugin_scope()->ping(
4066
  $this->get_anonymous_id( $blog_id ),
4067
+ $params
 
 
 
 
 
 
 
 
 
4068
  );
4069
  }
4070
 
4201
  $unique_id = self::$_accounts->get_option( 'unique_id', null, $blog_id );
4202
 
4203
  if ( empty( $unique_id ) || ! is_string( $unique_id ) ) {
4204
+ $key = self::get_unfiltered_site_url( $blog_id, true );
4205
 
4206
  $secure_auth = defined( 'SECURE_AUTH_KEY' ) ? SECURE_AUTH_KEY : '';
4207
  if ( empty( $secure_auth ) ||
4230
  return $unique_id;
4231
  }
4232
 
4233
+ /**
4234
+ * Returns anonymous network ID.
4235
+ *
4236
+ * @since 2.4.3
4237
+ *
4238
+ * @return string
4239
+ */
4240
+ function get_anonymous_network_id() {
4241
+ return $this->get_anonymous_id( get_network()->site_id );
4242
+ }
4243
+
4244
  /**
4245
  * @author Vova Feldman (@svovaf)
4246
  * @since 1.1.7.4
4389
  $install_previous_desc = $this->esc_html_inline( 'Uninstall this version and install the previous one.', 'install-previous-desc' );
4390
  $fix_issue_title = $this->esc_html_inline( 'Yes - I\'m giving you a chance to fix it', 'fix-issue-title' );
4391
  $fix_issue_desc = $this->esc_html_inline( '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.', 'fix-issue-desc' );
4392
+ /* translators: %s: product title (e.g. "Awesome Plugin" requires access to...) */
4393
+ $x_requires_access_to_api = $this->esc_html_inline( '%s requires access to our API.', 'x-requires-access-to-api' );
4394
  $sysadmin_title = $this->esc_html_inline( 'I\'m a system administrator', 'sysadmin-title' );
4395
  $happy_to_resolve_issue_asap = $this->esc_html_inline( '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.', 'happy-to-resolve-issue-asap' );
4396
 
4397
+ if ( $this->is_premium() ) {
4398
+ /* translators: This string is optionally prepended to 'plugin requires access to our API.' */
4399
+ $x_requires_access_to_api = $this->esc_html_inline( 'For automatic delivery of security & feature updates,', 'requires-api-for' ) . ' ' . $x_requires_access_to_api;
4400
+ }
4401
+
4402
  $message = false;
4403
  if ( is_object( $api_result ) &&
4404
  isset( $api_result->error ) &&
5030
 
5031
  /**
5032
  * This should be executed even if Freemius is off for the core module,
5033
+ * otherwise, the add-ons dialog box won't work properly. This is especially
5034
  * relevant when the developer decided to turn FS off for existing users.
5035
  *
5036
  * @author Vova Feldman (@svovaf)
5068
  * @since 1.1.7.3
5069
  *
5070
  */
5071
+ if ( $this->is_registered() && $this->is_tracking_allowed() ) {
5072
+ $this->maybe_schedule_sync_cron();
 
 
5073
  }
5074
 
5075
  /**
5076
  * Check if requested for manual blocking background sync.
5077
  */
5078
  if ( fs_request_has( 'background_sync' ) ) {
5079
+ self::require_pluggable_essentials();
5080
+ self::wp_cookie_constants();
5081
+
5082
  $this->run_manual_sync();
5083
  }
5084
  }
5085
  }
5086
 
5087
  if ( $this->is_registered() ) {
5088
+ FS_Clone_Manager::instance()->maybe_resolve_new_subsite_install_automatically( $this );
5089
+
5090
  $this->hook_callback_to_install_sync();
5091
  }
5092
 
5101
  }
5102
 
5103
  if ( $this->is_user_in_admin() ) {
5104
+ if ( $this->is_registered() && fs_request_has( 'purchase_completed' ) ) {
5105
+ $this->_admin_notices->add_sticky(
5106
+ sprintf(
5107
+ /* translators: %s: License type (e.g. you have a professional license) */
5108
+ $this->get_text_inline( 'You have purchased a %s license.', 'you-have-x-license' ),
5109
+ fs_request_get( 'purchased_plan' )
5110
+ ) .
5111
+ sprintf(
5112
+ $this->get_text_inline(" The %s's %sdownload link%s, license key, and installation instructions have been sent to %s. If you can't find the email after 5 min, please check your spam box.", 'post-purchase-email-sent-message' ),
5113
+ $this->get_module_label( true ),
5114
+ ( FS_Plugin::is_valid_id( $this->get_bundle_id() ) ? "products' " : '' ),
5115
+ ( FS_Plugin::is_valid_id( $this->get_bundle_id() ) ? 's' : '' ),
5116
+ sprintf(
5117
+ '<strong>%s</strong>',
5118
+ fs_request_get( 'purchase_email' )
5119
+ )
5120
+ ),
5121
+ 'plan_purchased',
5122
+ $this->get_text_x_inline( 'Yee-haw', 'interjection expressing joy or exuberance', 'yee-haw' ) . '!'
5123
+ );
5124
+ }
5125
+
5126
  if ( $this->is_addon() ) {
5127
  if ( ! $this->is_parent_plugin_installed() ) {
5128
  $parent_name = $this->get_option( $plugin_info, 'parent_name', null );
5227
  * because the updater has some logic that needs to be executed
5228
  * during AJAX calls.
5229
  *
5230
+ * Currently, we need to hook to the `http_request_host_is_external` filter.
5231
  * In the future, there might be additional logic added.
5232
  *
5233
  * @author Vova Feldman
5246
  */
5247
  ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this->premium_plugin_basename() ) ) )
5248
  ) &&
5249
+ $this->has_release_on_freemius() &&
5250
+ ( ! $this->is_unresolved_clone( true ) )
5251
  ) {
5252
  FS_Plugin_Updater::instance( $this );
5253
  }
5316
  }
5317
 
5318
  /**
5319
+ * @param string[] $permissions
5320
+ * @param bool $is_enabled
5321
+ * @param int|null $blog_id
5322
  *
5323
+ * @return true|object `true` on success, API error object on failure.
5324
  */
5325
+ private function update_site_permissions( array $permissions, $is_enabled, $blog_id = null ) {
5326
  $this->_logger->entrance();
5327
 
5328
+ $params = array(
5329
+ 'permissions' => implode( ',', $permissions ),
5330
+ 'is_enabled' => $is_enabled,
 
 
 
 
 
 
 
 
 
 
 
 
5331
  );
 
 
 
 
 
 
 
 
 
 
5332
 
5333
+ $current_blog_id = get_current_blog_id();
5334
+ $is_blog_switched = false;
5335
+ if ( is_numeric( $blog_id ) && $current_blog_id != $blog_id ) {
5336
+ $is_blog_switched = $this->switch_to_blog( $blog_id );
5337
  }
5338
 
5339
+ $result = $this->api_site_call( '/permissions.json', 'put', $params );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5340
 
5341
+ if ( $is_blog_switched ) {
5342
+ $this->switch_to_blog( $current_blog_id );
 
5343
  }
5344
 
5345
+ if (
5346
+ ! $this->is_api_result_object( $result ) ||
5347
+ ! isset( $result->install_id )
 
 
 
 
 
5348
  ) {
5349
  $this->_logger->api_error( $result );
5350
 
5351
  return $result;
5352
  }
5353
 
 
 
 
 
 
 
5354
  return true;
5355
  }
5356
 
5357
  /**
5358
+ * @param string[] $permissions
5359
+ * @param bool $is_enabled
5360
+ * @param bool $has_site_delegated_connection
5361
  *
5362
+ * @return true|object `true` on success, API error object on failure.
 
 
 
 
 
 
 
 
 
 
5363
  */
5364
+ private function update_network_permissions(
5365
+ array $permissions,
5366
+ $is_enabled,
5367
+ &$has_site_delegated_connection
5368
+ ) {
5369
  $this->_logger->entrance();
5370
 
 
 
 
 
 
5371
  $install_id_2_blog_id = array();
5372
+ $install_by_blog_id = $this->get_blog_install_map();
 
 
5373
 
5374
+ $has_site_delegated_connection = false;
 
 
 
 
 
5375
 
5376
+ foreach ( $install_by_blog_id as $blog_id => $install ) {
5377
  if ( $this->is_site_delegated_connection( $blog_id ) ) {
5378
+ // Only update permissions of non-delegated installs.
5379
+ $has_site_delegated_connection = true;
5380
  continue;
5381
  }
5382
 
 
 
5383
  $install_id_2_blog_id[ $install->id ] = $blog_id;
5384
  }
5385
 
5387
  return true;
5388
  }
5389
 
5390
+ $params = array(
5391
+ 'permissions' => implode( ',', $permissions ),
5392
+ 'is_enabled' => $is_enabled,
5393
+ 'install_ids' => implode( ',', array_keys( $install_id_2_blog_id ) ),
5394
+ );
5395
 
5396
  // Send update to FS.
5397
+ $result = $this->get_current_or_network_user_api_scope()->call(
5398
+ "/plugins/{$this->_module_id}/installs/permissions.json",
5399
+ 'put',
5400
+ $params
5401
+ );
5402
 
5403
+ if ( ! $this->is_api_result_object( $result, 'installs_metadata' ) ) {
5404
  $this->_logger->api_error( $result );
5405
 
5406
  return $result;
5407
  }
5408
 
 
 
 
 
 
 
 
 
 
 
5409
  return true;
5410
  }
5411
 
5412
  /**
5413
+ * @param mixed $result
 
 
 
 
 
 
 
 
 
 
 
 
5414
  *
5415
+ * @return string
5416
  */
5417
+ private function get_api_error_message( $result ) {
5418
+ $error_message = sprintf( $this->get_text_inline( 'There was an unexpected API error while processing your request. Please try again in a few minutes and if it still doesn\'t work, contact the %s\'s author with the following:',
5419
+ 'unexpected-api-error' ), $this->_module_type ) . ' ';
5420
+
5421
+ if (
5422
+ $this->is_api_error( $result ) &&
5423
+ isset( $result->error )
5424
+ ) {
5425
+ $code = empty( $result->error->code ) ? '' : " Code: {$result->error->code}";
5426
+
5427
+ $error_message .= "<b>{$result->error->message}{$code}</b>";
5428
+ } else {
5429
+ $error_message .= var_export( $result, true );
5430
+ }
5431
 
5432
+ return $error_message;
 
 
5433
  }
5434
 
5435
  /**
5436
+ * @author Vova Feldman (@svovaf)
5437
+ * @since 2.5.1
 
 
 
 
 
 
 
 
 
 
 
5438
  */
5439
+ function _toggle_permission_tracking_callback() {
5440
  $this->_logger->entrance();
5441
 
5442
+ $this->check_ajax_referer( 'toggle_permission_tracking' );
 
 
 
5443
 
5444
+ if ( ! $this->is_registered( true ) ) {
5445
+ self::shoot_ajax_failure( 'User never opted-in.' );
 
5446
  }
5447
 
5448
+ $is_enabled = fs_request_get_bool( 'is_enabled' );
5449
+ $permissions = fs_request_get( 'permissions' );
 
 
 
 
 
 
 
5450
 
5451
+ if ( ! is_string( $permissions ) ) {
5452
+ self::shoot_ajax_failure( 'The permissions param must be a string.' );
5453
  }
5454
 
5455
+ $permissions = explode( ',', $permissions );
 
5456
 
5457
+ $result = $this->toggle_permission_tracking( $permissions, $is_enabled );
5458
 
5459
+ if ( true !== $result ) {
5460
+ self::shoot_ajax_failure( $this->get_api_error_message( $result ) );
5461
+ }
5462
+
5463
+ self::shoot_ajax_success();
5464
  }
5465
 
5466
  /**
5467
+ * @param string[] $permissions
5468
+ * @param bool $is_enabled
5469
+ * @param int|null $blog_id
 
 
 
 
 
 
 
 
5470
  *
5471
+ * @return bool|mixed `true` if updated successfully or no update is needed.
5472
  */
5473
+ private function toggle_permission_tracking( $permissions, $is_enabled, $blog_id = null ) {
5474
+ if ( ! $this->is_registered( true ) ) {
 
 
5475
  // User never opted-in.
5476
  return false;
5477
  }
5478
 
5479
+ // Check if permissions are already set as needed.
5480
+ if ( FS_Permission_Manager::instance( $this )->are_permissions( $permissions, $is_enabled, $blog_id ) ) {
5481
+ /**
5482
+ * Note:
5483
+ * When running on the network admin, there's no need to iterate through all the installs individually since network opt-in permissions are managed for ALL non-delegated installs through a single option (per permission) on the network-level storage.
5484
+ */
5485
+ return true;
 
 
 
 
 
5486
  }
5487
 
5488
+ $api_managed_permissions = array_intersect(
5489
+ $permissions,
5490
+ FS_Permission_Manager::get_api_managed_permission_ids()
5491
+ );
5492
+
5493
+ if (
5494
+ in_array( FS_Permission_Manager::PERMISSION_ESSENTIALS, $permissions ) &&
5495
+ ! in_array( FS_Permission_Manager::PERMISSION_SITE, $permissions )
5496
+ ) {
5497
+ $api_managed_permissions[] = FS_Permission_Manager::PERMISSION_SITE;
5498
  }
5499
 
5500
+ if ( ! empty( $api_managed_permissions ) ) {
5501
+ $has_site_delegated_connection = false;
5502
 
5503
+ if (
5504
+ ! $is_enabled &&
5505
+ ! in_array( FS_Permission_Manager::PERMISSION_EXTENSIONS, $api_managed_permissions ) &&
5506
+ false === FS_Permission_Manager::instance( $this )->is_extensions_tracking_allowed( $blog_id )
5507
+ ) {
5508
+ /**
5509
+ * If we are turning off a permission and the extensions permission is off too, enrich the permissions update request to also turn off extensions tracking, as currently when opting in with extensions tracking disabled the extensions tracking is off but the API isn't aware of it.
5510
+ *
5511
+ * @todo Remove this entire `if` after implementing granular opt-in that also sends the permissions to the API when opting in.
5512
+ */
5513
+ $api_managed_permissions[] = FS_Permission_Manager::PERMISSION_EXTENSIONS;
5514
+ }
5515
 
5516
+ if ( is_null( $blog_id ) && fs_is_network_admin() ) {
5517
+ $result = $this->update_network_permissions(
5518
+ $api_managed_permissions,
5519
+ $is_enabled,
5520
+ $has_site_delegated_connection
5521
+ );
5522
+ } else {
5523
+ $result = $this->update_site_permissions(
5524
+ $api_managed_permissions,
5525
+ $is_enabled,
5526
+ $blog_id
5527
+ );
5528
+ }
5529
 
5530
+ if ( true !== $result ) {
5531
+ return $result;
5532
+ }
5533
 
5534
+ if ( in_array( FS_Permission_Manager::PERMISSION_SITE, $api_managed_permissions ) ) {
5535
+ if ( $is_enabled ) {
5536
+ $this->schedule_sync_cron();
5537
+ } else {
5538
+ $this->clear_sync_cron( ! $has_site_delegated_connection );
5539
+ }
5540
+ }
5541
 
5542
+ if ( in_array( FS_Permission_Manager::PERMISSION_USER, $api_managed_permissions ) ) {
5543
+ $this->toggle_user_permission( $is_enabled, $blog_id );
5544
+ }
 
 
5545
  }
5546
 
5547
+ $this->update_tracking_permissions(
5548
+ $permissions,
5549
+ $is_enabled,
5550
+ $blog_id
5551
+ );
5552
 
 
5553
  return true;
5554
  }
5555
 
5556
+ /**
5557
+ * @param bool $is_enabled
5558
+ * @param int|null $blog_id
5559
+ */
5560
+ private function toggle_user_permission( $is_enabled, $blog_id = null ) {
5561
+ $network_or_blog_ids = is_numeric( $blog_id ) ?
5562
+ $blog_id :
5563
+ fs_is_network_admin();
5564
+
5565
+ if ( $is_enabled ) {
5566
+ $this->reset_anonymous_mode( $network_or_blog_ids );
5567
+ } else {
5568
+ $this->skip_connection( $network_or_blog_ids );
5569
+ }
5570
+ }
5571
+
5572
  /**
5573
  * Opt-in back into usage tracking.
5574
  *
5582
  * @author Leo Fajardo (@leorw)
5583
  * @since 1.2.1.5
5584
  *
5585
+ * @bool $is_enabled
5586
  *
5587
  * @return bool|object
5588
  */
5589
+ private function toggle_site_tracking( $is_enabled, $blog_id = null ) {
5590
  $this->_logger->entrance();
5591
 
5592
+ return $this->toggle_permission_tracking(
5593
+ FS_Permission_Manager::instance( $this )->get_site_tracking_permission_names(),
5594
+ $is_enabled,
5595
+ $blog_id
5596
+ );
5597
  }
5598
 
5599
  /**
5614
 
5615
  if ( ! fs_is_network_admin() || $is_context_single_site ) {
5616
  if ( $this->is_tracking_prohibited() ) {
5617
+ FS_Permission_Manager::instance( $this )->update_site_tracking( true );
 
5618
  }
5619
  } else {
5620
  $installs_map = $this->get_blog_install_map();
5622
  /**
5623
  * @var FS_Site $install
5624
  */
5625
+ if ( ! $this->is_tracking_allowed( $blog_id, $install ) ) {
5626
+ FS_Permission_Manager::instance( $this )->update_site_tracking( true, $blog_id );
 
5627
  }
5628
  }
5629
  }
5630
  }
5631
 
5632
  /**
5633
+ * Update permission tracking flags. When updating in a network context, in addition to updating the network-level flags, also update the permissions on the site-level for all non-delegated sites.
 
5634
  *
5635
+ * @param string[] $permissions
5636
+ * @param bool $is_enabled
5637
+ * @param int|null $blog_id
5638
+ *
5639
+ * @return array
5640
  */
5641
+ private function update_tracking_permissions( $permissions, $is_enabled, $blog_id = null ) {
5642
+ // Alias.
5643
+ $permission_manager = FS_Permission_Manager::instance( $this );
 
 
 
5644
 
5645
+ $network_or_blog_ids = is_numeric( $blog_id ) ?
5646
+ $blog_id :
5647
+ fs_is_network_admin();
 
 
 
5648
 
5649
+ if ( true === $network_or_blog_ids ) {
5650
+ // Update the permission for all non-delegated sub-sites.
5651
+ $blog_ids = $this->get_non_delegated_blog_ids();
5652
 
5653
+ // Add the network-level to the array, to update the permission on the network-level storage.
5654
+ array_unshift( $blog_ids, null );
5655
+ }
5656
+ else
5657
+ {
5658
+ if ( false === $network_or_blog_ids ) {
5659
+ $network_or_blog_ids = null;
5660
+ }
5661
 
5662
+ $blog_ids = is_array( $network_or_blog_ids ) ?
5663
+ $network_or_blog_ids :
5664
+ array( $network_or_blog_ids );
5665
  }
5666
 
5667
+ $result = array();
5668
+ foreach ( $permissions as $permission ) {
5669
+ $permission = trim( $permission );
5670
+ $is_permission_supported = true;
5671
+
5672
+ foreach ( $blog_ids as $id ) {
5673
+ $is_permission_supported = $permission_manager->update_permission_tracking_flag(
5674
+ $permission,
5675
+ $is_enabled,
5676
+ $id
5677
+ );
5678
+ }
5679
 
5680
+ if ( ! $is_permission_supported ) {
 
 
 
 
5681
  $permission = 'no_match';
5682
+ }
5683
 
5684
+ $result[ $permission ] = $is_enabled;
 
5685
  }
5686
 
5687
+ return $result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5688
  }
5689
 
5690
  /**
5890
  if ( $this->is_activation_mode() ) {
5891
  if ( ! is_admin() ) {
5892
  /**
5893
+ * If in activation mode, don't execute Freemius outside the admin dashboard.
 
5894
  *
5895
  * @author Vova Feldman (@svovaf)
5896
  * @since 1.1.7.3
6437
  if ( ! isset( $this->_is_anonymous ) ) {
6438
  if ( $this->is_network_anonymous() ) {
6439
  $this->_is_anonymous = true;
6440
+ } else if ( fs_is_network_admin() ) {
6441
+ /**
6442
+ * When not-network-anonymous, yet, running in the network admin, consider as anonymous only when ALL non-delegated sites are set to anonymous.
6443
+ */
6444
+ $non_delegated_sites = $this->get_non_delegated_blog_ids();
6445
+
6446
+ foreach ( $non_delegated_sites as $blog_id ) {
6447
+ $is_anonymous = $this->_storage->get( 'is_anonymous', false, $blog_id );
6448
+
6449
+ if ( empty( $is_anonymous ) || false === $is_anonymous[ 'is' ] ) {
6450
+ $this->_is_anonymous = false;
6451
+ break;
6452
+ }
6453
+ }
6454
+
6455
+ if ( false !== $this->_is_anonymous ) {
6456
+ $this->_is_anonymous = true;
6457
+ }
6458
+ } else {
6459
  if ( ! isset( $this->_storage->is_anonymous ) ) {
6460
  // Not skipped.
6461
  $this->_is_anonymous = false;
6511
  return $this->_storage->get( 'is_pending_activation', false );
6512
  }
6513
 
6514
+ /**
6515
+ * @author Leo Fajardo (@leorw)
6516
+ * @since 2.5.0
6517
+ */
6518
+ private function clear_pending_activation_mode() {
6519
+ // Remove the pending activation sticky notice (if it still exists).
6520
+ $this->_admin_notices->remove_sticky( 'activation_pending' );
6521
+
6522
+ // Clear the plugin's pending activation mode.
6523
+ unset( $this->_storage->is_pending_activation );
6524
+ }
6525
+
6526
  /**
6527
  * Check if plugin must be WordPress.org compliant.
6528
  *
6599
  private function get_cron_blog_id( $name ) {
6600
  $this->_logger->entrance( $name );
6601
 
6602
+ if ( ! is_multisite() ) {
6603
+ // Not a multisite.
6604
+ return 0;
6605
+ }
6606
+
6607
  $cron_data = $this->get_cron_data( $name );
6608
 
6609
  return ( is_object( $cron_data ) && is_numeric( $cron_data->blog_id ) ) ?
6714
  return 0;
6715
  }
6716
 
6717
+ if ( $this->_is_network_active ) {
6718
+ $network_install_blog_id = $this->_storage->network_install_blog_id;
 
 
 
 
 
6719
 
6720
+ if (
6721
+ is_numeric( $network_install_blog_id ) &&
6722
+ $except_blog_id != $network_install_blog_id &&
6723
+ self::is_site_active( $network_install_blog_id )
6724
  ) {
6725
+ // Try to run cron from the main network blog.
6726
+ $install = $this->get_install_by_blog_id( $network_install_blog_id );
6727
+
6728
+ if (
6729
+ is_object( $install ) &&
6730
+ $this->is_tracking_allowed( $network_install_blog_id, $install )
6731
+ ) {
6732
+ return $network_install_blog_id;
6733
+ }
6734
  }
6735
  }
6736
 
6739
  foreach ( $installs as $blog_id => $install ) {
6740
  if ( $except_blog_id != $blog_id &&
6741
  self::is_site_active( $blog_id ) &&
6742
+ $this->is_tracking_allowed( $blog_id, $install )
6743
  ) {
6744
  return $blog_id;
6745
  }
6771
  /**
6772
  * @var FS_Site $install
6773
  */
6774
+ if ( $this->is_tracking_allowed( $blog_id, $install ) ) {
6775
  $clear_cron = false;
6776
  break;
6777
  }
6782
  return;
6783
  }
6784
 
6785
+ $cron_blog_id = $this->get_cron_blog_id( $name );
 
 
 
 
 
 
 
6786
 
6787
  $this->clear_cron_data( $name );
6788
 
6819
  return false;
6820
  }
6821
 
6822
+ $cron_blog_id = $this->get_cron_blog_id( $name );
 
 
 
 
 
 
 
6823
 
6824
  if ( 0 < $cron_blog_id ) {
6825
  switch_to_blog( $cron_blog_id );
6930
  } else {
6931
  $installs = $this->get_blog_install_map();
6932
  foreach ( $installs as $blog_id => $install ) {
6933
+ if ( $this->is_tracking_allowed( $blog_id, $install ) ) {
6934
  if ( ! isset( $users_2_blog_ids[ $install->user_id ] ) ) {
6935
  $users_2_blog_ids[ $install->user_id ] = array();
6936
  }
6995
  * @since 1.1.7.3
6996
  */
6997
  private function run_manual_sync() {
 
 
6998
  if ( ! $this->is_user_admin() ) {
6999
  return;
7000
  }
7078
  return $this->is_cron_on( 'sync' );
7079
  }
7080
 
7081
+ /**
7082
+ * @author Leo Fajardo (@leorw)
7083
+ * @since 2.5.0
7084
+ */
7085
+ private function maybe_schedule_sync_cron() {
7086
+ $next_schedule = $this->next_sync_cron();
7087
+
7088
+ // The event is properly scheduled, so no need to reschedule it.
7089
+ if (
7090
+ is_numeric( $next_schedule ) &&
7091
+ $next_schedule > time()
7092
+ ) {
7093
+ return;
7094
+ }
7095
+
7096
+ $this->schedule_sync_cron();
7097
+ }
7098
+
7099
  /**
7100
  * @author Vova Feldman (@svovaf)
7101
  * @since 1.1.7.3
7202
  * @param int $except_blog_id Since 2.0.0 when running in a multisite network environment, the cron execution is consolidated. This param allows excluding excluded specified blog ID from being the cron executor.
7203
  */
7204
  private function schedule_install_sync( $except_blog_id = 0 ) {
7205
+ if ( $this->is_clone() ) {
7206
+ return;
7207
+ }
7208
+
7209
  $this->schedule_cron( 'install_sync', 'install_sync', 'single', WP_FS__SCRIPT_START_TIME, false, $except_blog_id );
7210
  }
7211
 
7294
  /**
7295
  * Show a notice that activation is currently pending.
7296
  *
7297
+ * @todo Add some sort of mechanism to allow users to update the email address they would like to opt-in with when $is_suspicious_email is true.
7298
+ *
7299
  * @author Vova Feldman (@svovaf)
7300
  * @since 1.0.7
7301
  *
7302
  * @param bool|string $email
7303
  * @param bool $is_pending_trial Since 1.2.1.5
7304
+ * @param bool $is_suspicious_email Since 2.5.0 Set to true when there's an indication that email address the user opted in with is fake/dummy/placeholder.
7305
  */
7306
+ function _add_pending_activation_notice(
7307
+ $email = false,
7308
+ $is_pending_trial = false,
7309
+ $is_suspicious_email = false
7310
+ ) {
7311
  if ( ! is_string( $email ) ) {
7312
  $current_user = self::_get_current_wp_user();
7313
  $email = $current_user->user_email;
7363
  /**
7364
  * Don't redirect if activating multiple plugins at once (bulk activation).
7365
  */
7366
+ } else if (
7367
+ self::is_deactivation_snoozed() &&
7368
+ (
7369
+ // Either running the free code base.
7370
+ ! $this->is_premium() ||
7371
+ // Or if has a free version.
7372
+ ! $this->is_only_premium() ||
7373
+ // If premium only, don't redirect if license is activated.
7374
+ ( $this->is_registered() && ! $this->can_use_premium_code() )
7375
+ )
7376
+ ) {
7377
+ /**
7378
+ * Don't redirect if activating during the deactivation snooze period (aka troubleshooting), unless activating a paid product version that the admin didn't enter its license key yet.
7379
+ */
7380
  } else if ( ! $is_migration ) {
7381
  $this->_redirect_on_activation_hook();
7382
  return;
7390
  if ( fs_request_is_action( $this->get_unique_affix() . '_skip_activation' ) ) {
7391
  check_admin_referer( $this->get_unique_affix() . '_skip_activation' );
7392
 
7393
+ $this->skip_connection( fs_is_network_admin() );
7394
 
7395
  fs_redirect( $this->get_after_activation_url( 'after_skip_url' ) );
7396
  }
7563
 
7564
  fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
7565
  fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
 
 
7566
  }
7567
 
7568
  /**
7598
  <?php
7599
  echo $this->apply_filters( 'optin_pointer_execute', "
7600
 
7601
+ optin.pointer('open');
7602
 
7603
+ // Tag the opt-in pointer with custom class.
7604
+ $('.wp-pointer #fs_connect')
7605
+ .parents('.wp-pointer.wp-pointer-top')
7606
+ .addClass('fs-opt-in-pointer');
7607
 
7608
+ ", 'element', 'optin' ) ?>
7609
  }
7610
  }
7611
  });
7621
  *
7622
  * @return string
7623
  */
7624
+ static function current_page_url() {
7625
  $url = 'http';
7626
 
7627
  if ( isset( $_SERVER["HTTPS"] ) ) {
7653
  }
7654
 
7655
  /* Events
7656
+ ------------------------------------------------------------------------------------------------------------------*/
7657
  /**
7658
  * Delete site install from Database.
7659
  *
7817
 
7818
  /**
7819
  * @author Leo Fajardo (@leorw)
7820
+ * @since 1.2.2
7821
+ *
7822
+ * @return bool
7823
+ */
7824
+ private function can_activate_previous_theme() {
7825
+ return $this->can_activate_theme( $this->get_previous_theme_slug() );
7826
+ }
7827
+
7828
+ /**
7829
+ * @author Leo Fajardo (@leorw)
7830
+ * @since 2.5.0
7831
  *
7832
+ * @return bool
7833
  */
7834
+ private function can_activate_theme( $slug ) {
 
7835
  if ( false !== $slug && current_user_can( 'switch_themes' ) ) {
7836
  $theme_instance = wp_get_theme( $slug );
7837
 
7928
  ( current_filter() !== ( 'activate_' . $this->_free_plugin_basename ) ) :
7929
  $this->is_premium();
7930
 
7931
+ if ( $is_premium_version_activation && $this->is_pending_activation() ) {
7932
+ $this->clear_pending_activation_mode();
7933
+ }
7934
+
7935
  $this->_logger->info( 'Activating ' . ( $is_premium_version_activation ? 'premium' : 'free' ) . ' plugin version.' );
7936
 
7937
  if ( $this->is_plugin() ) {
7998
  $plugin_version = $this->_storage->is_anonymous_ms['version'];
7999
  $network = true;
8000
  } else {
8001
+ $plugin_version = isset( $this->_storage->is_anonymous ) ?
8002
+ $this->_storage->is_anonymous['version'] :
8003
+ null;
8004
  $network = false;
8005
  }
8006
 
8148
  );
8149
  } else {
8150
  // Activate the license.
8151
+ $install = $this->api_site_call(
8152
  '/',
8153
  'put',
8154
  array( 'license_key' => $this->apply_filters( 'license_key', $license->secret_key ) )
8807
  $this->_is_anonymous = $is_anonymous;
8808
  }
8809
 
8810
+ /**
8811
+ * @author Vova Feldman (@svovaf)
8812
+ * @since 2.5.1
8813
+ *
8814
+ * @param bool|int $network_or_blog_id
8815
+ */
8816
+ private function unset_anonymous_mode( $network_or_blog_id = 0 ) {
8817
+ if ( true === $network_or_blog_id ) {
8818
+ unset( $this->_storage->is_anonymous_ms );
8819
+ } else {
8820
+ $this->_storage->remove( 'is_anonymous', true, $network_or_blog_id );
8821
+ }
8822
+ }
8823
+
8824
  /**
8825
  * @author Vova Feldman (@svovaf)
8826
  * @since 2.0.0
8837
  * @uses Freemius::is_network_anonymous() to check if the super-admin network skipped.
8838
  * @uses Freemius::is_network_delegated_connection() to check if the super-admin network delegated the connection to the site admins.
8839
  */
8840
+ public function _after_new_blog_callback( $blog_id, $user_id, $domain, $path, $network_id, $meta ) {
8841
  $this->_logger->entrance();
8842
 
8843
+ if ( ! $this->_is_network_active ) {
8844
+ FS_Clone_Manager::instance()->store_blog_install_info( $blog_id );
8845
+ return;
8846
+ }
8847
+
8848
+ $site = null;
8849
+ $new_blog_id = $blog_id;
8850
+
8851
  if ( $this->is_premium() &&
8852
  $this->is_network_connected() &&
8853
  is_object( $this->_license ) &&
8881
  }
8882
  }
8883
 
8884
+ $site = $this->_site;
8885
+
8886
  $this->switch_to_blog( $current_blog_id );
8887
 
8888
+ if ( is_object( $site ) ) {
8889
+ FS_Clone_Manager::instance()->store_blog_install_info( $blog_id, $site );
8890
+
8891
  // Already connected (with or without a license), so no need to continue.
8892
  return;
8893
  }
8920
  false
8921
  );
8922
 
8923
+ $site = $this->_site;
8924
+
8925
  $this->switch_to_blog( $current_blog_id );
8926
  } else {
8927
  /**
8932
  $has_delegated_site = false;
8933
 
8934
  $sites = self::get_sites();
8935
+ foreach ( $sites as $wp_site ) {
8936
+ $blog_id = self::get_site_blog_id( $wp_site );
8937
 
8938
  if ( $this->is_site_delegated_connection( $blog_id ) ) {
8939
  $has_delegated_site = true;
8947
  $this->skip_site_connection( $blog_id );
8948
  }
8949
  }
8950
+
8951
+ /**
8952
+ * Store the new blog's information even if there's no install so that when a clone install is stored in the new blog's storage, we can try to resolve it automatically.
8953
+ *
8954
+ * @author Leo Fajardo (@leorw)
8955
+ * @since 2.5.0
8956
+ */
8957
+ FS_Clone_Manager::instance()->store_blog_install_info( $new_blog_id, $site );
8958
+ }
8959
+
8960
+ /**
8961
+ * @author Vova Feldman (@svovaf)
8962
+ * @since 2.5.0
8963
+ *
8964
+ * @param \WP_Site $new_site
8965
+ * @param array $args
8966
+ */
8967
+ public function _after_wp_initialize_site_callback( WP_Site $new_site, $args ) {
8968
+ $this->_logger->entrance();
8969
+
8970
+ $this->_after_new_blog_callback(
8971
+ $new_site->id,
8972
+ // Dummy user ID (not in use).
8973
+ 0,
8974
+ $new_site->domain,
8975
+ $new_site->path,
8976
+ $new_site->network_id,
8977
+ // Dummy meta, not in use.
8978
+ array()
8979
+ );
8980
  }
8981
 
8982
  /**
8983
  * @author Vova Feldman (@svovaf)
8984
  * @since 1.1.3
8985
  *
8986
+ * @param bool|int|int[] $network_or_blog_ids Since 2.0.0.
8987
  */
8988
+ private function reset_anonymous_mode( $network_or_blog_ids = false ) {
8989
+ if ( true === $network_or_blog_ids ) {
8990
+ $this->unset_anonymous_mode( true );
8991
+
8992
+ if ( fs_is_network_admin() ) {
8993
+ $this->_is_anonymous = null;
8994
+ }
8995
+
8996
+ // Rest anonymous mode for all non-delegated sub-sites.
8997
+ $blog_ids = $this->get_non_delegated_blog_ids();
8998
+ }
8999
+ else
9000
+ {
9001
+ if ( false === $network_or_blog_ids ) {
9002
+ $network_or_blog_ids = 0;
9003
+ }
9004
+
9005
+ $blog_ids = is_array( $network_or_blog_ids ) ?
9006
+ $network_or_blog_ids :
9007
+ array( $network_or_blog_ids );
9008
+
9009
+ foreach ( $blog_ids as $blog_id ) {
9010
+ if ( 0 === $blog_id || get_current_blog_id() == $blog_id ) {
9011
+ $this->_is_anonymous = null;
9012
+ }
9013
+ }
9014
+ }
9015
+
9016
+ foreach ( $blog_ids as $blog_id ) {
9017
+ $this->unset_anonymous_mode( $blog_id );
9018
  }
9019
 
9020
  /**
9025
  * @author Leo Fajardo (@leorw)
9026
  * @since 1.2.2
9027
  */
9028
+ if ( ! $this->_is_network_active ) {
 
 
 
 
9029
  $this->_is_anonymous = null;
9030
  }
9031
  }
9071
  * @author Vova Feldman (@svovaf)
9072
  * @since 1.1.1
9073
  *
9074
+ * @param bool|int|int[] $network_or_blog_ids Since 2.5.1
 
9075
  */
9076
+ function skip_connection( $network_or_blog_ids = false ) {
9077
  $this->_logger->entrance();
9078
 
9079
  $this->_admin_notices->remove_sticky( 'connect_account' );
9080
 
9081
+ if ( true === $network_or_blog_ids ) {
9082
  $this->set_anonymous_mode( true, true );
 
9083
 
9084
+ if ( fs_is_network_admin() ) {
9085
+ $this->_is_anonymous = null;
9086
+ }
9087
+
9088
+ // Rest anonymous mode for all non-delegated sub-sites.
9089
+ $blog_ids = $this->get_non_delegated_blog_ids();
9090
+ }
9091
+ else
9092
+ {
9093
+ if ( false === $network_or_blog_ids ) {
9094
+ $network_or_blog_ids = 0;
9095
+ }
9096
 
9097
+ $blog_ids = is_array( $network_or_blog_ids ) ?
9098
+ $network_or_blog_ids :
9099
+ array( $network_or_blog_ids );
9100
 
9101
+ foreach ( $blog_ids as $blog_id ) {
9102
+ if ( 0 === $blog_id || get_current_blog_id() == $blog_id ) {
9103
+ $this->_is_anonymous = null;
 
 
 
 
 
 
 
9104
  }
9105
  }
9106
+ }
9107
 
9108
+ foreach ( $blog_ids as $blog_id ) {
9109
+ $this->skip_site_connection( $blog_id );
 
 
 
9110
  }
9111
 
9112
  $this->network_upgrade_mode_completed();
9121
  * @param int|null $blog_id
9122
  * @param bool $send_skip
9123
  */
9124
+ private function skip_site_connection( $blog_id = null ) {
9125
  $this->_logger->entrance();
9126
 
9127
  $this->_admin_notices->remove_sticky( 'connect_account', $blog_id );
9128
 
9129
  $this->set_anonymous_mode( true, $blog_id );
 
 
 
 
 
 
9130
  }
9131
 
9132
  /**
9498
  * @param string[] $override
9499
  * @param bool $include_plugins Since 1.1.8 by default include plugin changes.
9500
  * @param bool $include_themes Since 1.1.8 by default include plugin changes.
9501
+ * @param bool $include_blog_data Since 2.3.0 by default include the current blog's data (language, title, and URL).
9502
  *
9503
  * @return array
9504
  */
9508
  $include_themes = true,
9509
  $include_blog_data = true
9510
  ) {
9511
+ // Alias.
9512
+ $permissions = FS_Permission_Manager::instance( $this );
9513
+
9514
+ if ( $permissions->is_extensions_tracking_allowed() ) {
9515
  if ( ! defined( 'WP_FS__TRACK_PLUGINS' ) || false !== WP_FS__TRACK_PLUGINS ) {
9516
  /**
9517
  * @since 1.1.8 Also send plugin updates.
9539
 
9540
  $versions = $this->get_versions();
9541
 
9542
+ $blog_data = array();
9543
+ if ( $include_blog_data ) {
9544
+ $blog_data['url'] = self::get_unfiltered_site_url();
9545
+
9546
+ if ( $permissions->is_diagnostic_tracking_allowed() ) {
9547
+ $blog_data = array_merge( $blog_data, array(
9548
+ 'language' => self::get_sanitized_language(),
9549
+ 'title' => get_bloginfo( 'name' ),
9550
+ ) );
9551
+ }
9552
+ }
9553
 
9554
  return array_merge( $versions, $blog_data, array(
9555
  'version' => $this->get_plugin_version(),
9556
  'is_premium' => $this->is_premium(),
9557
  // Special params.
9558
  'is_active' => true,
 
9559
  'is_uninstalled' => false,
9560
  ), $override );
9561
  }
9570
  *
9571
  * @param string[] string $override
9572
  * @param bool $only_diff
9573
+ * @param bool $is_keepalive
9574
  * @param bool $include_plugins Since 1.1.8 by default include plugin changes.
9575
  * @param bool $include_themes Since 1.1.8 by default include plugin changes.
9576
  *
9579
  private function get_installs_data_for_api(
9580
  array $override,
9581
  $only_diff = false,
9582
+ $is_keepalive = false,
9583
  $include_plugins = true,
9584
  $include_themes = true
9585
  ) {
9617
 
9618
  $sites = self::get_sites();
9619
 
9620
+ $subsite_data_for_api_by_install_id = array();
9621
+ $install_url_by_install_id = array();
9622
+ $subsite_registration_date_by_install_id = array();
9623
+
9624
  foreach ( $sites as $site ) {
9625
  $blog_id = self::get_site_blog_id( $site );
9626
 
9632
  continue;
9633
  }
9634
 
9635
+ if ( ! $this->is_tracking_allowed( $blog_id, $install ) ) {
9636
  // Don't send updates regarding opted-out installs.
9637
  continue;
9638
  }
9639
 
9640
+ $install_data = $this->get_site_info( $site, true );
9641
+
9642
+ if ( FS_Clone_Manager::instance()->is_temporary_duplicate_by_blog_id( $install_data['blog_id'] ) ) {
9643
+ continue;
9644
+ }
9645
+
9646
+ $uid = $install_data['uid'];
9647
+ $url = $install_data['url'];
9648
+ $registration_date = $install_data['registration_date'];
9649
+
9650
+ if ( isset( $subsite_data_for_api_by_install_id[ $install->id ] ) ) {
9651
+ $clone_subsite_data = $subsite_data_for_api_by_install_id[ $install->id ];
9652
+ $clone_install_url = $install_url_by_install_id[ $install->id ];
9653
+ $clone_subsite_registration_date = $subsite_registration_date_by_install_id[ $install->id ];
9654
+
9655
+ $skip = false;
9656
+
9657
+ if (
9658
+ ! empty( $install_data['registration_date'] ) &&
9659
+ ! empty( $clone_subsite_registration_date )
9660
+ ) {
9661
+ /**
9662
+ * If the current subsite was created after the other subsite that is also linked to the same install ID, we assume that it's a clone (not the original), and therefore, would skip its processing.
9663
+ *
9664
+ * @author Leo Fajardo (@leorw)
9665
+ * @since 2.5.1
9666
+ */
9667
+ $skip = ( strtotime( $install_data['registration_date'] ) > strtotime( $clone_subsite_registration_date ) );
9668
+ } else if (
9669
+ /**
9670
+ * If we already have an install with the same URL as the subsite it's stored in, skip the current subsite. Otherwise, replace the existing install's data with the current subsite's install's data if the URLs match.
9671
+ *
9672
+ * @author Leo Fajardo (@leorw)
9673
+ * @since 2.5.0
9674
+ */
9675
+ fs_strip_url_protocol( untrailingslashit( $clone_install_url ) ) === fs_strip_url_protocol( untrailingslashit( $clone_subsite_data['url'] ) ) ||
9676
+ fs_strip_url_protocol( untrailingslashit( $install->url ) ) !== fs_strip_url_protocol( untrailingslashit( $url ) )
9677
+ ) {
9678
+ $skip = true;
9679
+ }
9680
 
9681
+ if ( $skip ) {
9682
+ // Store the skipped subsite's ID so that the clone resolution manager can try to resolve the clone install that is stored in that subsite later on.
9683
+ FS_Clone_Manager::instance()->store_blog_install_info( $blog_id );
9684
+ continue;
9685
+ }
9686
+ }
9687
 
9688
  unset( $install_data['blog_id'] );
9689
  unset( $install_data['uid'] );
9690
+ unset( $install_data['url'] );
9691
+ unset( $install_data['registration_date'] );
9692
 
 
9693
  $install_data['is_active'] = $this->is_active_for_site( $blog_id );
9694
  $install_data['is_uninstalled'] = $install->is_uninstalled;
9695
 
9712
  $is_common_diff_for_any_site = $is_common_diff_for_any_site || $is_common_diff;
9713
  }
9714
 
9715
+ if ( ! empty( $install_data ) || $is_common_diff || $is_keepalive ) {
9716
  // Add install ID and site unique ID.
9717
  $install_data['id'] = $install->id;
9718
  $install_data['uid'] = $uid;
9719
+ $install_data['url'] = $url;
9720
 
9721
+ $subsite_data_for_api_by_install_id[ $install->id ] = $install_data;
9722
+ $install_url_by_install_id[ $install->id ] = $install->url;
9723
+ $subsite_registration_date_by_install_id[ $install->id ] = $registration_date;
9724
  }
9725
  }
9726
  }
9727
 
9728
  restore_current_blog();
9729
 
9730
+ $installs_data = array_merge(
9731
+ $installs_data,
9732
+ array_values( $subsite_data_for_api_by_install_id )
9733
+ );
9734
+
9735
  if ( 0 < count( $installs_data ) && ( $is_common_diff_for_any_site || ! $only_diff ) ) {
9736
  if ( ! $only_diff ) {
9737
  $installs_data[] = $common;
9769
  if ( ( is_bool( $install->{$p} ) || ! empty( $install->{$p} ) ) &&
9770
  $install->{$p} != $v
9771
  ) {
9772
+ $val = self::get_api_sanitized_property( $p, $v );
9773
+
9774
+ if ( $install->{$p} != $val ) {
9775
+ $install->{$p} = $val;
9776
+ $diff[ $p ] = $val;
9777
+ }
9778
  }
9779
  } else {
9780
  $special[ $p ] = $v;
9799
  return $diff;
9800
  }
9801
 
9802
+ /**
9803
+ * @author Leo Fajardo (@leorw)
9804
+ * @since 2.5.1
9805
+ */
9806
+ private function send_pending_clone_update_once() {
9807
+ $this->_logger->entrance();
9808
+
9809
+ if ( ! empty( $this->_storage->clone_id ) ) {
9810
+ return;
9811
+ }
9812
+
9813
+ $install_clone = $this->get_api_site_scope()->call(
9814
+ '/clones',
9815
+ 'post',
9816
+ array( 'site_url' => self::get_unfiltered_site_url() )
9817
+ );
9818
+
9819
+ if ( $this->is_api_result_entity( $install_clone ) ) {
9820
+ $this->_storage->clone_id = $install_clone->id;
9821
+ }
9822
+ }
9823
+
9824
+ /**
9825
+ * @author Leo Fajardo (@leorw)
9826
+ * @since 2.5.1
9827
+ *
9828
+ * @param string $resolution_type
9829
+ * @param FS_Site $clone_context_install
9830
+ */
9831
+ function send_clone_resolution_update( $resolution_type, $clone_context_install ) {
9832
+ $this->_logger->entrance();
9833
+
9834
+ if ( empty( $this->_storage->clone_id ) ) {
9835
+ return;
9836
+ }
9837
+
9838
+ $new_install_id = null;
9839
+ $current_site = null;
9840
+
9841
+ $flush = false;
9842
+
9843
+ /**
9844
+ * If the current site is now different from the context install before the clone resolution, we need to override `$this->_site` so that the API call below will be made with the right install scope entity.
9845
+ */
9846
+ if ( $clone_context_install->id != $this->_site->id ) {
9847
+ $new_install_id = $this->_site->id;
9848
+ $current_site = $this->_site;
9849
+ $this->_site = $clone_context_install;
9850
+
9851
+ $flush = true;
9852
+ }
9853
+
9854
+ $this->get_api_site_scope( $flush )->call(
9855
+ "/clones/{$this->_storage->clone_id}",
9856
+ 'put',
9857
+ array(
9858
+ 'resolution' => $resolution_type,
9859
+ 'new_install_id' => $new_install_id,
9860
+ )
9861
+ );
9862
+
9863
+ if ( is_object( $current_site ) ) {
9864
+ /**
9865
+ * Ensure that the install scope entity is updated back to the previous install entity.
9866
+ */
9867
+ $this->_site = $current_site;
9868
+
9869
+ // Restore the previous install scope entity of the API.
9870
+ $this->get_api_site_scope( true );
9871
+ }
9872
+ }
9873
+
9874
  /**
9875
  * Update install only if changed.
9876
  *
9879
  *
9880
  * @param string[] string $override
9881
  * @param bool $flush
9882
+ * @param bool $is_two_way_sync @since 2.5.0 If true and there's a successful API request, the install sync cron will be cleared.
9883
  *
9884
  * @return false|object|string
9885
  */
9886
+ private function send_install_update( $override = array(), $flush = false, $is_two_way_sync = false ) {
9887
  $this->_logger->entrance();
9888
 
9889
  $check_properties = $this->get_install_data_for_api( $override );
9894
  $params = $this->get_install_diff_for_api( $check_properties, $this->_site, $override );
9895
  }
9896
 
 
9897
  if ( empty( $params ) ) {
9898
  $keepalive_only_update = $this->should_send_keepalive_update();
9899
 
9908
  }
9909
  }
9910
 
9911
+ if ( $is_two_way_sync ) {
9912
  /**
9913
+ * Update last install sync timestamp during a two-way sync call as we expect that updates are sent during this call.
 
9914
  *
9915
  * @author Leo Fajardo (@leorw)
9916
  * @since 2.2.3
9926
  $this->set_keepalive_timestamp();
9927
 
9928
  // Send updated values to FS.
9929
+ $site = $this->api_site_call( '/', 'put', $params, true );
9930
 
9931
+ if ( $is_two_way_sync && $this->is_api_result_entity( $site ) ) {
9932
  /**
9933
+ * Clear scheduled install sync after a two-way sync call.
9934
  *
9935
  * @author Leo Fajardo (@leorw)
9936
  * @since 2.2.3
9952
  *
9953
  * @param string[] string $override
9954
  * @param bool $flush
9955
+ * @param bool $is_two_way_sync @since 2.5.0 If true and there's a successful API request, the install sync cron will be cleared.
9956
  *
9957
  * @return false|object|string
9958
  */
9959
+ private function send_installs_update( $override = array(), $flush = false, $is_two_way_sync = false ) {
9960
  $this->_logger->entrance();
9961
 
9962
+ /**
9963
+ * Pass `true` to use the network level storage since the update is for many installs.
9964
+ *
9965
+ * @author Leo Fajardo (@leorw)
9966
+ * @since 2.2.3
9967
+ */
9968
+ $should_send_keepalive = $this->should_send_keepalive_update( true );
9969
 
9970
+ $installs_data = $this->get_installs_data_for_api( $override, ! $flush, $should_send_keepalive );
 
 
 
 
 
 
 
 
9971
 
9972
+ if ( empty( $installs_data ) ) {
9973
+ return false;
 
 
 
 
 
 
 
9974
  }
9975
 
9976
+ if ( $is_two_way_sync ) {
9977
+ // Update last install sync timestamp during a two-way sync call as we expect that updates are sent during this call.
9978
  $this->set_cron_execution_timestamp( 'install_sync' );
9979
  }
9980
 
9989
  // Send updated values to FS.
9990
  $result = $this->get_api_user_scope()->call( "/plugins/{$this->_plugin->id}/installs.json", 'put', $installs_data );
9991
 
9992
+ if ( $is_two_way_sync && $this->is_api_result_object( $result, 'installs' ) ) {
9993
+ // I successfully sent a two-way installs update, clear the scheduled install sync if it exists.
9994
  $this->clear_install_sync_cron();
9995
  }
9996
 
10040
  * @param string[] string $override
10041
  * @param bool $flush
10042
  */
10043
+ function sync_install( $override = array(), $flush = false ) {
10044
  $this->_logger->entrance();
10045
 
10046
+ $site = $this->send_install_update( $override, $flush, true );
10047
 
10048
  if ( false === $site ) {
10049
  // No sync required.
10072
  private function sync_installs( $override = array(), $flush = false ) {
10073
  $this->_logger->entrance();
10074
 
10075
+ $result = $this->send_installs_update( $override, $flush, true );
10076
 
10077
  if ( false === $result ) {
10078
  // No sync required.
10227
  // Send uninstall event.
10228
  $this->send_installs_update( $params );
10229
  } else {
10230
+ // Send uninstall event and handle the result.
10231
+ $this->sync_install( $params );
10232
  }
10233
  }
10234
 
10325
  return;
10326
  }
10327
 
10328
+ if (
10329
+ ! $fs->is_clone() &&
10330
+ /**
10331
+ * If there's a context install, run this method only when there's also a context user (e.g., when cloning a subsite of a multisite network into a single-site installation, it's possible for an install to be associated with a non-existing user entity; we want Freemius to be off in this case, while we are trying to recover the user).
10332
+ *
10333
+ * @author Leo Fajardo
10334
+ */
10335
+ ( ! is_object( $fs->_site ) || $fs->is_registered() )
10336
+ ) {
10337
+ $fs->_uninstall_plugin_event();
10338
+ }
10339
 
10340
  $fs->do_action( 'after_uninstall' );
10341
  }
10446
  * @return string
10447
  */
10448
  function get_premium_slug() {
10449
+ return ( is_object( $this->_plugin ) && ! empty( $this->_plugin->premium_slug ) ) ?
10450
  $this->_plugin->premium_slug :
10451
  "{$this->_slug}-premium";
10452
  }
10499
  null;
10500
  }
10501
 
10502
+ /**
10503
+ * Get whether the SDK has been initiated in the context of a Bundle.
10504
+ *
10505
+ * This will return true, if `bundle_id` is present in the SDK init parameters.
10506
+ *
10507
+ * ```php
10508
+ * $my_fs = fs_dynamic_init( array(
10509
+ * // ...
10510
+ * 'bundle_id' => 'XXXX', // Will return true since we have bundle id.
10511
+ * 'bundle_public_key' => 'pk_XXXX',
10512
+ * ) );
10513
+ * ```
10514
+ *
10515
+ * @author Swashata Ghosh (@swashata)
10516
+ * @since 2.5.0
10517
+ *
10518
+ * @return bool True if we are running in bundle context, false otherwise.
10519
+ */
10520
+ private function has_bundle_context() {
10521
+ return ! is_null( $this->get_bundle_id() );
10522
+ }
10523
+
10524
  /**
10525
  * @author Vova Feldman (@svovaf)
10526
  * @since 1.2.1.5
10565
  function get_eula_url() {
10566
  return $this->apply_filters(
10567
  'eula_url',
10568
+ "https://freemius.com/product/{$this->_plugin->id}/{$this->_slug}/legal/eula/"
10569
  );
10570
  }
10571
 
10753
  #endregion ------------------------------------------------------------------
10754
 
10755
  /* Account
10756
+ ------------------------------------------------------------------------------------------------------------------*/
10757
 
10758
  /**
10759
  * Find plugin's slug by plugin's basename.
10817
  */
10818
  private static function get_all_sites(
10819
  $module_type = WP_FS__MODULE_TYPE_PLUGIN,
10820
+ $blog_id = null,
10821
+ $is_backup = false
10822
  ) {
10823
+ $sites = self::get_account_option(
10824
+ ( $is_backup ? 'prev_' : '' ) . 'sites',
10825
+ $module_type,
10826
+ $blog_id
10827
+ );
10828
 
10829
  if ( ! is_array( $sites ) ) {
10830
  $sites = array();
11184
  *
11185
  * @author Vova Feldman (@svovaf)
11186
  * @since 1.0.1
11187
+ *
11188
+ * @param bool $ignore_anonymous_state Since 2.5.1
11189
+ *
11190
  * @return bool
11191
  */
11192
+ function is_registered( $ignore_anonymous_state = false ) {
11193
+ return (
11194
+ is_object( $this->_user ) &&
11195
+ (
11196
+ $this->is_premium() ||
11197
+ $ignore_anonymous_state ||
11198
+ ! $this->is_anonymous()
11199
+ )
11200
+ );
11201
  }
11202
 
11203
  /**
11208
  *
11209
  * @return bool
11210
  */
11211
+ function is_tracking_allowed( $blog_id = null, $install = null ) {
11212
+ if ( is_null( $install ) ) {
11213
+ $install = is_null( $blog_id ) ?
11214
+ $this->_site :
11215
+ $this->get_install_by_blog_id( $blog_id );
11216
+ }
11217
+
11218
+ return (
11219
+ is_object( $install ) &&
11220
+ FS_Permission_Manager::instance( $this )->is_homepage_url_tracking_allowed( $blog_id )
11221
+ );
11222
+ }
11223
+
11224
+ /**
11225
+ * Returns TRUE if the user never opted-in or manually opted-out.
11226
+ *
11227
+ * @author Vova Feldman (@svovaf)
11228
+ * @since 1.2.1.5
11229
+ *
11230
+ * @param int|null $blog_id
11231
+ *
11232
+ * @return bool
11233
+ */
11234
+ function is_tracking_prohibited( $blog_id = null ) {
11235
+ return (
11236
+ ! $this->is_registered( true ) ||
11237
+ ! $this->is_tracking_allowed( $blog_id )
11238
+ );
11239
  }
11240
 
11241
  /**
11271
  }
11272
 
11273
  /**
11274
+ * @author Vova Feldman (@svovaf)
11275
+ * @since 1.0.3
11276
+ *
11277
+ * @return FS_Site
11278
+ */
11279
+ function get_site() {
11280
+ return $this->_site;
11281
+ }
11282
+
11283
+ /**
11284
+ * @author Leo Fajardo (@leorw)
11285
+ * @since 2.5.0
11286
+ */
11287
+ function store_site( $site ) {
11288
+ $this->_site = $site;
11289
+ $this->_store_site( true );
11290
+ }
11291
+
11292
+ /**
11293
+ * Deletes the current install with an option to back it up in case restoration will be needed (e.g., if the automatic clone resolution attempt fails).
11294
+ *
11295
+ * @author Leo Fajardo (@leorw)
11296
+ * @since 2.5.0
11297
+ */
11298
+ function delete_current_install( $back_up ) {
11299
+ // Back up and delete the unique ID.
11300
+ if ( $back_up ) {
11301
+ self::$_accounts->set_option( 'prev_unique_id', $this->get_anonymous_id() );
11302
+ }
11303
+
11304
+ self::$_accounts->set_option( 'unique_id', null );
11305
+
11306
+ if ( $back_up ) {
11307
+ // Back up the install before deleting it so that it can be restored later on if necessary (e.g., if the automatic clone resolution attempt fails).
11308
+ $this->back_up_site();
11309
+ }
11310
+
11311
+ $this->_delete_site();
11312
+ $this->_site = null;
11313
+ }
11314
+
11315
+ /**
11316
+ * @author Leo Fajardo (@leorw)
11317
+ * @since 2.5.0
11318
  */
11319
+ function restore_backup_site() {
11320
+ self::$_accounts->set_option(
11321
+ 'unique_id',
11322
+ self::$_accounts->get_option( 'prev_unique_id' )
11323
+ );
11324
+
11325
+ $sites = self::get_all_sites( $this->_module_type, null, true );
11326
+ $this->store_site( clone $sites[ $this->_slug ] );
11327
  }
11328
 
11329
  /**
12607
  } else {
12608
  $url = is_object( $site ) ?
12609
  $site->siteurl :
12610
+ self::get_unfiltered_site_url( $blog_id );
12611
 
12612
  $disconnected_site_ids[] = $blog_id;
12613
  }
12980
  } else if ( $is_whitelabeled_flag ) {
12981
  $is_whitelabeled = true;
12982
  } else {
12983
+ if ( $this->is_registered() || $this->is_premium() ) {
12984
+ $addon_ids = $this->get_updated_account_addons();
12985
+ } else {
12986
+ $addons = self::get_all_addons();
12987
+
12988
+ $plugin_addons = isset( $addons[ $this->_plugin->id ] ) ?
12989
+ $addons[ $this->_plugin->id ] :
12990
+ array();
12991
+
12992
+ $addon_ids = array();
12993
+ foreach ( $plugin_addons as $addon ) {
12994
+ $addon_ids[] = $addon->id;
12995
+ }
12996
+ }
12997
+
12998
  $installed_addons = $this->get_installed_addons();
12999
  foreach ( $installed_addons as $fs_addon ) {
13000
  $addon_ids[] = $fs_addon->get_id();
13423
  fs_require_template( 'forms/resend-key.php', $vars );
13424
  }
13425
 
13426
+ /**
13427
+ * Displays an email address update dialog box when the user clicks on the email address "Edit" button on the "Account" page.
13428
+ *
13429
+ * @author Leo Fajardo (@leorw)
13430
+ * @since 2.5.0
13431
+ */
13432
+ function _add_email_address_update_dialog_box() {
13433
+ $vars = array( 'id' => $this->_module_id );
13434
+
13435
+ fs_require_template( 'forms/email-address-update.php', $vars );
13436
+ }
13437
+
13438
+ /**
13439
+ * @author Leo Fajardo (@leorw)
13440
+ * @since 2.5.0
13441
+ */
13442
+ function _add_email_address_update_option() {
13443
+ if ( ! $this->should_handle_user_change() ) {
13444
+ return;
13445
+ }
13446
+
13447
+ // Add email address update AJAX handler.
13448
+ $this->add_ajax_action( 'update_email_address', array( &$this, '_email_address_update_ajax_handler' ) );
13449
+ }
13450
+
13451
+ /**
13452
+ * @author Leo Fajardo (@leorw)
13453
+ * @since 2.5.0
13454
+ */
13455
+ function _email_address_update_ajax_handler() {
13456
+ $this->check_ajax_referer( 'update_email_address' );
13457
+
13458
+ $new_email_address = fs_request_get( 'email_address' );
13459
+ $transfer_type = fs_request_get( 'transfer_type' );
13460
+
13461
+ $result = $this->update_email( $new_email_address );
13462
+
13463
+ if ( ! FS_Api::is_api_error( $result ) ) {
13464
+ self::shoot_ajax_success();
13465
+ }
13466
+
13467
+ $error = '';
13468
+
13469
+ if ( FS_Api::is_api_error_object( $result ) ) {
13470
+ switch ( $result->error->code ) {
13471
+ case 'user_exist':
13472
+ case 'account_verification_required':
13473
+ $error = array(
13474
+ 'code' => 'change_ownership',
13475
+ 'url' => $this->get_account_url( 'change_owner', array(
13476
+ 'state' => 'init',
13477
+ 'candidate_email' => $new_email_address,
13478
+ 'transfer_type' => $transfer_type,
13479
+ ) ),
13480
+ );
13481
+
13482
+ break;
13483
+ }
13484
+ }
13485
+
13486
+ if ( empty( $error ) ) {
13487
+ $error = is_object( $result ) ?
13488
+ var_export( $result->error, true ) :
13489
+ $result;
13490
+ }
13491
+
13492
+ self::shoot_ajax_failure( $error );
13493
+ }
13494
+
13495
  /**
13496
  * Returns a collection of IDs of installs that are associated with the context product and its add-ons, and activated with foreign licenses.
13497
  *
13699
  ( $is_network_admin && $this->is_network_active() && ! $this->is_network_delegated_connection() ) ||
13700
  ( ! $is_network_admin && ( ! $this->is_network_active() || $this->is_delegated_connection() ) )
13701
  ) {
13702
+ if (
13703
+ $this->is_premium() ||
13704
+ ( $this->has_paid_plan() && ! $this->has_premium_version() )
13705
+ ) {
13706
+ /**
13707
+ * @since 1.2.0 Add license action link only on plugins page.
13708
+ */
13709
+ $this->_add_license_action_link();
13710
+ }
13711
  }
13712
  }
13713
 
13879
  self::shoot_ajax_failure();
13880
  }
13881
 
13882
+ $site = $this->api_site_call(
13883
  '',
13884
  'put',
13885
  array(
13932
  fs_request_get( 'blog_id', null ),
13933
  fs_request_get( 'module_id', null, 'post' ),
13934
  fs_request_get( 'user_id', null ),
13935
+ fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
13936
+ fs_request_get_bool( 'is_diagnostic_tracking_allowed', null )
13937
  );
13938
 
13939
  if (
14178
  * @param null|int $blog_id
14179
  * @param null|number $plugin_id
14180
  * @param null|number $license_owner_id
14181
+ * @param bool|null $is_extensions_tracking_allowed
14182
+ * @param bool|null $is_diagnostic_tracking_allowed Since 2.5.0.2 to allow license activation with minimal data footprint.
14183
+ *
14184
  *
14185
  * @return array {
14186
  * @var bool $success
14195
  $blog_id = null,
14196
  $plugin_id = null,
14197
  $license_owner_id = null,
14198
+ $is_extensions_tracking_allowed = null,
14199
+ $is_diagnostic_tracking_allowed = null
14200
  ) {
14201
  $this->_logger->entrance();
14202
 
14216
  $this :
14217
  $this->get_addon_instance( $plugin_id );
14218
 
14219
+ FS_Permission_Manager::instance( $this )->update_permissions_tracking_flag( array(
14220
+ FS_Permission_Manager::PERMISSION_DIAGNOSTIC => $is_diagnostic_tracking_allowed,
14221
+ FS_Permission_Manager::PERMISSION_EXTENSIONS => $is_extensions_tracking_allowed,
14222
+ ) );
14223
 
14224
  $error = false;
14225
  $next_page = false;
14384
  }
14385
  }
14386
 
14387
+ $all_sites = self::get_sites();
14388
+ $pending_blog_ids = array();
14389
 
14390
  /**
14391
  * Check if there are any sites that are not connected, skipped, nor delegated. For every site that falls into that category, if the product is freemium, skip the connection. If the product is premium only, delegate the connection to the site administrator.
14415
  continue;
14416
  }
14417
 
14418
+ $pending_blog_ids[] = $blog_id;
14419
  }
14420
 
14421
+ if ( ! empty( $pending_blog_ids ) ) {
14422
  if ( $fs->is_freemium() && $fs->is_enable_anonymous() ) {
14423
+ $fs->skip_connection( $pending_blog_ids );
14424
  } else {
14425
+ $fs->delegate_connection( $pending_blog_ids );
14426
  }
14427
  }
14428
  }
14500
 
14501
  $addon_info = $fs->_get_addon_info( $addon_id, $is_installed );
14502
 
14503
+ if ( ! isset( $addon_info['is_connected'] ) || ! $addon_info['is_connected'] ) {
14504
  // Add-on is not associated with an install entity.
14505
  continue;
14506
  }
14558
  $this->delegate_connection();
14559
  } else {
14560
  if ( ! empty( $sites_by_action['delegate'] ) ) {
14561
+ $this->delegate_connection( self::get_sites_blog_ids( $sites_by_action['delegate'] ) );
14562
  }
14563
 
14564
  if ( ! empty( $sites_by_action['skip'] ) ) {
14565
+ $this->skip_connection( self::get_sites_blog_ids( $sites_by_action['skip'] ) );
14566
  }
14567
 
14568
  if ( empty( $sites_by_action['allow'] ) ) {
14880
  return $this->_plugin->has_affiliate_program();
14881
  }
14882
 
14883
+ /**
14884
+ * Get Plugin ID under which we will track affiliate application.
14885
+ *
14886
+ * This could either be the Bundle ID or the main plugin ID.
14887
+ *
14888
+ * @return number Bundle ID if developer has provided one, else the main plugin ID.
14889
+ */
14890
+ private function get_plugin_id_for_affiliate_terms() {
14891
+ return $this->has_bundle_context() ?
14892
+ $this->get_bundle_id() :
14893
+ $this->_plugin_id;
14894
+ }
14895
+
14896
  /**
14897
  * @author Leo Fajardo (@leorw)
14898
  * @since 1.2.4
14899
  */
14900
  private function fetch_affiliate_terms() {
14901
  if ( ! is_object( $this->plugin_affiliate_terms ) ) {
14902
+ /**
14903
+ * In case we have a bundle set in SDK configuration, we would like to use that for affiliates, not the main plugin.
14904
+ */
14905
+ $plugins_api = $this->has_bundle_context() ?
14906
+ $this->get_api_bundle_scope() :
14907
+ $this->get_api_plugin_scope();
14908
+
14909
  $affiliate_terms = $plugins_api->get( '/aff.json?type=affiliation', false );
14910
 
14911
+ /**
14912
+ * At this point, we intentionally don't fallback to the main plugin, because the developer has chosen to use bundle. So it makes sense the affiliate program should be in context to the bundle too.
14913
+ */
14914
  if ( ! $this->is_api_result_entity( $affiliate_terms ) ) {
14915
  return;
14916
  }
14928
  $application_data = $this->_storage->affiliate_application_data;
14929
  $flush = ( ! isset( $application_data['status'] ) || 'pending' === $application_data['status'] );
14930
 
14931
+ $plugin_id_for_affiliate = $this->get_plugin_id_for_affiliate_terms();
14932
+
14933
  $users_api = $this->get_api_user_scope();
14934
+ $result = $users_api->get( "/plugins/{$plugin_id_for_affiliate}/aff/{$this->plugin_affiliate_terms->id}/affiliates.json", $flush );
14935
  if ( $this->is_api_result_object( $result, 'affiliates' ) ) {
14936
  if ( ! empty( $result->affiliates ) ) {
14937
  $affiliate = new FS_Affiliate( $result->affiliates[0] );
15031
  var_export( $next_page, true )
15032
  );
15033
  } else if ( $this->is_pending_activation() ) {
15034
+ self::shoot_ajax_failure( $this->get_text_inline( 'Account is pending activation. Please check your email and click the link to activate your account and then submit the affiliate form again.', 'account-is-pending-activation' ) );
15035
  }
15036
  }
15037
 
15038
  $this->fetch_affiliate_terms();
15039
 
15040
+ $plugin_id_for_affiliate = $this->get_plugin_id_for_affiliate_terms();
15041
+
15042
  $api = $this->get_api_user_scope();
15043
  $result = $api->call(
15044
+ ( "/plugins/{$plugin_id_for_affiliate}/aff/{$this->plugin_affiliate_terms->id}/affiliates.json" ),
15045
  'post',
15046
  $affiliate
15047
  );
15503
  return ( defined( 'DOING_CRON' ) && DOING_CRON );
15504
  }
15505
 
15506
+ /**
15507
+ * @author Leo Fajardo (@leorw)
15508
+ * @since 2.5.0
15509
+ *
15510
+ * @return bool
15511
+ */
15512
+ static function is_admin_post() {
15513
+ return ( 'admin-post.php' === self::get_current_page() );
15514
+ }
15515
+
15516
  /**
15517
  * Check if a real user is visiting the admin dashboard.
15518
  *
15526
  is_admin() &&
15527
  ! self::is_ajax() &&
15528
  ! self::is_cron() &&
15529
+ ! self::is_admin_post()
15530
  );
15531
  }
15532
 
15678
  * @author Leo Fajardo (@leorw)
15679
  * @since 2.0.0
15680
  *
15681
+ * @param bool|int[] $all_or_blog_ids
15682
  */
15683
+ private function delegate_connection( $all_or_blog_ids = true ) {
15684
  $this->_logger->entrance();
15685
 
15686
  $this->_admin_notices->remove_sticky( 'connect_account' );
15687
 
15688
+ if ( true === $all_or_blog_ids ) {
15689
  // All sites delegation.
15690
+ $this->_storage->store( 'is_delegated_connection', true, true );
15691
  } else {
15692
  // Specified sites delegation.
15693
+ foreach ( $all_or_blog_ids as $blog_id ) {
15694
+ $this->delegate_site_connection( $blog_id );
15695
  }
15696
  }
15697
 
15707
  * @param int $blog_id
15708
  */
15709
  private function delegate_site_connection( $blog_id ) {
15710
+ $this->_storage->store( 'is_delegated_connection', true, $blog_id );
15711
  }
15712
 
15713
  /**
15747
  }
15748
 
15749
  /**
15750
+ * Check if delegated the connection. When running within the network admin,
15751
  * and haven't specified the blog ID, checks if network level delegated. If running
15752
  * within a site admin or specified a blog ID, check if delegated the connection for
15753
  * the current context site.
15807
  }
15808
 
15809
  /**
15810
+ * @todo Implement pagination when accessing the subsites collection.
15811
+ *
15812
  * @author Leo Fajardo (@leorw)
15813
  * @since 2.0.0
15814
  *
15815
+ * @param int $limit Default to 1,000
15816
+ * @param int $offset Default to 0
15817
+ *
15818
  * @return array Active & public sites collection.
15819
  */
15820
+ static function get_sites( $limit = 1000, $offset = 0 ) {
15821
  if ( ! is_multisite() ) {
15822
  return array();
15823
  }
15839
  'mature' => 0,
15840
  'spam' => 0,
15841
  'deleted' => 0,
15842
+ 'number' => $limit,
15843
+ 'offset' => $offset,
15844
  );
15845
 
15846
+ return get_sites( $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15847
  }
15848
 
15849
  /**
15892
  $address_to_blog_map = array();
15893
  foreach ( $sites as $site ) {
15894
  $blog_id = self::get_site_blog_id( $site );
15895
+ $address = self::get_unfiltered_site_url( $blog_id, true, true );
15896
  $address_to_blog_map[ $address ] = $blog_id;
15897
  }
15898
 
15928
  return $install_map;
15929
  }
15930
 
15931
+ /**
15932
+ * @author Vova Feldman (@svovaf)
15933
+ * @since 2.5.1
15934
+ *
15935
+ * @param bool|null $is_delegated When `true`, returns only connection delegated blog IDs. When `false`, only non-delegated blog IDs.
15936
+ *
15937
+ * @return int[]
15938
+ */
15939
+ private function get_blog_ids( $is_delegated = null ) {
15940
+ $blog_ids = array();
15941
+
15942
+ $sites = self::get_sites();
15943
+ foreach ( $sites as $site ) {
15944
+ $blog_id = self::get_site_blog_id( $site );
15945
+
15946
+ if (
15947
+ is_null( $is_delegated ) ||
15948
+ $is_delegated === $this->is_site_delegated_connection( $blog_id )
15949
+ ) {
15950
+ $blog_ids[] = $blog_id;
15951
+ }
15952
+ }
15953
+
15954
+ return $blog_ids;
15955
+ }
15956
+
15957
+ /**
15958
+ * @author Vova Feldman (@svovaf)
15959
+ * @since 2.5.1
15960
+ *
15961
+ * @return int[]
15962
+ */
15963
+ private function get_non_delegated_blog_ids() {
15964
+ return $this->get_blog_ids( false );
15965
+ }
15966
+
15967
  /**
15968
  * Gets a map of module IDs that the given user has opted-in to.
15969
  *
16048
  *
16049
  * @param int $blog_id
16050
  * @param FS_Site $install
16051
+ * @param bool $flush
16052
  *
16053
  * @return bool Since 2.3.1 returns if a switch was made.
16054
  */
16055
+ function switch_to_blog( $blog_id, FS_Site $install = null, $flush = false ) {
16056
+ if ( ! is_numeric( $blog_id ) ) {
16057
+ return false;
16058
+ }
16059
+
16060
+ if ( ! $flush && $blog_id == $this->_context_is_network_or_blog_id ) {
16061
  return false;
16062
  }
16063
 
16121
  unset( $this->_site_api );
16122
  unset( $this->_user_api );
16123
 
16124
+ return true;
16125
  }
16126
 
16127
  /**
16150
  $site['blog_id'] );
16151
  }
16152
 
16153
+ /**
16154
+ * @author Vova Feldman (@svovaf)
16155
+ * @since 2.5.1
16156
+ *
16157
+ * @param WP_Site[]|array[] $sites
16158
+ *
16159
+ * @return int[]
16160
+ */
16161
+ static function get_sites_blog_ids( $sites ) {
16162
+ $blog_ids = array();
16163
+ foreach ( $sites as $site ) {
16164
+ $blog_ids[] = self::get_site_blog_id( $site );
16165
+ }
16166
+
16167
+ return $blog_ids;
16168
+ }
16169
+
16170
  /**
16171
  * @author Leo Fajardo (@leorw)
16172
  * @since 2.0.0
16173
  *
16174
  * @param array|WP_Site|null $site
16175
+ * @param bool $load_registration Since 2.5.1 When set to `true` the method will attempt to return the subsite's registration date, regardless of the `$site` type and value. In most calls, the registration date will be returned anyway, even when the value is `false`. This param is purely for performance optimization.
16176
  *
16177
  * @return array
16178
  */
16179
+ function get_site_info( $site = null, $load_registration = false ) {
16180
  $this->_logger->entrance();
16181
 
16182
  $switched = false;
16183
 
16184
+ $registration_date = null;
16185
+
16186
  if ( is_null( $site ) ) {
16187
+ $url = self::get_unfiltered_site_url();
16188
  $name = get_bloginfo( 'name' );
16189
  $blog_id = null;
16190
  } else {
16196
  }
16197
 
16198
  if ( $site instanceof WP_Site ) {
16199
+ $url = $site->siteurl;
16200
+ $name = $site->blogname;
16201
+ $registration_date = $site->registered;
16202
  } else {
16203
+ $url = self::get_unfiltered_site_url( $blog_id );
16204
  $name = get_bloginfo( 'name' );
16205
  }
16206
  }
16207
 
16208
+ if ( empty( $registration_date ) && $load_registration ) {
16209
+ $blog_details = get_blog_details( $blog_id, false );
16210
+
16211
+ if ( is_object( $blog_details ) && isset( $blog_details->registered ) ) {
16212
+ $registration_date = $blog_details->registered;
16213
+ }
16214
+ }
16215
+
16216
  $info = array(
16217
+ 'uid' => $this->get_anonymous_id( $blog_id ),
16218
+ 'url' => $url,
 
 
 
16219
  );
16220
 
16221
+ // Add these diagnostic information only if user allowed to track.
16222
+ if ( FS_Permission_Manager::instance( $this )->is_diagnostic_tracking_allowed() ) {
16223
+ $info = array_merge( $info, array(
16224
+ 'title' => $name,
16225
+ 'language' => self::get_sanitized_language(),
16226
+ ) );
16227
+ }
16228
+
16229
  if ( is_numeric( $blog_id ) ) {
16230
  $info['blog_id'] = $blog_id;
16231
  }
16232
 
16233
+ if ( ! empty( $registration_date ) ) {
16234
+ $info[ 'registration_date' ] = $registration_date;
16235
+ }
16236
+
16237
  if ( $switched ) {
16238
  restore_current_blog();
16239
  }
16456
  }
16457
  }
16458
 
16459
+ if ( ! $this->is_registered() ) {
16460
+ return;
16461
+ }
16462
+
16463
  if ( $this->is_sync_cron_scheduled() &&
16464
  $context_blog_id == $this->get_sync_cron_blog_id()
16465
  ) {
16493
 
16494
  $this->update_multisite_data_after_site_deactivation( $context_blog_id );
16495
 
16496
+ if ( ! $this->is_registered() ) {
16497
+ return;
16498
+ }
16499
+
16500
  $current_blog_id = get_current_blog_id();
16501
 
16502
  $this->switch_to_blog( $context_blog_id );
16530
 
16531
  $this->update_multisite_data_after_site_deactivation( $context_blog_id );
16532
 
16533
+ if ( ! $this->is_registered() ) {
16534
+ return;
16535
+ }
16536
+
16537
  $current_blog_id = get_current_blog_id();
16538
 
16539
  $this->switch_to_blog( $context_blog_id );
16551
  $this->switch_to_blog( $current_blog_id );
16552
  }
16553
 
16554
+ /**
16555
+ * Executed after site deletion, called from wp_delete_site
16556
+ *
16557
+ * @author Dario Curvino (@dudo)
16558
+ * @since 2.5.0
16559
+ *
16560
+ * @param WP_Site $old_site
16561
+ */
16562
+ public function _after_wpsite_deleted_callback( WP_Site $old_site ) {
16563
+ $this->_logger->entrance();
16564
+
16565
+ $this->_after_site_deleted_callback( $old_site->blog_id, true );
16566
+ }
16567
+
16568
  /**
16569
  * Executed after site re-activation.
16570
  *
16679
  * @return bool
16680
  */
16681
  function is_product_settings_page() {
16682
+ $page = fs_request_get( 'page', '', 'get' );
16683
+ $menu_slug = $this->_menu->get_slug();
16684
+
16685
+ if ( $page === $menu_slug ) {
16686
+ return true;
16687
+ }
16688
+
16689
  return fs_starts_with(
16690
+ // e.g., {$menu_slug}-account, {$menu_slug}-affiliation, etc.
16691
+ $page,
16692
+ ( $menu_slug . '-' )
16693
  );
16694
  }
16695
 
16769
  *
16770
  * @param bool|string $topic
16771
  * @param bool|string $message
16772
+ * @param bool|string $summary Since 2.5.1.
16773
  *
16774
  * @return string
16775
  */
16776
+ function contact_url( $topic = false, $message = false, $summary = false ) {
16777
  $params = array();
16778
  if ( is_string( $topic ) ) {
16779
  $params['topic'] = $topic;
16782
  $params['message'] = $message;
16783
  }
16784
 
16785
+ if ( is_string( $summary ) ) {
16786
+ $params['summary'] = $summary;
16787
+ }
16788
+
16789
  if ( $this->is_addon() ) {
16790
  $params['addon_id'] = $this->get_id();
16791
 
16824
  }
16825
 
16826
  /* Logger
16827
+ ------------------------------------------------------------------------------------------------------------------*/
16828
  /**
16829
  * @param string $id
16830
  * @param bool $prefix_slug
16849
  }
16850
 
16851
  /* Security
16852
+ ------------------------------------------------------------------------------------------------------------------*/
16853
  private static function _encrypt( $str ) {
16854
  if ( is_null( $str ) ) {
16855
  return null;
17069
  ) {
17070
  // Load site.
17071
  $this->_site = $site;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17072
  }
17073
 
17074
  $user = null;
17097
  /**
17098
  * This is a special fault tolerance mechanism to handle a scenario that the user data is missing.
17099
  */
17100
+ if (
17101
+ ! isset( $this->_storage->user_recovery_from_install_last_attempt_timestamp ) ||
17102
+ time() > ( $this->_storage->user_recovery_from_install_last_attempt_timestamp + FS_Clone_Manager::CLONE_RESOLUTION_MAX_EXECUTION_TIME )
17103
+ ) {
17104
+ $user = $this->sync_user_by_current_install();
17105
+ } else {
17106
+ return;
17107
+ }
17108
+
17109
+ if ( is_object( $user ) ) {
17110
+ $this->_storage->user_was_recovered_from_install = true;
17111
+ } else {
17112
+ $this->_storage->user_recovery_from_install_attempts = isset( $this->_storage->user_recovery_from_install_attempts ) ?
17113
+ ( $this->_storage->user_recovery_from_install_attempts + 1 ) :
17114
+ 1;
17115
+
17116
+ if ( $this->_storage->user_recovery_from_install_attempts >= 3 ) {
17117
+ $this->delete_current_install( false );
17118
+ } else {
17119
+ $this->_storage->user_recovery_from_install_last_attempt_timestamp = time();
17120
+
17121
+ return;
17122
+ }
17123
+ }
17124
  }
17125
 
17126
  $this->_user = ( $user instanceof FS_User ) ?
17134
  }
17135
 
17136
  if ( is_object( $this->_site ) ) {
17137
+ // Load plans.
17138
+ $this->_plans = isset( $plans[ $this->_slug ] ) ?
17139
+ $plans[ $this->_slug ] :
17140
+ array();
17141
+
17142
+ if ( ! is_array( $this->_plans ) || empty( $this->_plans ) ) {
17143
+ $this->_sync_plans();
17144
+ } else {
17145
+ for ( $i = 0, $len = count( $this->_plans ); $i < $len; $i ++ ) {
17146
+ if ( $this->_plans[ $i ] instanceof FS_Plugin_Plan ) {
17147
+ $this->_plans[ $i ] = self::decrypt_entity( $this->_plans[ $i ] );
17148
+ } else {
17149
+ unset( $this->_plans[ $i ] );
17150
+ }
17151
+ }
17152
+ }
17153
+
17154
  $this->_license = $this->_get_license_by_id( $this->_site->license_id );
17155
 
17156
  if ( $this->_site->version != $this->get_plugin_version() ) {
17169
  if ( $this->is_theme() ) {
17170
  $this->_register_account_hooks();
17171
  }
17172
+
17173
+ if ( $this->is_user_in_admin() && $this->is_clone() ) {
17174
+ if ( empty( FS_Clone_Manager::instance()->get_clone_identification_timestamp() ) ) {
17175
+ FS_Clone_Manager::instance()->store_clone_identification_timestamp();
17176
+ }
17177
+
17178
+ FS_Clone_Manager::instance()->maybe_update_clone_resolution_support_flag( $this->_storage->sdk_last_version );
17179
+ $this->send_pending_clone_update_once();
17180
+ }
17181
  }
17182
 
17183
  /**
17257
  */
17258
  private function get_versions() {
17259
  $versions = array();
17260
+ $versions['sdk_version'] = $this->version;
17261
+
17262
+ // Collect these diagnostic information only if it's allowed.
17263
+ if ( FS_Permission_Manager::instance( $this )->is_diagnostic_tracking_allowed() ) {
17264
+ $versions['platform_version'] = get_bloginfo( 'version' );
17265
+ $versions['programming_language_version'] = phpversion();
17266
+ }
17267
+
17268
+ foreach ( $versions as $k => $version ) {
17269
+ $versions[ $k ] = self::get_api_sanitized_property( $k, $version );
17270
+ }
17271
+
17272
+ return $versions;
17273
+ }
17274
+
17275
+ /**
17276
+ * Get sanitized site language.
17277
+ *
17278
+ * @param string $language
17279
+ * @param int $max_len
17280
+ *
17281
+ * @since 2.5.1
17282
+ * @author Vova Feldman (@svovaf)
17283
+ *
17284
+ * @return string
17285
+ */
17286
+ private static function get_sanitized_language( $language = '', $max_len = self::LANGUAGE_MAX_CHARS ) {
17287
+ if ( empty( $language ) ) {
17288
+ $language = get_bloginfo( 'language' );
17289
+ }
17290
+
17291
+ return substr( $language, 0, $max_len );
17292
+ }
17293
+
17294
+ /**
17295
+ * Get core version stripped from pre-release and build.
17296
+ *
17297
+ * @since 2.5.1
17298
+ * @author Vova Feldman (@svovaf)
17299
+ *
17300
+ * @param string $version
17301
+ * @param int $parts
17302
+ * @param int $max_len
17303
+ * @param bool $include_pre_release
17304
+ *
17305
+ * @return string
17306
+ */
17307
+ private static function get_core_version(
17308
+ $version,
17309
+ $parts = 3,
17310
+ $max_len = self::VERSION_MAX_CHARS,
17311
+ $include_pre_release = false
17312
+ ) {
17313
+ if ( empty( $version ) ) {
17314
+ // Version is empty.
17315
+ return '';
17316
+ }
17317
+
17318
+ if ( is_numeric( $version ) ) {
17319
+ $is_float_version = is_float( $version );
17320
+
17321
+ $version = (string) $version;
17322
+
17323
+ /**
17324
+ * Casting a whole float number to a string cuts the decimal point. This part make sure to add the missing decimal part to the version.
17325
+ */
17326
+ if ( $is_float_version && false === strpos( $version, '.' ) ) {
17327
+ $version .= '.0';
17328
+ }
17329
+ }
17330
+
17331
+ if ( ! is_string( $version ) ) {
17332
+ return '';
17333
+ }
17334
+
17335
+ if ( $parts < 1 ) {
17336
+ return '';
17337
+ }
17338
 
17339
+ $pre_release_regex = $include_pre_release ?
17340
+ '(\-(alpha|beta|RC)([0-9]+)?)?' :
17341
+ '';
17342
+
17343
+ if ( 0 === preg_match( '/^([0-9]+(\.[0-9]+){0,' . ( $parts - 1 ) . '}' . $pre_release_regex . ')/i', $version, $matches ) ) {
17344
+ // Version is not starting with a digit.
17345
+ return '';
17346
  }
17347
 
17348
+ return substr( $matches[1], 0, $max_len );
17349
+ }
17350
+
17351
+ /**
17352
+ * @param string $prop
17353
+ * @param mixed $val
17354
+ *
17355
+ * @return mixed
17356
+ *@author Vova Feldman (@svovaf)
17357
+ *
17358
+ * @since 2.5.1
17359
+ */
17360
+ private static function get_api_sanitized_property( $prop, $val ) {
17361
+ if ( ! is_string( $val ) || empty( $val ) ) {
17362
+ return $val;
17363
+ }
17364
+
17365
+ switch ( $prop ) {
17366
+ case 'programming_language_version':
17367
+ // Get core PHP version, which can have up to 3 parts (ignore pre-releases).
17368
+ return self::get_core_version( $val );
17369
+ case 'platform_version':
17370
+ // Get the exact WordPress version, which can have up to 3 parts (including pre-releases).
17371
+ return self::get_core_version( $val, 3, self::VERSION_MAX_CHARS, true );
17372
+ case 'sdk_version':
17373
+ // Get the exact SDK version, which can have up to 4 parts.
17374
+ return self::get_core_version( $val, 4 );
17375
+ case 'version':
17376
+ // Get the entire version but just limited in length.
17377
+ return substr( $val, 0, self::VERSION_MAX_CHARS );
17378
+ case 'language':
17379
+ return self::get_sanitized_language( $val );
17380
+ default:
17381
+ return $val;
17382
+ }
17383
  }
17384
 
17385
  /**
17434
  $versions = $this->get_versions();
17435
 
17436
  $params = array_merge( $versions, array(
17437
+ 'user_firstname' => $current_user->user_firstname,
17438
+ 'user_lastname' => $current_user->user_lastname,
17439
+ 'user_email' => $current_user->user_email,
17440
+ 'plugin_slug' => $this->_slug,
17441
+ 'plugin_id' => $this->get_id(),
17442
+ 'plugin_public_key' => $this->get_public_key(),
17443
+ 'plugin_version' => $this->get_plugin_version(),
17444
+ 'return_url' => fs_nonce_url( $return_url, $activation_action ),
17445
+ 'account_url' => fs_nonce_url( $this->_get_admin_page_url(
 
 
17446
  'account',
17447
  array( 'fs_action' => 'sync_user' )
17448
  ), 'sync_user' ),
17449
+ 'is_premium' => $this->is_premium(),
17450
+ 'is_active' => true,
17451
+ 'is_uninstalled' => false,
17452
+ 'is_localhost' => WP_FS__IS_LOCALHOST,
17453
  ) );
17454
 
17455
  if ( $this->is_addon() ) {
17470
 
17471
  $site = $this->get_site_info( $site );
17472
 
17473
+ $diagnostic_info = array();
17474
+ if ( FS_Permission_Manager::instance( $this )->is_diagnostic_tracking_allowed() ) {
17475
+ $diagnostic_info = array(
17476
+ 'site_name' => $site['title'],
17477
+ 'language' => self::get_sanitized_language( $site['language'] ),
17478
+ );
17479
+ }
17480
+
17481
+ $params = array_merge( $params, $diagnostic_info, array(
17482
  'site_uid' => $site['uid'],
17483
  'site_url' => $site['url'],
 
 
 
17484
  ) );
17485
  }
17486
 
17505
  );
17506
  }
17507
 
17508
+ if ( is_multisite() && function_exists( 'get_network' ) ) {
17509
+ $params['network_uid'] = $this->get_anonymous_network_id();
17510
+ }
17511
+
17512
  return array_merge( $params, $override_with );
17513
  }
17514
 
17527
  * In this case, the user and site info will be sent to the server but no
17528
  * data will be saved to the WP installation's database.
17529
  * @param number|bool $trial_plan_id
17530
+ * @param bool $is_disconnected Whether to opt in without tracking.
17531
  * @param null|bool $is_marketing_allowed
17532
  * @param array $sites If network-level opt-in, an array of containing details of sites.
17533
+ * @param bool $redirect
17534
  *
17535
  * @return string|object
17536
  * @use WP_Error
17544
  $trial_plan_id = false,
17545
  $is_disconnected = false,
17546
  $is_marketing_allowed = null,
17547
+ $sites = array(),
17548
+ $redirect = true
17549
  ) {
17550
  $this->_logger->entrance();
17551
 
17569
  $fs_user,
17570
  false,
17571
  $trial_plan_id,
17572
+ $redirect,
17573
  true,
17574
  $sites
17575
  );
17637
  $params['is_marketing_allowed'] = $is_marketing_allowed;
17638
  }
17639
 
17640
+ $params['is_disconnected'] = $is_disconnected;
17641
+ $params['format'] = 'json';
17642
+ $params['is_extensions_tracking_allowed'] = FS_Permission_Manager::instance( $this )->is_extensions_tracking_allowed();
17643
+ $params['is_diagnostic_tracking_allowed'] = FS_Permission_Manager::instance( $this )->is_diagnostic_tracking_allowed();
17644
 
17645
  $request = array(
17646
  'method' => 'POST',
17647
  'body' => $params,
17648
+ 'timeout' => 60,
17649
  );
17650
 
17651
  $url = $this->add_show_pending( WP_FS__ADDRESS . '/action/service/user/install/' );
17731
  true ),
17732
  false,
17733
  $filtered_license_key,
17734
+ ! empty( $params['trial_plan_id'] ),
17735
+ isset( $decoded->is_suspicious_email ) && $decoded->is_suspicious_email
17736
  );
17737
  } else if ( isset( $decoded->install_secret_key ) ) {
17738
  return $this->install_with_new_user(
17745
  ( isset( $decoded->is_extensions_tracking_allowed ) && ! is_null( $decoded->is_extensions_tracking_allowed ) ?
17746
  $decoded->is_extensions_tracking_allowed :
17747
  null ),
17748
+ ( isset( $decoded->is_diagnostic_tracking_allowed ) && ! is_null( $decoded->is_diagnostic_tracking_allowed ) ?
17749
+ $decoded->is_diagnostic_tracking_allowed :
17750
+ null ),
17751
  $decoded->install_id,
17752
  $decoded->install_public_key,
17753
  $decoded->install_secret_key,
17764
  ( isset( $decoded->is_extensions_tracking_allowed ) && ! is_null( $decoded->is_extensions_tracking_allowed ) ?
17765
  $decoded->is_extensions_tracking_allowed :
17766
  null ),
17767
+ ( isset( $decoded->is_diagnostic_tracking_allowed ) && ! is_null( $decoded->is_diagnostic_tracking_allowed ) ?
17768
+ $decoded->is_diagnostic_tracking_allowed :
17769
+ null ),
17770
  $decoded->installs,
17771
  false
17772
  );
17864
  $this->_admin_notices->remove_sticky( 'connect_account' );
17865
 
17866
  if ( $this->is_pending_activation() || ! $this->has_settings_menu() ) {
17867
+ $this->clear_pending_activation_mode();
 
 
 
 
17868
 
17869
  if ( ! $this->is_paying_or_trial() ) {
17870
  $this->_admin_notices->add_sticky(
17871
+ sprintf( $this->get_text_inline( '%s opt-in was successfully completed.', 'plugin-x-activation-message' ), '<b>' . $this->get_plugin_name() . '</b>' ),
17872
  'activation_complete'
17873
  );
17874
  }
17990
  fs_request_get( 'user_secret_key' ),
17991
  fs_request_get_bool( 'is_marketing_allowed', null ),
17992
  fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
17993
+ fs_request_get_bool( 'is_diagnostic_tracking_allowed', null ),
17994
  $pending_sites_info['blog_ids'],
17995
  $pending_sites_info['license_key'],
17996
  $pending_sites_info['trial_plan_id']
18002
  fs_request_get( 'user_secret_key' ),
18003
  fs_request_get_bool( 'is_marketing_allowed', null ),
18004
  fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
18005
+ fs_request_get_bool( 'is_diagnostic_tracking_allowed', null ),
18006
  fs_request_get( 'install_id' ),
18007
  fs_request_get( 'install_public_key' ),
18008
  fs_request_get( 'install_secret_key' ),
18011
  );
18012
  }
18013
  } else if ( fs_request_has( 'pending_activation' ) ) {
18014
+ $this->set_pending_confirmation(
18015
+ fs_request_get( 'user_email' ),
18016
+ true,
18017
+ false,
18018
+ false,
18019
+ fs_request_get_bool( 'is_suspicious_email' )
18020
+ );
18021
  }
18022
  }
18023
  }
18065
  * @param string $user_secret_key
18066
  * @param bool|null $is_marketing_allowed
18067
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
18068
+ * @param bool|null $is_diagnostic_tracking_allowed Since 2.5.0.2
18069
  * @param number $install_id
18070
  * @param string $install_public_key
18071
  * @param string $install_secret_key
18080
  $user_secret_key,
18081
  $is_marketing_allowed,
18082
  $is_extensions_tracking_allowed,
18083
+ $is_diagnostic_tracking_allowed,
18084
  $install_id,
18085
  $install_public_key,
18086
  $install_secret_key,
18114
  $site->secret_key = $install_secret_key;
18115
 
18116
  $this->_site = $site;
18117
+ $site_result = $this->get_api_site_scope( true )->get();
18118
  $site = new FS_Site( $site_result );
18119
  $this->_site = $site;
18120
 
18122
  $this->disable_opt_in_notice_and_lock_user();
18123
  }
18124
 
18125
+ FS_Permission_Manager::instance( $this )->update_permissions_tracking_flag( array(
18126
+ FS_Permission_Manager::PERMISSION_DIAGNOSTIC => $is_diagnostic_tracking_allowed,
18127
+ FS_Permission_Manager::PERMISSION_EXTENSIONS => $is_extensions_tracking_allowed,
18128
+ ) );
18129
 
18130
  return $this->setup_account(
18131
  $this->_user,
18146
  * @param string $user_secret_key
18147
  * @param bool|null $is_marketing_allowed
18148
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
18149
+ * @param bool|null $is_diagnostic_tracking_allowed Since 2.5.0.2
18150
  * @param array $site_ids
18151
  * @param bool $license_key
18152
  * @param bool $trial_plan_id
18160
  $user_secret_key,
18161
  $is_marketing_allowed,
18162
  $is_extensions_tracking_allowed,
18163
+ $is_diagnostic_tracking_allowed,
18164
  $site_ids,
18165
  $license_key = false,
18166
  $trial_plan_id = false,
18172
  $this->disable_opt_in_notice_and_lock_user();
18173
  }
18174
 
18175
+ FS_Permission_Manager::instance( $this )->update_permissions_tracking_flag( array(
18176
+ FS_Permission_Manager::PERMISSION_DIAGNOSTIC => $is_diagnostic_tracking_allowed,
18177
+ FS_Permission_Manager::PERMISSION_EXTENSIONS => $is_extensions_tracking_allowed,
18178
+ ) );
18179
 
18180
  $sites = array();
18181
  foreach ( $site_ids as $site_id ) {
18196
  * @param string $user_secret_key
18197
  * @param bool|null $is_marketing_allowed
18198
  * @param bool|null $is_extensions_tracking_allowed Since 2.3.2
18199
+ * @param bool|null $is_diagnostic_tracking_allowed Since 2.5.0.2
18200
  * @param object[] $installs
18201
  * @param bool $redirect
18202
  * @param bool $auto_install Since 1.2.1.7 If `true` and setting up an account with a valid license, will redirect (or return a URL) to the account page with a special parameter to trigger the auto installation processes.
18209
  $user_secret_key,
18210
  $is_marketing_allowed,
18211
  $is_extensions_tracking_allowed,
18212
+ $is_diagnostic_tracking_allowed,
18213
  array $installs,
18214
  $redirect = true,
18215
  $auto_install = false
18220
  $this->disable_opt_in_notice_and_lock_user();
18221
  }
18222
 
18223
+ FS_Permission_Manager::instance( $this )->update_permissions_tracking_flag( array(
18224
+ FS_Permission_Manager::PERMISSION_DIAGNOSTIC => $is_diagnostic_tracking_allowed,
18225
+ FS_Permission_Manager::PERMISSION_EXTENSIONS => $is_extensions_tracking_allowed,
18226
+ ) );
18227
 
18228
  $install_ids = array();
18229
 
18231
  $install_ids[] = $install->id;
18232
  }
18233
 
18234
+ $items_per_request = 25;
18235
+ $left = count( $install_ids );
18236
+ $offset = 0;
18237
 
18238
  $installs = array();
18239
  while ( $left > 0 ) {
18240
+ $result = $this->get_api_user_scope()->get( "/plugins/{$this->_module_id}/installs.json?ids=" . implode( ',', array_slice( $install_ids, $offset, $items_per_request ) ) );
18241
 
18242
  if ( ! $this->is_api_result_object( $result, 'installs' ) ) {
18243
  // @todo Handle API error.
18245
 
18246
  $installs = array_merge( $installs, $result->installs );
18247
 
18248
+ $left -= $items_per_request;
18249
+ $offset += $items_per_request;
18250
  }
18251
 
18252
  foreach ( $installs as &$install ) {
18276
  $email = false,
18277
  $redirect = true,
18278
  $license_key = false,
18279
+ $is_pending_trial = false,
18280
+ $is_suspicious_email = false
18281
  ) {
18282
  if ( $this->_ignore_pending_mode ) {
18283
  /**
18287
  * @author Vova Feldman
18288
  * @since 1.2.1.6
18289
  */
18290
+ $this->skip_connection( fs_is_network_admin() );
18291
  } else {
18292
  // Install must be activated via email since
18293
  // user with the same email already exist.
18294
  $this->_storage->is_pending_activation = true;
18295
+ $this->_add_pending_activation_notice( $email, $is_pending_trial, $is_suspicious_email );
18296
  }
18297
 
18298
  if ( ! empty( $license_key ) ) {
18307
 
18308
  $next_page = $this->get_after_activation_url( 'after_pending_connect_url' );
18309
 
 
18310
  if ( $redirect ) {
18311
+ // Reload the page with a pending activation message.
18312
  fs_redirect( $next_page );
18313
  }
18314
 
18337
  */
18338
  $license_key = fs_request_get( 'license_secret_key' );
18339
 
18340
+ FS_Permission_Manager::instance( $this )->update_permissions_tracking_flag( array(
18341
+ FS_Permission_Manager::PERMISSION_DIAGNOSTIC => fs_request_get_bool( 'is_diagnostic_tracking_allowed', null ),
18342
+ FS_Permission_Manager::PERMISSION_EXTENSIONS => fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
18343
+ ) );
18344
 
18345
  $this->install_with_current_user( $license_key );
18346
  }
18358
  *
18359
  * @return object|string If redirect is `false`, returns the next page the user should be redirected to, or the API error object if failed to install.
18360
  */
18361
+ function install_with_current_user(
18362
  $license_key = false,
18363
  $trial_plan_id = false,
18364
  $sites = array(),
18741
  $this->send_installs_update();
18742
  }
18743
 
 
 
 
18744
  $current_blog = get_current_blog_id();
18745
 
18746
  foreach ( $blog_2_install_map as $blog_id => $install ) {
18749
  $this->do_action( 'after_account_connection', $this->_user, $install );
18750
  }
18751
 
18752
+ // Switch install context back to the first install.
18753
+ $this->switch_to_blog(
18754
+ $current_blog,
18755
+ $first_install,
18756
+ ( $this->_site->id != $first_install->id )
18757
+ );
18758
 
18759
  $this->do_action( 'after_network_account_connection', $this->_user, $blog_2_install_map );
18760
  }
18802
  $parent_fs->_admin_notices->remove_sticky( 'connect_account' );
18803
 
18804
  if ( $parent_fs->is_pending_activation() ) {
18805
+ $parent_fs->clear_pending_activation_mode();
 
 
18806
  }
18807
 
18808
  // Get user information based on parent's plugin.
18856
  // return;
18857
  // }
18858
 
18859
+ if ( is_object( $this->_site ) && ! $this->is_registered() ) {
18860
+ return;
18861
+ }
18862
+
18863
  /**
18864
  * When running from a site admin with a network activated module and the connection
18865
  * was NOT delegated and the user still haven't skipped or opted-in, then hide the
19814
  *
19815
  * @return string
19816
  */
19817
+ static function get_ajax_action_static( $tag, $module_id = null ) {
19818
  $action = "fs_{$tag}";
19819
 
19820
  if ( ! empty( $module_id ) ) {
19837
  * @uses do_action()
19838
  */
19839
  function do_action( $tag, $arg = '' ) {
 
 
19840
  $args = func_get_args();
19841
 
19842
+ $this->_logger->entrance( $tag );
19843
+
19844
  call_user_func_array( 'do_action', array_merge(
19845
  array( $this->get_action_tag( $tag ) ),
19846
  array_slice( $args, 1 ) )
19980
  wp_send_json( $result );
19981
  }
19982
 
19983
+ /**
19984
+ * Returns an AJAX URL with a special extra param to indicate whether the request was triggered from the network admin or blog admin.
19985
+ *
19986
+ * @author Vova Feldman (@svovaf)
19987
+ * @since 2.5.1
19988
+ *
19989
+ * @param string $wrap_with By default, returns the AJAX URL wrapped with single quotes.
19990
+ *
19991
+ * @return string
19992
+ */
19993
+ static function ajax_url( $wrap_with = "'") {
19994
+ if ( fs_is_network_admin() ) {
19995
+ $param_name = '_fs_network_admin';
19996
+ } else {
19997
+ $param_name = '_fs_blog_admin';
19998
+ }
19999
+
20000
+ $url = admin_url( 'admin-ajax.php', 'relative' );
20001
+ $url .= ( false === strpos( $url, '?' ) ) ? '?' : '&';
20002
+ $url .= "{$param_name}=true";
20003
+
20004
+ return "{$wrap_with}{$url}{$wrap_with}";
20005
+ }
20006
+
20007
  /**
20008
  * Apply filter, specific for the current context plugin.
20009
  *
20018
  * @uses apply_filters()
20019
  */
20020
  function apply_filters( $tag, $value ) {
20021
+ $args = func_get_args();
20022
+
20023
  $this->_logger->entrance( $tag );
20024
 
 
20025
  array_unshift( $args, $this->get_unique_affix() );
20026
 
20027
  return call_user_func_array( 'fs_apply_filter', $args );
20082
  }
20083
 
20084
  /* Account Page
20085
+ ------------------------------------------------------------------------------------------------------------------*/
20086
  /**
20087
  * Update site information.
20088
  *
20093
  * @param null|int $network_level_or_blog_id Since 2.0.0
20094
  * @param \FS_Site $site Since 2.0.0
20095
  */
20096
+ private function _store_site( $store = true, $network_level_or_blog_id = null, FS_Site $site = null, $is_backup = false ) {
20097
  $this->_logger->entrance();
20098
 
20099
  if ( is_null( $site ) ) {
20108
 
20109
  $site_clone = clone $site;
20110
 
20111
+ $sites = self::get_all_sites( $this->_module_type, $network_level_or_blog_id, $is_backup );
20112
 
20113
+ if (
20114
+ ! $is_backup &&
20115
+ is_object( $this->_user ) && $this->_user->id != $site->user_id
20116
+ ) {
20117
  $this->sync_user_by_current_install( $site->user_id );
20118
 
20119
  $prev_stored_user_id = $this->_storage->get( 'prev_user_id', false, $network_level_or_blog_id );
20138
 
20139
  $sites[ $this->_slug ] = $site_clone;
20140
 
20141
+ $this->set_account_option(
20142
+ ( $is_backup ? 'prev_' : '' ) . 'sites',
20143
+ $sites,
20144
+ $store,
20145
+ $network_level_or_blog_id
20146
+ );
20147
+ }
20148
+
20149
+ /**
20150
+ * Stores the context site in the sites backup storage. This logic is used before deleting the site info so that it can be restored later on if necessary (e.g., if the automatic clone resolution attempt fails).
20151
+ *
20152
+ * @author Leo Fajardo (@leorw)
20153
+ * @since 2.5.0
20154
+ */
20155
+ private function back_up_site() {
20156
+ $this->_logger->entrance();
20157
+
20158
+ $site_clone = clone $this->_site;
20159
+
20160
+ $this->_store_site( true, null, $site_clone, true );
20161
  }
20162
 
20163
  /**
21398
  $this->switch_to_blog( $current_blog_id );
21399
  }
21400
 
21401
+ $result = $this->send_install_update( array(), true, true );
21402
  $is_valid = $this->is_api_result_entity( $result );
21403
  } else {
21404
+ $result = $this->send_installs_update( array(), true, true );
21405
  $is_valid = $this->is_api_result_object( $result, 'installs' );
21406
  }
21407
 
21411
  $this->switch_to_blog( $this->_storage->network_install_blog_id );
21412
  }
21413
 
21414
+ // Show API message only if not background sync or if paying customer.
21415
  if ( ! $background || $this->is_paying() ) {
21416
  // Try to ping API to see if not blocked.
21417
  if ( ! FS_Api::test() ) {
21421
  * @author Vova Feldman (@svovaf)
21422
  * @since 1.1.6 Only show message related to one of the Freemius powered plugins. Once it will be resolved it will fix the issue for all plugins anyways. There's no point to scare users with multiple error messages.
21423
  */
 
21424
 
21425
  if ( ! self::$_global_admin_notices->has_sticky( 'api_blocked' ) ) {
21426
+ // Add notice immediately if not a background sync.
21427
+ $add_notice = ( ! $background );
21428
+
21429
+ if ( ! $add_notice ) {
21430
+ $counter = (int) get_transient( '_fs_api_connection_retry_counter' );
21431
+
21432
+ // We only want to add the notice after 3 consecutive failures.
21433
+ $add_notice = ( 3 <= $counter );
21434
+
21435
+ if ( ! $add_notice ) {
21436
+ /**
21437
+ * Update counter transient only if notice shouldn't be added. If it is added the transient will be reset anyway, because the retries mechanism should only start counting if the admin isn't aware of the connectivity issue.
21438
+ *
21439
+ * Also, since the background sync happens once a day, setting the transient expiration for a week should be enough to count 3 failures, if there's an actual connectivity issue.
21440
+ */
21441
+ set_transient( '_fs_api_connection_retry_counter', $counter + 1, WP_FS__TIME_WEEK_IN_SEC );
21442
+ }
21443
+ }
21444
+
21445
+ // Add notice instantly for not-background sync and only after 3 failed attempts for background sync.
21446
+ if ( $add_notice ) {
21447
+ self::$_global_admin_notices->add(
21448
+ sprintf(
21449
+ $this->get_text_inline( 'Your server is blocking the access to Freemius\' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s', 'server-blocking-access' ),
21450
+ $this->get_plugin_name(),
21451
+ '<b>' . implode( ', ', $this->apply_filters( 'api_domains', array(
21452
+ 'api.freemius.com',
21453
+ 'wp.freemius.com'
21454
+ ) ) ) . '</b>'
21455
+ ) . '<br> ' . $this->get_text_inline( 'Error received from the server:', 'server-error-message' ) . var_export( $result->error, true ),
21456
+ $this->get_text_x_inline( 'Oops', 'exclamation', 'oops' ) . '...',
21457
+ 'error',
21458
+ $background,
21459
+ 'api_blocked'
21460
+ );
21461
+
21462
+ // Notice was just shown, reset connectivity counter.
21463
+ delete_transient( '_fs_api_connection_retry_counter' );
21464
+ }
21465
  }
21466
+ } else if ( is_object( $result ) ) {
21467
  // Authentication params are broken.
21468
  $this->_admin_notices->add(
21469
  $this->get_text_inline( 'It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again.', 'wrong-authentication-param-message' ) . '<br> ' . $this->get_text_inline( 'Error received from the server:', 'server-error-message' ) . var_export( $result->error, true ),
21477
  return;
21478
  }
21479
 
21480
+ // API is working now. Delete the transient and start afresh.
21481
+ delete_transient('_fs_api_connection_retry_counter');
21482
+
21483
  if ( $is_site_level_sync ) {
21484
  $site = new FS_Site( $result );
21485
  } else {
21671
  }
21672
 
21673
  if ( ! $this->is_addon() &&
21674
+ $this->_site->is_beta() !== $site->is_beta()
21675
  ) {
21676
  // Beta flag updated.
21677
  $this->_site = $site;
22226
  if ( ! $this->is_api_result_entity( $plan ) ) {
22227
  // Some API error while trying to start the trial.
22228
  $this->_admin_notices->add(
22229
+ $this->get_api_error_message( $plan ),
 
22230
  $oops_text,
22231
  'error'
22232
  );
22404
  ) {
22405
  $this->_logger->entrance();
22406
 
22407
+ if ( $this->is_unresolved_clone( true ) ) {
22408
+ return false;
22409
+ }
22410
+
22411
  $switch_to_blog_id = null;
22412
 
22413
  /**
22414
  * @since 1.1.7.3 Check for plugin updates from Freemius only if opted-in.
22415
  * @since 1.1.7.4 Also check updates for add-ons.
22416
  */
22417
+ if (
22418
+ ( ! $this->is_registered() || ! FS_Permission_Manager::instance( $this )->is_essentials_tracking_allowed() ) &&
22419
  ! $this->_is_addon_id( $addon_id )
22420
  ) {
22421
  if ( ! is_multisite() ) {
22425
  $installs_map = $this->get_blog_install_map();
22426
 
22427
  foreach ( $installs_map as $blog_id => $install ) {
22428
+ if ( ! FS_Permission_Manager::instance( $this )->is_essentials_tracking_allowed( $blog_id ) ) {
22429
+ continue;
22430
+ }
22431
+
22432
  /**
22433
  * @var FS_Site $install
22434
  */
22525
  private function get_latest_download_api_url( $plugin_id = false ) {
22526
  $this->_logger->entrance();
22527
 
22528
+ $download_api_url = $this->get_api_site_scope()->get_signed_url(
22529
  $this->_get_latest_version_endpoint( $plugin_id, 'zip' )
22530
  );
22531
+
22532
+ return str_replace( 'http:', 'https:', $download_api_url );
22533
  }
22534
 
22535
  /**
22724
  private function update_email( $new_email ) {
22725
  $this->_logger->entrance();
22726
 
 
22727
  $api = $this->get_api_user_scope();
22728
  $user = $api->call( "?plugin_id={$this->_plugin->id}&fields=id,email,is_verified", 'put', array(
22729
  'email' => $new_email,
22739
  $this->_store_user();
22740
  } else {
22741
  // handle different error cases.
 
22742
  }
22743
 
22744
  return $user;
22814
  * @uses FS_Api
22815
  *
22816
  * @param string $candidate_email
22817
+ * @param string $transfer_type
22818
  *
22819
  * @return bool Is ownership change successfully initiated.
22820
  */
22821
+ private function init_change_owner( $candidate_email, $transfer_type ) {
22822
  $this->_logger->entrance();
22823
 
22824
+ $installs_info_by_slug_map = $this->get_parent_and_addons_installs_info();
22825
+ $install_ids = array();
22826
+
22827
+ foreach ( $installs_info_by_slug_map as $slug => $install_info ) {
22828
+ $install = $install_info['install'];
22829
+
22830
+ if ( $this->_user->id != $install->user_id ) {
22831
+ // Skip add-on installs that are not owned by the parent product's install's owner.
22832
+ continue;
22833
+ }
22834
+
22835
+ $install_ids[ $slug ] = $install->id;
22836
+ }
22837
+
22838
  $api = $this->get_api_site_scope();
22839
  $result = $api->call( "/users/{$this->_user->id}.json", 'put', array(
22840
  'email' => $candidate_email,
22841
+ 'transfer_type' => $transfer_type,
22842
+ 'install_ids' => implode( ',', array_values( $install_ids ) ),
22843
  'after_confirm_url' => $this->_get_admin_page_url(
22844
  'account',
22845
  array( 'fs_action' => 'change_owner' )
22861
  private function complete_change_owner() {
22862
  $this->_logger->entrance();
22863
 
22864
+ $install_ids = fs_request_get( 'install_ids' );
22865
+
22866
+ if ( ! empty( $install_ids ) ) {
22867
+ $install_ids = explode( ',', $install_ids );
22868
+
22869
+ foreach ( $install_ids as $key => $install_id ) {
22870
+ if ( ! FS_Site::is_valid_id( $install_id ) ) {
22871
+ unset( $install_ids[ $key ] );
22872
+ }
22873
+ }
22874
+ }
22875
+
22876
+ if ( ! is_array( $install_ids ) ) {
22877
+ $install_ids = array();
22878
+ }
22879
+
22880
+ $user = new FS_User();
22881
+ $user->id = fs_request_get( 'user_id' );
22882
+ $user->public_key = fs_request_get( 'user_public_key' );
22883
+ $user->secret_key = fs_request_get( 'user_secret_key' );
22884
 
22885
+ $prev_user = $this->_user;
22886
+ $this->_user = $user;
22887
+
22888
+ $result = $this->get_api_user_scope( true )->get(
22889
+ "/installs.json?install_ids=" . implode( ',', $install_ids )
22890
+ );
22891
+
22892
+ $current_blog_sites = self::get_all_sites( $this->get_module_type() );
22893
+
22894
+ if ( $this->is_api_result_object( $result, 'installs' ) ) {
22895
+ $site_id_slug_map = array();
22896
+
22897
+ foreach ( $current_blog_sites as $slug => $site ) {
22898
+ $site_id_slug_map[ $site->id ] = $slug;
22899
+ }
22900
+
22901
+ foreach ( $result->installs as $install ) {
22902
+ $site = new FS_Site( $install );
22903
+
22904
+ if ( ! isset( $site_id_slug_map[ $install->id ] ) ) {
22905
+ continue;
22906
+ }
22907
+
22908
+ $current_blog_sites[ $site_id_slug_map[ $install->id ] ] = clone $site;
22909
+
22910
+ if ( $this->_site->id == $site->id ) {
22911
+ $this->_site = $site;
22912
+ }
22913
+ }
22914
+ }
22915
 
22916
  // Validate install's user and given user.
22917
  if ( $user->id != $this->_site->user_id ) {
22918
+ $this->_user = $prev_user;
22919
+
22920
  return false;
22921
  }
22922
 
22923
+ $this->set_account_option( 'sites', $current_blog_sites, true );
 
22924
 
22925
  // Fetch new user information.
 
22926
  $user_result = $this->get_api_user_scope( true )->get();
22927
  $user = new FS_User( $user_result );
22928
  $this->_user = $user;
22929
 
22930
+ $this->_set_account( $user, $this->_site );
22931
+
22932
+ $remove_user = true;
22933
+ $all_modules_sites = self::get_all_modules_sites();
22934
+
22935
+ foreach ( $all_modules_sites as $sites_by_module_type ) {
22936
+ foreach ( $sites_by_module_type as $sites_by_slug ) {
22937
+ foreach ( $sites_by_slug as $site ) {
22938
+ if ( $prev_user->id == $site->user_id ) {
22939
+ $remove_user = false;
22940
+ break;
22941
+ }
22942
+ }
22943
+
22944
+ if ( ! $remove_user ) {
22945
+ break;
22946
+ }
22947
+ }
22948
+
22949
+ if ( ! $remove_user ) {
22950
+ break;
22951
+ }
22952
+ }
22953
+
22954
+ if ( $remove_user ) {
22955
+ $users = self::get_all_users();
22956
+
22957
+ if ( isset( $users[ $prev_user->id ] ) ) {
22958
+ unset( $users[ $prev_user->id ] );
22959
+ } else {
22960
+ // If the prev user wasn't found by the key, iterate over the users collection.
22961
+ foreach ( $users as $key => $user ) {
22962
+ if ( $user->id == $prev_user->id ) {
22963
+ unset( $users[ $key ] );
22964
+ break;
22965
+ }
22966
+ }
22967
+ }
22968
+
22969
+ $this->set_account_option( 'users', $users, true );
22970
+ }
22971
 
22972
  return true;
22973
  }
23212
 
23213
  if ( $is_parent_plugin_action ) {
23214
  if ( $is_network_action && ! empty( $blog_id ) ) {
23215
+ if ( $this->is_registered( true ) ) {
23216
+ if ( $this->is_tracking_prohibited( $blog_id ) ) {
23217
+ if ( $this->toggle_site_tracking( true, $blog_id ) ) {
23218
  $this->_admin_notices->add(
23219
+ sprintf( $this->get_text_inline( 'Sharing diagnostic data with %s helps to provide functionality that\'s more relevant to your website, avoid WordPress or PHP version incompatibilities that can break your website, and recognize which languages & regions the plugin should be translated and tailored to.', 'opt-out-message-appreciation' ), "<b>{$this->get_plugin_title()}</b>" ),
23220
  $this->get_text_inline( 'Thank you!', 'thank-you' )
23221
  );
23222
  }
23223
  } else {
23224
+ if ( $this->toggle_site_tracking( false, $blog_id ) ) {
23225
+ $install = $this->get_install_by_blog_id( $blog_id );
23226
+
23227
  $this->_admin_notices->add(
23228
  sprintf(
23229
+ $this->get_text_inline( 'Diagnostic data will no longer be sent from %s to %s.', 'opted-out-successfully' ),
23230
+ self::get_unfiltered_site_url( $blog_id, true ),
23231
+ "<b>{$this->get_plugin_title()}</b>"
 
 
 
 
 
23232
  )
23233
  );
23234
  }
23376
  $state = fs_request_get( 'state', 'init' );
23377
  switch ( $state ) {
23378
  case 'init':
23379
+ $candidate_email = fs_request_get( 'candidate_email' );
23380
+ $transfer_type = fs_request_get( 'transfer_type' );
23381
 
23382
+ if ( $this->init_change_owner( $candidate_email, $transfer_type ) ) {
23383
+ if ( 'transfer' === $transfer_type ) {
23384
+ $this->_admin_notices->add( sprintf( $this->get_text_inline( 'A confirmation email was just sent to %s. The email owner must confirm the update within the next 4 hours.', 'change-owner-request-sent-x-transfer' ), '<b>' . $this->_user->email . '</b>' ) );
23385
+ } else {
23386
+ $this->_admin_notices->add( sprintf( $this->get_text_inline( 'A confirmation email was just sent to %s. You must confirm the update within the next 4 hours. If you cannot find the email, please check your spam folder.', 'change-owner-request-sent-x' ), '<b>' . $this->_user->email . '</b>' ) );
23387
+ }
23388
  }
23389
  break;
23390
  case 'owner_confirmed':
23407
 
23408
  return;
23409
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23410
  case 'update_user_name':
23411
  check_admin_referer( 'update_user_name' );
23412
 
23568
 
23569
  fs_enqueue_local_style( 'fs_affiliation', '/admin/affiliation.css' );
23570
 
23571
+ $is_bundle_context = $this->has_bundle_context();
23572
+
23573
+ $plugin_title = $this->get_plugin_title();
23574
+
23575
+ if ( $is_bundle_context ) {
23576
+ $plugin_title = $this->plugin_affiliate_terms->plugin_title;
23577
+
23578
+ // Add the suffix "Bundle" only if the word is not present in the title itself.
23579
+ if ( false === mb_stripos( $plugin_title, fs_text_inline( 'Bundle', 'bundle' ) ) ) {
23580
+ $plugin_title = $this->apply_filters(
23581
+ 'formatted_bundle_title',
23582
+ $plugin_title . ' ' . fs_text_inline( 'Bundle', 'bundle' )
23583
+ );
23584
+ }
23585
+ }
23586
+
23587
+ $vars = array(
23588
+ 'id' => $this->_module_id,
23589
+ 'plugin_title' => $plugin_title,
23590
+ );
23591
  echo $this->apply_filters( "/forms/affiliation.php", fs_get_template( '/forms/affiliation.php', $vars ) );
23592
  }
23593
 
23688
  }
23689
 
23690
  /* Pricing & Upgrade
23691
+ ------------------------------------------------------------------------------------------------------------------*/
23692
  /**
23693
  * Render pricing page.
23694
  *
23830
  }
23831
 
23832
  static function _clean_admin_content_section_hook() {
23833
+ $hide_admin_notices = true;
23834
+
23835
+ if ( fs_request_is_action( 'allow_clone_resolution_notice' ) ) {
23836
+ check_admin_referer( 'fs_allow_clone_resolution_notice' );
23837
+
23838
+ $hide_admin_notices = false;
23839
+ }
23840
+
23841
+ if ( $hide_admin_notices ) {
23842
+ self::_hide_admin_notices();
23843
+ }
23844
 
23845
  // Hide footer.
23846
  echo '<style>#wpfooter { display: none !important; }</style>';
23857
  }
23858
 
23859
  /* CSS & JavaScript
23860
+ ------------------------------------------------------------------------------------------------------------------*/
23861
  /* function _enqueue_script($handle, $src) {
23862
+ $url = plugins_url( substr( WP_FS__DIR_JS, strlen( $this->_plugin_dir_path ) ) . '/assets/js/' . $src );
23863
 
23864
+ $this->_logger->entrance( 'script = ' . $url );
23865
 
23866
+ wp_enqueue_script( $handle, $url );
23867
+ }*/
23868
 
23869
  /* SDK
23870
+ ------------------------------------------------------------------------------------------------------------------*/
23871
  private $_user_api;
23872
 
23873
  /**
23879
  *
23880
  * @return FS_Api
23881
  */
23882
+ function get_api_user_scope( $flush = false ) {
23883
  if ( ! isset( $this->_user_api ) || $flush ) {
23884
  $this->_user_api = $this->get_api_user_scope_by_user( $this->_user );
23885
  }
23958
  $this->_site->public_key,
23959
  ! $this->is_live(),
23960
  $this->_site->secret_key,
23961
+ $this->get_sdk_version(),
23962
+ self::get_unfiltered_site_url()
23963
  );
23964
  }
23965
 
23966
  return $this->_site_api;
23967
  }
23968
 
23969
+ /**
23970
+ * @author Leo Fajardo (@leorw)
23971
+ * @since 2.5.0
23972
+ *
23973
+ * @param string $path
23974
+ * @param string $method
23975
+ * @param array $params
23976
+ * @param bool $flush_instance
23977
+ *
23978
+ * @return array|mixed|string|void
23979
+ * @throws Freemius_Exception
23980
+ */
23981
+ private function api_site_call( $path, $method = 'GET', $params = array(), $flush_instance = false ) {
23982
+ $result = $this->get_api_site_scope( $flush_instance )->call( $path, $method, $params );
23983
+
23984
+ /**
23985
+ * Checks if the local install's URL is different from the remote install's URL, update the local install if necessary, and then run the clone handler if the install's URL is different from the URL of the site.
23986
+ *
23987
+ * @author Leo Fajardo (@leorw)
23988
+ * @since 2.5.0
23989
+ */
23990
+ if (
23991
+ $this->is_registered() &&
23992
+ FS_Api::is_api_result_entity( $result ) &&
23993
+ isset( $result->url )
23994
+ ) {
23995
+ $stored_local_url = trailingslashit( $this->_site->url );
23996
+ $stored_remote_url = trailingslashit( $result->url );
23997
+
23998
+ if ( $stored_local_url !== $stored_remote_url ) {
23999
+ $this->_site->url = $result->url;
24000
+ $this->_store_site();
24001
+ }
24002
+
24003
+ if ( fs_strip_url_protocol( $stored_remote_url ) !== self::get_unfiltered_site_url( null, true, true ) ) {
24004
+ FS_Clone_Manager::instance()->maybe_run_clone_resolution();
24005
+ }
24006
+ }
24007
+
24008
+ return $result;
24009
+ }
24010
+
24011
  private $_plugin_api;
24012
 
24013
  /**
24443
  }
24444
 
24445
  /* Action Links
24446
+ ------------------------------------------------------------------------------------------------------------------*/
24447
  private $_action_links_hooked = false;
24448
  private $_action_links = array();
24449
 
24614
 
24615
  $this->_logger->entrance();
24616
 
 
 
 
 
 
 
 
 
 
24617
  if ( $this->is_only_premium() && $this->is_free_plan() ) {
24618
  // Don't add tracking links for premium-only products that were opted-in by relation (add-on or a parent product) before activating any license.
24619
  return;
24621
 
24622
  if (
24623
  $this->is_addon() &&
24624
+ ! $this->is_only_premium()
 
24625
  ) {
24626
+ $parent = $this->get_parent_instance();
24627
+
24628
+ if ( is_object( $parent ) && $parent->is_anonymous() ) {
24629
+ return;
24630
+ }
24631
  }
24632
 
24633
  if ( fs_is_network_admin() ) {
24676
  }
24677
  }
24678
 
24679
+ if ( $this->add_ajax_action( 'toggle_permission_tracking', array( &$this, '_toggle_permission_tracking_callback' ) ) ) {
 
 
 
 
 
 
 
 
24680
  return;
24681
  }
24682
 
24683
  $link_text_id = '';
24684
  $url = '#';
24685
 
24686
+ if ( $this->is_registered( true ) ) {
24687
+ if ( $this->is_registered() && $this->is_tracking_allowed() ) {
24688
  $link_text_id = $this->get_text_inline( 'Opt Out', 'opt-out' );
24689
  } else {
24690
  $link_text_id = $this->get_text_inline( 'Opt In', 'opt-in' );
24881
  */
24882
  private function is_premium_version_installed() {
24883
  $premium_plugin_basename = $this->premium_plugin_basename();
 
24884
 
24885
+ if ( $this->is_theme() ) {
24886
+ return $this->can_activate_theme( $this->get_premium_slug() );
24887
+ }
24888
+
24889
+ return file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) );
24890
  }
24891
 
24892
  /**
24922
  * @author Leo Fajardo (@leorw)
24923
  * @since 2.2.1
24924
  */
24925
+ $premium_theme_slug_or_plugin_basename = $this->is_theme() ?
24926
+ $this->get_premium_slug() :
24927
+ $this->premium_plugin_basename();
24928
 
24929
  return sprintf(
24930
  /* translators: %1$s: Product title; %2$s: Plan title */
24933
  $plan_title,
24934
  sprintf(
24935
  '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s</button></a>',
24936
+ ( $this->is_theme() ?
24937
+ wp_nonce_url( 'themes.php?action=activate&amp;stylesheet=' . $premium_theme_slug_or_plugin_basename, 'switch-theme_' . $premium_theme_slug_or_plugin_basename ) :
24938
+ wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $premium_theme_slug_or_plugin_basename, 'activate-plugin_' . $premium_theme_slug_or_plugin_basename ) ),
24939
  esc_html( sprintf(
24940
  /* translators: %s: Plan title */
24941
  $this->get_text_inline( 'Activate %s features', 'activate-x-features' ),
24960
  ) ),
24961
  $deactivation_step,
24962
  $this->get_text_inline( 'Upload and activate the downloaded version', 'upload-and-activate' ),
24963
+ $this->apply_filters( 'upload_and_install_video_url', '//bit.ly/wp-' . $this->_module_type . '-upload' ),
24964
  $this->get_text_inline( 'How to upload and activate?', 'howto-upload-activate' )
24965
  );
24966
  }
25413
  function _tabs_capture() {
25414
  $this->_logger->entrance();
25415
 
25416
+ if (
25417
+ ! $this->is_product_settings_page() ||
25418
+ ! $this->should_page_include_tabs() ||
25419
+ ! $this->is_matching_url( $this->main_menu_url() )
25420
  ) {
25421
  return;
25422
  }
25470
  function _store_tabs_styles() {
25471
  $this->_logger->entrance();
25472
 
25473
+ if (
25474
+ ! $this->is_product_settings_page() ||
25475
+ ! $this->should_page_include_tabs() ||
25476
+ ! $this->is_matching_url( $this->main_menu_url() )
25477
  ) {
25478
  return;
25479
  }
freemius/includes/class-fs-admin-notices.php CHANGED
@@ -125,13 +125,10 @@
125
  $is_sticky = false,
126
  $id = '',
127
  $store_if_sticky = true,
128
- $network_level_or_blog_id = null
 
129
  ) {
130
- if ( $this->should_use_network_notices( $id, $network_level_or_blog_id ) ) {
131
- $notices = $this->_network_notices;
132
- } else {
133
- $notices = $this->get_site_notices( $network_level_or_blog_id );
134
- }
135
 
136
  $notices->add(
137
  $message,
@@ -139,7 +136,11 @@
139
  $type,
140
  $is_sticky,
141
  $id,
142
- $store_if_sticky
 
 
 
 
143
  );
144
  }
145
 
@@ -149,8 +150,9 @@
149
  *
150
  * @param string|string[] $ids
151
  * @param int|null $network_level_or_blog_id
 
152
  */
153
- function remove_sticky( $ids, $network_level_or_blog_id = null ) {
154
  if ( ! is_array( $ids ) ) {
155
  $ids = array( $ids );
156
  }
@@ -161,7 +163,7 @@
161
  $notices = $this->get_site_notices( $network_level_or_blog_id );
162
  }
163
 
164
- return $notices->remove_sticky( $ids );
165
  }
166
 
167
  /**
@@ -176,11 +178,7 @@
176
  * @return bool
177
  */
178
  function has_sticky( $id, $network_level_or_blog_id = null ) {
179
- if ( $this->should_use_network_notices( $id, $network_level_or_blog_id ) ) {
180
- $notices = $this->_network_notices;
181
- } else {
182
- $notices = $this->get_site_notices( $network_level_or_blog_id );
183
- }
184
 
185
  return $notices->has_sticky( $id );
186
  }
@@ -200,6 +198,7 @@
200
  * @param string|null $plugin_title
201
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and
202
  * blog admin pages.
 
203
  */
204
  function add_sticky(
205
  $message,
@@ -209,15 +208,30 @@
209
  $network_level_or_blog_id = null,
210
  $wp_user_id = null,
211
  $plugin_title = null,
212
- $is_network_and_blog_admins = false
 
 
213
  ) {
214
- if ( $this->should_use_network_notices( $id, $network_level_or_blog_id ) ) {
215
- $notices = $this->_network_notices;
216
- } else {
217
- $notices = $this->get_site_notices( $network_level_or_blog_id );
218
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
- $notices->add_sticky( $message, $id, $title, $type, $wp_user_id, $plugin_title, $is_network_and_blog_admins );
221
  }
222
 
223
  /**
@@ -227,21 +241,22 @@
227
  * @since 2.0.0
228
  *
229
  * @param int|null $network_level_or_blog_id
 
230
  */
231
- function clear_all_sticky( $network_level_or_blog_id = null ) {
232
  if ( ! $this->_is_multisite ||
233
  false === $network_level_or_blog_id ||
234
  0 == $network_level_or_blog_id ||
235
  is_null( $network_level_or_blog_id )
236
  ) {
237
  $notices = $this->get_site_notices( $network_level_or_blog_id );
238
- $notices->clear_all_sticky();
239
  }
240
 
241
  if ( $this->_is_multisite &&
242
  ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
243
  ) {
244
- $this->_network_notices->clear_all_sticky();
245
  }
246
  }
247
 
@@ -317,5 +332,22 @@
317
  return fs_is_network_admin();
318
  }
319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  #endregion
321
  }
125
  $is_sticky = false,
126
  $id = '',
127
  $store_if_sticky = true,
128
+ $network_level_or_blog_id = null,
129
+ $is_dimissible = null
130
  ) {
131
+ $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );
 
 
 
 
132
 
133
  $notices->add(
134
  $message,
136
  $type,
137
  $is_sticky,
138
  $id,
139
+ $store_if_sticky,
140
+ null,
141
+ null,
142
+ false,
143
+ $is_dimissible
144
  );
145
  }
146
 
150
  *
151
  * @param string|string[] $ids
152
  * @param int|null $network_level_or_blog_id
153
+ * @param bool $store
154
  */
155
+ function remove_sticky( $ids, $network_level_or_blog_id = null, $store = true ) {
156
  if ( ! is_array( $ids ) ) {
157
  $ids = array( $ids );
158
  }
163
  $notices = $this->get_site_notices( $network_level_or_blog_id );
164
  }
165
 
166
+ return $notices->remove_sticky( $ids, $store );
167
  }
168
 
169
  /**
178
  * @return bool
179
  */
180
  function has_sticky( $id, $network_level_or_blog_id = null ) {
181
+ $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );
 
 
 
 
182
 
183
  return $notices->has_sticky( $id );
184
  }
198
  * @param string|null $plugin_title
199
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and
200
  * blog admin pages.
201
+ * @param bool $is_dismissible
202
  */
203
  function add_sticky(
204
  $message,
208
  $network_level_or_blog_id = null,
209
  $wp_user_id = null,
210
  $plugin_title = null,
211
+ $is_network_and_blog_admins = false,
212
+ $is_dismissible = true,
213
+ $data = array()
214
  ) {
215
+ $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );
216
+
217
+ $notices->add_sticky( $message, $id, $title, $type, $wp_user_id, $plugin_title, $is_network_and_blog_admins, $is_dismissible, $data );
218
+ }
219
+
220
+ /**
221
+ * Retrieves the data of a sticky notice.
222
+ *
223
+ * @author Leo Fajardo (@leorw)
224
+ * @since 2.4.3
225
+ *
226
+ * @param string $id
227
+ * @param int|null $network_level_or_blog_id
228
+ *
229
+ * @return array|null
230
+ */
231
+ function get_sticky( $id, $network_level_or_blog_id ) {
232
+ $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );
233
 
234
+ return $notices->get_sticky( $id );
235
  }
236
 
237
  /**
241
  * @since 2.0.0
242
  *
243
  * @param int|null $network_level_or_blog_id
244
+ * @param bool $is_temporary
245
  */
246
+ function clear_all_sticky( $network_level_or_blog_id = null, $is_temporary = false ) {
247
  if ( ! $this->_is_multisite ||
248
  false === $network_level_or_blog_id ||
249
  0 == $network_level_or_blog_id ||
250
  is_null( $network_level_or_blog_id )
251
  ) {
252
  $notices = $this->get_site_notices( $network_level_or_blog_id );
253
+ $notices->clear_all_sticky( $is_temporary );
254
  }
255
 
256
  if ( $this->_is_multisite &&
257
  ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
258
  ) {
259
+ $this->_network_notices->clear_all_sticky( $is_temporary );
260
  }
261
  }
262
 
332
  return fs_is_network_admin();
333
  }
334
 
335
+ /**
336
+ * Retrieves an instance of FS_Admin_Notice_Manager.
337
+ *
338
+ * @author Leo Fajardo (@leorw)
339
+ * @since 2.5.0
340
+ *
341
+ * @param string $id
342
+ * @param int|null $network_level_or_blog_id
343
+ *
344
+ * @return FS_Admin_Notice_Manager
345
+ */
346
+ private function get_site_or_network_notices( $id, $network_level_or_blog_id ) {
347
+ return $this->should_use_network_notices( $id, $network_level_or_blog_id ) ?
348
+ $this->_network_notices :
349
+ $this->get_site_notices( $network_level_or_blog_id );
350
+ }
351
+
352
  #endregion
353
  }
freemius/includes/class-fs-api.php CHANGED
@@ -64,6 +64,14 @@
64
  */
65
  private $_sdk_version;
66
 
 
 
 
 
 
 
 
 
67
  /**
68
  * @param string $slug
69
  * @param string $scope 'app', 'developer', 'user' or 'install'.
@@ -72,6 +80,7 @@
72
  * @param bool $is_sandbox
73
  * @param bool|string $secret_key Element's secret key.
74
  * @param null|string $sdk_version
 
75
  *
76
  * @return FS_Api
77
  */
@@ -82,14 +91,15 @@
82
  $public_key,
83
  $is_sandbox,
84
  $secret_key = false,
85
- $sdk_version = null
 
86
  ) {
87
  $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
88
 
89
  if ( ! isset( self::$_instances[ $identifier ] ) ) {
90
  self::_init();
91
 
92
- self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version );
93
  }
94
 
95
  return self::$_instances[ $identifier ];
@@ -123,6 +133,7 @@
123
  * @param bool|string $secret_key Element's secret key.
124
  * @param bool $is_sandbox
125
  * @param null|string $sdk_version
 
126
  */
127
  private function __construct(
128
  $slug,
@@ -131,12 +142,14 @@
131
  $public_key,
132
  $secret_key,
133
  $is_sandbox,
134
- $sdk_version
 
135
  ) {
136
  $this->_api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
137
 
138
  $this->_slug = $slug;
139
  $this->_sdk_version = $sdk_version;
 
140
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
141
  }
142
 
@@ -198,6 +211,17 @@
198
  }
199
  }
200
 
 
 
 
 
 
 
 
 
 
 
 
201
  $result = $this->_api->Api( $path, $method, $params );
202
 
203
  if ( null !== $result &&
64
  */
65
  private $_sdk_version;
66
 
67
+ /**
68
+ * @author Leo Fajardo (@leorw)
69
+ * @since 2.5.0
70
+ *
71
+ * @var string
72
+ */
73
+ private $_url;
74
+
75
  /**
76
  * @param string $slug
77
  * @param string $scope 'app', 'developer', 'user' or 'install'.
80
  * @param bool $is_sandbox
81
  * @param bool|string $secret_key Element's secret key.
82
  * @param null|string $sdk_version
83
+ * @param null|string $url
84
  *
85
  * @return FS_Api
86
  */
91
  $public_key,
92
  $is_sandbox,
93
  $secret_key = false,
94
+ $sdk_version = null,
95
+ $url = null
96
  ) {
97
  $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
98
 
99
  if ( ! isset( self::$_instances[ $identifier ] ) ) {
100
  self::_init();
101
 
102
+ self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version, $url );
103
  }
104
 
105
  return self::$_instances[ $identifier ];
133
  * @param bool|string $secret_key Element's secret key.
134
  * @param bool $is_sandbox
135
  * @param null|string $sdk_version
136
+ * @param null|string $url
137
  */
138
  private function __construct(
139
  $slug,
142
  $public_key,
143
  $secret_key,
144
  $is_sandbox,
145
+ $sdk_version,
146
+ $url
147
  ) {
148
  $this->_api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
149
 
150
  $this->_slug = $slug;
151
  $this->_sdk_version = $sdk_version;
152
+ $this->_url = $url;
153
  $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
154
  }
155
 
211
  }
212
  }
213
 
214
+ /**
215
+ * @since 2.5.0 Include the site's URL, if available, in all API requests that are going through the API manager.
216
+ */
217
+ if ( ! empty( $this->_url ) ) {
218
+ if ( false === strpos( $path, 'url=' ) &&
219
+ ! isset( $params['url'] )
220
+ ) {
221
+ $path = add_query_arg( 'url', $this->_url, $path );
222
+ }
223
+ }
224
+
225
  $result = $this->_api->Api( $path, $method, $params );
226
 
227
  if ( null !== $result &&
freemius/includes/class-fs-lock.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Class FS_Lock
15
+ *
16
+ * @author Vova Feldman (@svovaf)
17
+ * @since 2.5.1
18
+ */
19
+ class FS_Lock {
20
+ /**
21
+ * @var int Random ID representing the current PHP thread.
22
+ */
23
+ private static $_thread_id;
24
+ /**
25
+ * @var string
26
+ */
27
+ private $_lock_id;
28
+
29
+ /**
30
+ * @param string $lock_id
31
+ */
32
+ function __construct( $lock_id ) {
33
+ if ( ! fs_starts_with( $lock_id, WP_FS___OPTION_PREFIX ) ) {
34
+ $lock_id = WP_FS___OPTION_PREFIX . $lock_id;
35
+ }
36
+
37
+ $this->_lock_id = $lock_id;
38
+
39
+ if ( ! isset( self::$_thread_id ) ) {
40
+ self::$_thread_id = mt_rand( 0, 32000 );
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything.
46
+ *
47
+ * @param int $expiration
48
+ *
49
+ * @return bool TRUE if successfully acquired lock.
50
+ */
51
+ function try_lock( $expiration = 0 ) {
52
+ if ( $this->is_locked() ) {
53
+ // Already locked.
54
+ return false;
55
+ }
56
+
57
+ set_site_transient( $this->_lock_id, self::$_thread_id, $expiration );
58
+
59
+ if ( $this->has_lock() ) {
60
+ $this->lock($expiration);
61
+
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * Acquire lock regardless if it's already acquired by another locker or not.
70
+ *
71
+ * @author Vova Feldman (@svovaf)
72
+ * @since 2.1.0
73
+ *
74
+ * @param int $expiration
75
+ */
76
+ function lock( $expiration = 0 ) {
77
+ set_site_transient( $this->_lock_id, true, $expiration );
78
+ }
79
+
80
+ /**
81
+ * Checks if lock is currently acquired.
82
+ *
83
+ * @author Vova Feldman (@svovaf)
84
+ * @since 2.1.0
85
+ *
86
+ * @return bool
87
+ */
88
+ function is_locked() {
89
+ return ( false !== get_site_transient( $this->_lock_id ) );
90
+ }
91
+
92
+ /**
93
+ * Unlock the lock.
94
+ *
95
+ * @author Vova Feldman (@svovaf)
96
+ * @since 2.1.0
97
+ */
98
+ function unlock() {
99
+ delete_site_transient( $this->_lock_id );
100
+ }
101
+
102
+ /**
103
+ * Checks if lock is currently acquired by the current locker.
104
+ *
105
+ * @return bool
106
+ */
107
+ protected function has_lock() {
108
+ return ( self::$_thread_id == get_site_transient( $this->_lock_id ) );
109
+ }
110
+ }
freemius/includes/class-fs-logger.php CHANGED
@@ -38,9 +38,10 @@
38
  private static $_HOOKED_FOOTER = false;
39
 
40
  private function __construct( $id, $on = false, $echo = false ) {
 
 
41
  $this->_id = $id;
42
 
43
- $bt = debug_backtrace();
44
  $caller = $bt[2];
45
 
46
  if ( false !== strpos( $caller['file'], 'plugins' ) ) {
38
  private static $_HOOKED_FOOTER = false;
39
 
40
  private function __construct( $id, $on = false, $echo = false ) {
41
+ $bt = debug_backtrace();
42
+
43
  $this->_id = $id;
44
 
 
45
  $caller = $bt[2];
46
 
47
  if ( false !== strpos( $caller['file'], 'plugins' ) ) {
freemius/includes/class-fs-plugin-updater.php CHANGED
@@ -240,7 +240,11 @@
240
  * @since 2.0.0
241
  */
242
  private function add_transient_filters() {
243
- if ( $this->_fs->is_premium() && ! $this->_fs->is_tracking_allowed() ) {
 
 
 
 
244
  $this->_logger->log( 'Opted out sites cannot receive automatic software updates.' );
245
 
246
  return;
@@ -610,11 +614,9 @@
610
  if ( ! isset( $this->_translation_updates ) ) {
611
  $this->_translation_updates = array();
612
 
613
- if ( current_user_can( 'update_languages' ) ) {
614
- $translation_updates = $this->fetch_wp_org_module_translation_updates( $module_type, $slug );
615
- if ( ! empty( $translation_updates ) ) {
616
- $this->_translation_updates = $translation_updates;
617
- }
618
  }
619
  }
620
 
@@ -648,7 +650,7 @@
648
  }
649
 
650
  /**
651
- * Get module's required data for the updates mechanism.
652
  *
653
  * @author Vova Feldman (@svovaf)
654
  * @since 2.0.0
240
  * @since 2.0.0
241
  */
242
  private function add_transient_filters() {
243
+ if (
244
+ $this->_fs->is_premium() &&
245
+ $this->_fs->is_registered() &&
246
+ ! FS_Permission_Manager::instance( $this->_fs )->is_essentials_tracking_allowed()
247
+ ) {
248
  $this->_logger->log( 'Opted out sites cannot receive automatic software updates.' );
249
 
250
  return;
614
  if ( ! isset( $this->_translation_updates ) ) {
615
  $this->_translation_updates = array();
616
 
617
+ $translation_updates = $this->fetch_wp_org_module_translation_updates( $module_type, $slug );
618
+ if ( ! empty( $translation_updates ) ) {
619
+ $this->_translation_updates = $translation_updates;
 
 
620
  }
621
  }
622
 
650
  }
651
 
652
  /**
653
+ * Get module's required data for the updates' mechanism.
654
  *
655
  * @author Vova Feldman (@svovaf)
656
  * @since 2.0.0
freemius/includes/class-fs-storage.php CHANGED
@@ -15,9 +15,11 @@
15
  *
16
  * A wrapper class for handling network level and single site level storage.
17
  *
18
- * @property bool $is_network_activation
19
- * @property int $network_install_blog_id
20
- * @property object $sync_cron
 
 
21
  */
22
  class FS_Storage {
23
  /**
@@ -72,6 +74,16 @@
72
  */
73
  private static $_NETWORK_OPTIONS_MAP;
74
 
 
 
 
 
 
 
 
 
 
 
75
  /**
76
  * @author Leo Fajardo (@leorw)
77
  *
@@ -142,10 +154,17 @@
142
  * @param string $key
143
  * @param mixed $value
144
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
 
145
  * @param bool $flush
146
  */
147
- function store( $key, $value, $network_level_or_blog_id = null, $flush = true ) {
148
- if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
 
 
 
 
 
 
149
  $this->_network_storage->store( $key, $value, $flush );
150
  } else {
151
  $storage = $this->get_site_storage( $network_level_or_blog_id );
@@ -199,11 +218,17 @@
199
  * @param string $key
200
  * @param mixed $default
201
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
 
202
  *
203
  * @return mixed
204
  */
205
- function get( $key, $default = false, $network_level_or_blog_id = null ) {
206
- if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
 
 
 
 
 
207
  return $this->_network_storage->get( $key, $default );
208
  } else {
209
  $storage = $this->get_site_storage( $network_level_or_blog_id );
@@ -289,19 +314,6 @@
289
  // Migrate option to the network storage.
290
  $this->_network_storage->store( $option, $this->_storage->{$option}, false );
291
 
292
- /**
293
- * Remove the option from site level storage.
294
- *
295
- * IMPORTANT:
296
- * The line below is intentionally commented since we want to preserve the option
297
- * on the site storage level for "downgrade compatibility". Basically, if the user
298
- * will downgrade to an older version of the plugin with the prev storage structure,
299
- * it will continue working.
300
- *
301
- * @todo After a few releases we can remove this.
302
- */
303
- // $this->_storage->remove($option, false);
304
-
305
  $updated = true;
306
  }
307
  }
@@ -336,63 +348,61 @@
336
  private static function load_network_options_map() {
337
  self::$_NETWORK_OPTIONS_MAP = array(
338
  // Network level options.
339
- 'affiliate_application_data' => 0,
340
- 'beta_data' => 0,
341
- 'connectivity_test' => 0,
342
- 'handle_gdpr_admin_notice' => 0,
343
- 'has_trial_plan' => 0,
344
- 'install_sync_timestamp' => 0,
345
- 'install_sync_cron' => 0,
346
- 'is_anonymous_ms' => 0,
347
- 'is_network_activated' => 0,
348
- 'is_on' => 0,
349
- 'is_plugin_new_install' => 0,
350
- 'network_install_blog_id' => 0,
351
- 'pending_sites_info' => 0,
352
- 'plugin_last_version' => 0,
353
- 'plugin_main_file' => 0,
354
- 'plugin_version' => 0,
355
- 'sdk_downgrade_mode' => 0,
356
- 'sdk_last_version' => 0,
357
- 'sdk_upgrade_mode' => 0,
358
- 'sdk_version' => 0,
359
- 'sticky_optin_added_ms' => 0,
360
- 'subscriptions' => 0,
361
- 'sync_timestamp' => 0,
362
- 'sync_cron' => 0,
363
- 'was_plugin_loaded' => 0,
364
- 'network_user_id' => 0,
365
- 'plugin_upgrade_mode' => 0,
366
- 'plugin_downgrade_mode' => 0,
367
- 'is_network_connected' => 0,
368
  /**
369
- * Special flag that is used when a super-admin upgrades to the new version of the SDK that
370
- * supports network level integration, when the connection decision wasn't made for all of the
371
- * sites in the network.
372
  */
373
- 'is_network_activation' => 0,
374
- 'license_migration' => 0,
375
 
376
  // When network activated, then network level.
377
- 'install_timestamp' => 1,
378
- 'prev_is_premium' => 1,
379
- 'require_license_activation' => 1,
380
 
381
  // If not network activated OR delegated, then site level.
382
- 'activation_timestamp' => 2,
383
- 'expired_license_notice_shown' => 2,
384
- 'is_whitelabeled' => 2,
385
- 'last_license_key' => 2,
386
- 'last_license_user_id' => 2,
387
- 'prev_user_id' => 2,
388
- 'sticky_optin_added' => 2,
389
- 'uninstall_reason' => 2,
390
- 'is_pending_activation' => 2,
391
- 'pending_license_key' => 2,
392
- 'is_extensions_tracking_allowed' => 2,
393
 
394
  // Site level options.
395
- 'is_anonymous' => 3,
 
396
  );
397
  }
398
 
@@ -403,25 +413,33 @@
403
  * @since 2.0.0
404
  *
405
  * @param string $key
 
406
  *
407
- * @return bool|mixed
408
  */
409
- private function is_multisite_option( $key ) {
410
  if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
411
  self::load_network_options_map();
412
  }
413
 
414
- if ( ! isset( self::$_NETWORK_OPTIONS_MAP[ $key ] ) ) {
 
 
 
 
 
 
 
415
  // Option not found -> use site level storage.
416
  return false;
417
  }
418
 
419
- if ( 0 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
420
  // Option found and set to always use the network level storage on a multisite.
421
  return true;
422
  }
423
 
424
- if ( 3 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
425
  // Option found and set to always use the site level storage on a multisite.
426
  return false;
427
  }
@@ -430,12 +448,15 @@
430
  return false;
431
  }
432
 
433
- if ( 1 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
434
  // Network activated.
435
  return true;
436
  }
437
 
438
- if ( 2 === self::$_NETWORK_OPTIONS_MAP[ $key ] && ! $this->_is_delegated_connection ) {
 
 
 
439
  // Network activated and not delegated.
440
  return true;
441
  }
@@ -448,10 +469,15 @@
448
  *
449
  * @param string $key
450
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
 
451
  *
452
  * @return bool
453
  */
454
- private function should_use_network_storage( $key, $network_level_or_blog_id = null ) {
 
 
 
 
455
  if ( ! $this->_is_multisite ) {
456
  // Not a multisite environment.
457
  return false;
@@ -463,12 +489,12 @@
463
  }
464
 
465
  if ( is_bool( $network_level_or_blog_id ) ) {
466
- // Explicitly specified whether should use the network or blog level storage.
467
  return $network_level_or_blog_id;
468
  }
469
 
470
  // Determine which storage to use based on the option.
471
- return $this->is_multisite_option( $key );
472
  }
473
 
474
  /**
@@ -529,4 +555,4 @@
529
  }
530
 
531
  #endregion
532
- }
15
  *
16
  * A wrapper class for handling network level and single site level storage.
17
  *
18
+ * @property bool $is_network_activation
19
+ * @property int $network_install_blog_id
20
+ * @property bool|null $is_extensions_tracking_allowed
21
+ * @property bool|null $is_diagnostic_tracking_allowed
22
+ * @property object $sync_cron
23
  */
24
  class FS_Storage {
25
  /**
74
  */
75
  private static $_NETWORK_OPTIONS_MAP;
76
 
77
+ const OPTION_LEVEL_UNDEFINED = -1;
78
+ // The option should be stored on the network level.
79
+ const OPTION_LEVEL_NETWORK = 0;
80
+ // The option should be stored on the network level when the plugin is network-activated.
81
+ const OPTION_LEVEL_NETWORK_ACTIVATED = 1;
82
+ // The option should be stored on the network level when the plugin is network-activated and the opt-in connection was NOT delegated to the sub-site admin.
83
+ const OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED = 2;
84
+ // The option should be stored on the site level.
85
+ const OPTION_LEVEL_SITE = 3;
86
+
87
  /**
88
  * @author Leo Fajardo (@leorw)
89
  *
154
  * @param string $key
155
  * @param mixed $value
156
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
157
+ * @param int $option_level Since 2.5.1
158
  * @param bool $flush
159
  */
160
+ function store(
161
+ $key,
162
+ $value,
163
+ $network_level_or_blog_id = null,
164
+ $option_level = self::OPTION_LEVEL_UNDEFINED,
165
+ $flush = true
166
+ ) {
167
+ if ( $this->should_use_network_storage( $key, $network_level_or_blog_id, $option_level ) ) {
168
  $this->_network_storage->store( $key, $value, $flush );
169
  } else {
170
  $storage = $this->get_site_storage( $network_level_or_blog_id );
218
  * @param string $key
219
  * @param mixed $default
220
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
221
+ * @param int $option_level Since 2.5.1
222
  *
223
  * @return mixed
224
  */
225
+ function get(
226
+ $key,
227
+ $default = false,
228
+ $network_level_or_blog_id = null,
229
+ $option_level = self::OPTION_LEVEL_UNDEFINED
230
+ ) {
231
+ if ( $this->should_use_network_storage( $key, $network_level_or_blog_id, $option_level ) ) {
232
  return $this->_network_storage->get( $key, $default );
233
  } else {
234
  $storage = $this->get_site_storage( $network_level_or_blog_id );
314
  // Migrate option to the network storage.
315
  $this->_network_storage->store( $option, $this->_storage->{$option}, false );
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  $updated = true;
318
  }
319
  }
348
  private static function load_network_options_map() {
349
  self::$_NETWORK_OPTIONS_MAP = array(
350
  // Network level options.
351
+ 'affiliate_application_data' => self::OPTION_LEVEL_NETWORK,
352
+ 'beta_data' => self::OPTION_LEVEL_NETWORK,
353
+ 'connectivity_test' => self::OPTION_LEVEL_NETWORK,
354
+ 'handle_gdpr_admin_notice' => self::OPTION_LEVEL_NETWORK,
355
+ 'has_trial_plan' => self::OPTION_LEVEL_NETWORK,
356
+ 'install_sync_timestamp' => self::OPTION_LEVEL_NETWORK,
357
+ 'install_sync_cron' => self::OPTION_LEVEL_NETWORK,
358
+ 'is_anonymous_ms' => self::OPTION_LEVEL_NETWORK,
359
+ 'is_network_activated' => self::OPTION_LEVEL_NETWORK,
360
+ 'is_on' => self::OPTION_LEVEL_NETWORK,
361
+ 'is_plugin_new_install' => self::OPTION_LEVEL_NETWORK,
362
+ 'network_install_blog_id' => self::OPTION_LEVEL_NETWORK,
363
+ 'pending_sites_info' => self::OPTION_LEVEL_NETWORK,
364
+ 'plugin_last_version' => self::OPTION_LEVEL_NETWORK,
365
+ 'plugin_main_file' => self::OPTION_LEVEL_NETWORK,
366
+ 'plugin_version' => self::OPTION_LEVEL_NETWORK,
367
+ 'sdk_downgrade_mode' => self::OPTION_LEVEL_NETWORK,
368
+ 'sdk_last_version' => self::OPTION_LEVEL_NETWORK,
369
+ 'sdk_upgrade_mode' => self::OPTION_LEVEL_NETWORK,
370
+ 'sdk_version' => self::OPTION_LEVEL_NETWORK,
371
+ 'sticky_optin_added_ms' => self::OPTION_LEVEL_NETWORK,
372
+ 'subscriptions' => self::OPTION_LEVEL_NETWORK,
373
+ 'sync_timestamp' => self::OPTION_LEVEL_NETWORK,
374
+ 'sync_cron' => self::OPTION_LEVEL_NETWORK,
375
+ 'was_plugin_loaded' => self::OPTION_LEVEL_NETWORK,
376
+ 'network_user_id' => self::OPTION_LEVEL_NETWORK,
377
+ 'plugin_upgrade_mode' => self::OPTION_LEVEL_NETWORK,
378
+ 'plugin_downgrade_mode' => self::OPTION_LEVEL_NETWORK,
379
+ 'is_network_connected' => self::OPTION_LEVEL_NETWORK,
380
  /**
381
+ * Special flag that is used when a super-admin upgrades to the new version of the SDK that supports network level integration, when the connection decision wasn't made for all the sites in the network.
 
 
382
  */
383
+ 'is_network_activation' => self::OPTION_LEVEL_NETWORK,
384
+ 'license_migration' => self::OPTION_LEVEL_NETWORK,
385
 
386
  // When network activated, then network level.
387
+ 'install_timestamp' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
388
+ 'prev_is_premium' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
389
+ 'require_license_activation' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
390
 
391
  // If not network activated OR delegated, then site level.
392
+ 'activation_timestamp' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
393
+ 'expired_license_notice_shown' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
394
+ 'is_whitelabeled' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
395
+ 'last_license_key' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
396
+ 'last_license_user_id' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
397
+ 'prev_user_id' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
398
+ 'sticky_optin_added' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
399
+ 'uninstall_reason' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
400
+ 'is_pending_activation' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
401
+ 'pending_license_key' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
 
402
 
403
  // Site level options.
404
+ 'is_anonymous' => self::OPTION_LEVEL_SITE,
405
+ 'clone_id' => self::OPTION_LEVEL_SITE,
406
  );
407
  }
408
 
413
  * @since 2.0.0
414
  *
415
  * @param string $key
416
+ * @param int $option_level Since 2.5.1
417
  *
418
+ * @return bool
419
  */
420
+ private function is_multisite_option( $key, $option_level = self::OPTION_LEVEL_UNDEFINED ) {
421
  if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
422
  self::load_network_options_map();
423
  }
424
 
425
+ if (
426
+ self::OPTION_LEVEL_UNDEFINED === $option_level &&
427
+ isset( self::$_NETWORK_OPTIONS_MAP[ $key ] )
428
+ ) {
429
+ $option_level = self::$_NETWORK_OPTIONS_MAP[ $key ];
430
+ }
431
+
432
+ if ( self::OPTION_LEVEL_UNDEFINED === $option_level ) {
433
  // Option not found -> use site level storage.
434
  return false;
435
  }
436
 
437
+ if ( self::OPTION_LEVEL_NETWORK === $option_level ) {
438
  // Option found and set to always use the network level storage on a multisite.
439
  return true;
440
  }
441
 
442
+ if ( self::OPTION_LEVEL_SITE === $option_level ) {
443
  // Option found and set to always use the site level storage on a multisite.
444
  return false;
445
  }
448
  return false;
449
  }
450
 
451
+ if ( self::OPTION_LEVEL_NETWORK_ACTIVATED === $option_level ) {
452
  // Network activated.
453
  return true;
454
  }
455
 
456
+ if (
457
+ self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED === $option_level &&
458
+ ! $this->_is_delegated_connection
459
+ ) {
460
  // Network activated and not delegated.
461
  return true;
462
  }
469
  *
470
  * @param string $key
471
  * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
472
+ * @param int $option_level Since 2.5.1
473
  *
474
  * @return bool
475
  */
476
+ private function should_use_network_storage(
477
+ $key,
478
+ $network_level_or_blog_id = null,
479
+ $option_level = self::OPTION_LEVEL_UNDEFINED
480
+ ) {
481
  if ( ! $this->_is_multisite ) {
482
  // Not a multisite environment.
483
  return false;
489
  }
490
 
491
  if ( is_bool( $network_level_or_blog_id ) ) {
492
+ // Explicitly specified whether it should use the network or blog level storage.
493
  return $network_level_or_blog_id;
494
  }
495
 
496
  // Determine which storage to use based on the option.
497
+ return $this->is_multisite_option( $key, $option_level );
498
  }
499
 
500
  /**
555
  }
556
 
557
  #endregion
558
+ }
freemius/includes/class-fs-user-lock.php CHANGED
@@ -10,18 +10,16 @@
10
  exit;
11
  }
12
 
 
 
13
  /**
14
  * Class FS_User_Lock
15
  */
16
  class FS_User_Lock {
17
  /**
18
- * @var int
19
- */
20
- private $_wp_user_id;
21
- /**
22
- * @var int
23
  */
24
- private $_thread_id;
25
 
26
  #--------------------------------------------------------------------------------
27
  #region Singleton
@@ -49,10 +47,10 @@
49
  #endregion
50
 
51
  private function __construct() {
52
- $this->_wp_user_id = Freemius::get_current_wp_user_id();
53
- $this->_thread_id = mt_rand( 0, 32000 );
54
- }
55
 
 
 
56
 
57
  /**
58
  * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything.
@@ -65,20 +63,7 @@
65
  * @return bool TRUE if successfully acquired lock.
66
  */
67
  function try_lock( $expiration = 0 ) {
68
- if ( $this->is_locked() ) {
69
- // Already locked.
70
- return false;
71
- }
72
-
73
- set_site_transient( "locked_{$this->_wp_user_id}", $this->_thread_id, $expiration );
74
-
75
- if ( $this->has_lock() ) {
76
- set_site_transient( "locked_{$this->_wp_user_id}", true, $expiration );
77
-
78
- return true;
79
- }
80
-
81
- return false;
82
  }
83
 
84
  /**
@@ -90,19 +75,7 @@
90
  * @param int $expiration
91
  */
92
  function lock( $expiration = 0 ) {
93
- set_site_transient( "locked_{$this->_wp_user_id}", true, $expiration );
94
- }
95
-
96
- /**
97
- * Checks if lock is currently acquired.
98
- *
99
- * @author Vova Feldman (@svovaf)
100
- * @since 2.1.0
101
- *
102
- * @return bool
103
- */
104
- function is_locked() {
105
- return ( false !== get_site_transient( "locked_{$this->_wp_user_id}" ) );
106
  }
107
 
108
  /**
@@ -112,15 +85,6 @@
112
  * @since 2.1.0
113
  */
114
  function unlock() {
115
- delete_site_transient( "locked_{$this->_wp_user_id}" );
116
- }
117
-
118
- /**
119
- * Checks if lock is currently acquired by the current locker.
120
- *
121
- * @return bool
122
- */
123
- private function has_lock() {
124
- return ( $this->_thread_id == get_site_transient( "locked_{$this->_wp_user_id}" ) );
125
  }
126
  }
10
  exit;
11
  }
12
 
13
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-lock.php';
14
+
15
  /**
16
  * Class FS_User_Lock
17
  */
18
  class FS_User_Lock {
19
  /**
20
+ * @var FS_Lock
 
 
 
 
21
  */
22
+ private $_lock;
23
 
24
  #--------------------------------------------------------------------------------
25
  #region Singleton
47
  #endregion
48
 
49
  private function __construct() {
50
+ $current_user_id = Freemius::get_current_wp_user_id();
 
 
51
 
52
+ $this->_lock = new FS_Lock( "locked_{$current_user_id}" );
53
+ }
54
 
55
  /**
56
  * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything.
63
  * @return bool TRUE if successfully acquired lock.
64
  */
65
  function try_lock( $expiration = 0 ) {
66
+ return $this->_lock->try_lock( $expiration );
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  /**
75
  * @param int $expiration
76
  */
77
  function lock( $expiration = 0 ) {
78
+ $this->_lock->lock( $expiration );
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
  /**
85
  * @since 2.1.0
86
  */
87
  function unlock() {
88
+ $this->_lock->unlock();
 
 
 
 
 
 
 
 
 
89
  }
90
  }
freemius/includes/customizer/class-fs-customizer-upsell-control.php CHANGED
@@ -101,11 +101,11 @@
101
  }
102
  }
103
  }
 
 
104
  }
105
  }
106
 
107
- $this->json['plans'] = $pricing->plans;
108
-
109
  $this->json['strings'] = array(
110
  'plan' => $this->fs->get_text_x_inline( 'Plan', 'as product pricing plan', 'plan' ),
111
  );
101
  }
102
  }
103
  }
104
+
105
+ $this->json['plans'] = $pricing->plans;
106
  }
107
  }
108
 
 
 
109
  $this->json['strings'] = array(
110
  'plan' => $this->fs->get_text_x_inline( 'Plan', 'as product pricing plan', 'plan' ),
111
  );
freemius/includes/entities/class-fs-affiliate-terms.php CHANGED
@@ -84,6 +84,10 @@
84
  * @var bool If `true`, allow referrals from any site.
85
  */
86
  public $is_any_site_allowed;
 
 
 
 
87
 
88
  #endregion Properties
89
 
84
  * @var bool If `true`, allow referrals from any site.
85
  */
86
  public $is_any_site_allowed;
87
+ /**
88
+ * @var string $plugin_title Title of the plugin. This is used in case we are showing affiliate form for a Bundle instead of the `plugin` in context.
89
+ */
90
+ public $plugin_title;
91
 
92
  #endregion Properties
93
 
freemius/includes/entities/class-fs-site.php CHANGED
@@ -10,6 +10,9 @@
10
  exit;
11
  }
12
 
 
 
 
13
  class FS_Site extends FS_Scope_Entity {
14
  /**
15
  * @var number
@@ -39,10 +42,6 @@
39
  * @var string E.g. en-GB
40
  */
41
  public $language;
42
- /**
43
- * @var string E.g. UTF-8
44
- */
45
- public $charset;
46
  /**
47
  * @var string Platform version (e.g WordPress version).
48
  */
@@ -86,6 +85,8 @@
86
  * @author Leo Fajardo (@leorw)
87
  *
88
  * @since 1.2.1.5
 
 
89
  *
90
  * @var bool
91
  */
@@ -190,7 +191,13 @@
190
  // DesktopServer
191
  fs_ends_with( $subdomain, '.dev.cc' ) ||
192
  // Pressable
193
- fs_ends_with( $subdomain, '.mystagingwebsite.com' )
 
 
 
 
 
 
194
  );
195
  }
196
 
@@ -223,31 +230,25 @@
223
  }
224
 
225
  /**
226
- * @author Vova Feldman (@svovaf)
227
- * @since 2.0.0
228
  *
229
  * @return bool
230
  */
231
- function is_tracking_allowed() {
232
- return ( true !== $this->is_disconnected );
233
  }
234
 
235
  /**
236
- * @author Vova Feldman (@svovaf)
237
- * @since 2.0.0
238
  *
239
- * @return bool
240
- */
241
- function is_tracking_prohibited() {
242
- return ! $this->is_tracking_allowed();
243
- }
244
-
245
- /**
246
- * @author Edgar Melkonyan
247
  *
248
  * @return bool
249
  */
250
- function is_beta() {
251
- return ( isset( $this->is_beta ) && true === $this->is_beta );
 
 
252
  }
253
  }
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @property int $blog_id
15
+ */
16
  class FS_Site extends FS_Scope_Entity {
17
  /**
18
  * @var number
42
  * @var string E.g. en-GB
43
  */
44
  public $language;
 
 
 
 
45
  /**
46
  * @var string Platform version (e.g WordPress version).
47
  */
85
  * @author Leo Fajardo (@leorw)
86
  *
87
  * @since 1.2.1.5
88
+ * @deprecated Since 2.5.1
89
+ * @todo Remove after a few releases.
90
  *
91
  * @var bool
92
  */
191
  // DesktopServer
192
  fs_ends_with( $subdomain, '.dev.cc' ) ||
193
  // Pressable
194
+ fs_ends_with( $subdomain, '.mystagingwebsite.com' ) ||
195
+ // WPMU DEV
196
+ ( fs_ends_with( $subdomain, '.tempurl.host' ) || fs_ends_with( $subdomain, '.wpmudev.host' ) ) ||
197
+ // Vendasta
198
+ ( fs_ends_with( $subdomain, '.websitepro-staging.com' ) || fs_ends_with( $subdomain, '.websitepro.hosting' ) ) ||
199
+ // InstaWP
200
+ fs_ends_with( $subdomain, '.instawp.xyz' )
201
  );
202
  }
203
 
230
  }
231
 
232
  /**
233
+ * @author Edgar Melkonyan
 
234
  *
235
  * @return bool
236
  */
237
+ function is_beta() {
238
+ return ( isset( $this->is_beta ) && true === $this->is_beta );
239
  }
240
 
241
  /**
242
+ * @author Leo Fajardo (@leorw)
243
+ * @since 2.5.1
244
  *
245
+ * @param string $site_url
 
 
 
 
 
 
 
246
  *
247
  * @return bool
248
  */
249
+ function is_clone( $site_url ) {
250
+ $clone_install_url = trailingslashit( fs_strip_url_protocol( $this->url ) );
251
+
252
+ return ( $clone_install_url !== $site_url );
253
  }
254
  }
freemius/includes/entities/class-fs-user.php CHANGED
@@ -56,7 +56,18 @@
56
  return ( isset( $this->is_verified ) && true === $this->is_verified );
57
  }
58
 
59
- static function get_type() {
 
 
 
 
 
 
 
 
 
 
 
60
  return 'user';
61
  }
62
  }
56
  return ( isset( $this->is_verified ) && true === $this->is_verified );
57
  }
58
 
59
+ /**
60
+ * @author Leo Fajardo (@leorw)
61
+ * @since 2.4.2
62
+ *
63
+ * @return bool
64
+ */
65
+ function is_beta() {
66
+ // Return `false` since this is just for backward compatibility.
67
+ return false;
68
+ }
69
+
70
+ static function get_type() {
71
  return 'user';
72
  }
73
  }
freemius/includes/fs-core-functions.php CHANGED
@@ -756,7 +756,7 @@
756
  } // If b has a priority and a does not, b wins.
757
  elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
758
  return - 1;
759
- } // If neither has a priority or both priorities are equal its a tie.
760
  elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
761
  return 0;
762
  }
@@ -770,6 +770,12 @@
770
  #region Localization
771
  #--------------------------------------------------------------------------------
772
 
 
 
 
 
 
 
773
  if ( ! function_exists( 'fs_text' ) ) {
774
  /**
775
  * Retrieve a translated text by key.
@@ -782,12 +788,10 @@
782
  *
783
  * @return string
784
  *
785
- * @global $fs_text , $fs_text_overrides
786
  */
787
  function fs_text( $key, $slug = 'freemius' ) {
788
- global $fs_text,
789
- $fs_module_info_text,
790
- $fs_text_overrides;
791
 
792
  if ( isset( $fs_text_overrides[ $slug ] ) ) {
793
  if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
@@ -800,22 +804,6 @@
800
  }
801
  }
802
 
803
- if ( ! isset( $fs_text ) ) {
804
- $dir = defined( 'WP_FS__DIR_INCLUDES' ) ?
805
- WP_FS__DIR_INCLUDES :
806
- dirname( __FILE__ );
807
-
808
- require_once $dir . '/i18n.php';
809
- }
810
-
811
- if ( isset( $fs_text[ $key ] ) ) {
812
- return $fs_text[ $key ];
813
- }
814
-
815
- if ( isset( $fs_module_info_text[ $key ] ) ) {
816
- return $fs_module_info_text[ $key ];
817
- }
818
-
819
  return $key;
820
  }
821
 
@@ -1349,7 +1337,7 @@
1349
  function fs_is_plugin_uninstall() {
1350
  return (
1351
  defined( 'WP_UNINSTALL_PLUGIN' ) ||
1352
- ( 0 < did_action( 'update_option_uninstall_plugins' ) )
1353
  );
1354
  }
1355
  }
756
  } // If b has a priority and a does not, b wins.
757
  elseif ( isset( $a['priority'] ) && ! isset( $b['priority'] ) ) {
758
  return - 1;
759
+ } // If neither has a priority or both priorities are equal it's a tie.
760
  elseif ( ( ! isset( $a['priority'] ) && ! isset( $b['priority'] ) ) || $a['priority'] === $b['priority'] ) {
761
  return 0;
762
  }
770
  #region Localization
771
  #--------------------------------------------------------------------------------
772
 
773
+ global $fs_text_overrides;
774
+
775
+ if ( ! isset( $fs_text_overrides ) ) {
776
+ $fs_text_overrides = array();
777
+ }
778
+
779
  if ( ! function_exists( 'fs_text' ) ) {
780
  /**
781
  * Retrieve a translated text by key.
788
  *
789
  * @return string
790
  *
791
+ * @global $fs_text_overrides
792
  */
793
  function fs_text( $key, $slug = 'freemius' ) {
794
+ global $fs_text_overrides;
 
 
795
 
796
  if ( isset( $fs_text_overrides[ $slug ] ) ) {
797
  if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
804
  }
805
  }
806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
807
  return $key;
808
  }
809
 
1337
  function fs_is_plugin_uninstall() {
1338
  return (
1339
  defined( 'WP_UNINSTALL_PLUGIN' ) ||
1340
+ ( 0 < did_action( 'pre_uninstall_plugin' ) )
1341
  );
1342
  }
1343
  }
freemius/includes/fs-essential-functions.php CHANGED
@@ -149,111 +149,21 @@
149
 
150
  #endregion Core Redirect (copied from BuddyPress) -----------------------------------------
151
 
152
- if ( ! function_exists( '__fs' ) ) {
153
- global $fs_text_overrides;
154
-
155
- if ( ! isset( $fs_text_overrides ) ) {
156
- $fs_text_overrides = array();
157
- }
158
-
159
- /**
160
- * Retrieve a translated text by key.
161
- *
162
- * @deprecated Use `fs_text()` instead since methods starting with `__` trigger warnings in Php 7.
163
- * @todo Remove this method in the future.
164
- *
165
- * @author Vova Feldman (@svovaf)
166
- * @since 1.1.4
167
- *
168
- * @param string $key
169
- * @param string $slug
170
- *
171
- * @return string
172
- *
173
- * @global $fs_text, $fs_text_overrides
174
- */
175
- function __fs( $key, $slug = 'freemius' ) {
176
- _deprecated_function( __FUNCTION__, '2.0.0', 'fs_text()' );
177
-
178
- global $fs_text,
179
- $fs_module_info_text,
180
- $fs_text_overrides;
181
-
182
- if ( isset( $fs_text_overrides[ $slug ] ) ) {
183
- if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
184
- return $fs_text_overrides[ $slug ][ $key ];
185
- }
186
-
187
- $lower_key = strtolower( $key );
188
- if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
189
- return $fs_text_overrides[ $slug ][ $lower_key ];
190
- }
191
- }
192
-
193
- if ( ! isset( $fs_text ) ) {
194
- $dir = defined( 'WP_FS__DIR_INCLUDES' ) ?
195
- WP_FS__DIR_INCLUDES :
196
- dirname( __FILE__ );
197
-
198
- require_once $dir . '/i18n.php';
199
- }
200
-
201
- if ( isset( $fs_text[ $key ] ) ) {
202
- return $fs_text[ $key ];
203
- }
204
-
205
- if ( isset( $fs_module_info_text[ $key ] ) ) {
206
- return $fs_module_info_text[ $key ];
207
- }
208
-
209
- return $key;
210
- }
211
-
212
- /**
213
- * Output a translated text by key.
214
- *
215
- * @deprecated Use `fs_echo()` instead for consistency with `fs_text()`.
216
- *
217
- * @todo Remove this method in the future.
218
- *
219
- * @author Vova Feldman (@svovaf)
220
- * @since 1.1.4
221
- *
222
- * @param string $key
223
- * @param string $slug
224
- */
225
- function _efs( $key, $slug = 'freemius' ) {
226
- fs_echo( $key, $slug );
227
- }
228
- }
229
-
230
  if ( ! function_exists( 'fs_get_ip' ) ) {
231
  /**
232
- * Get client IP.
233
- *
 
 
234
  * @author Vova Feldman (@svovaf)
235
  * @since 1.1.2
236
  *
237
  * @return string|null
238
  */
239
  function fs_get_ip() {
240
- $fields = array(
241
- 'HTTP_CF_CONNECTING_IP',
242
- 'HTTP_CLIENT_IP',
243
- 'HTTP_X_FORWARDED_FOR',
244
- 'HTTP_X_FORWARDED',
245
- 'HTTP_FORWARDED_FOR',
246
- 'HTTP_FORWARDED',
247
- 'REMOTE_ADDR',
248
- );
249
-
250
- foreach ( $fields as $ip_field ) {
251
- if ( ! empty( $_SERVER[ $ip_field ] ) ) {
252
- return $_SERVER[ $ip_field ];
253
- }
254
- }
255
-
256
- return null;
257
  }
258
  }
259
 
149
 
150
  #endregion Core Redirect (copied from BuddyPress) -----------------------------------------
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  if ( ! function_exists( 'fs_get_ip' ) ) {
153
  /**
154
+ * Get server IP.
155
+ *
156
+ * @since 2.5.1 This method returns the server IP.
157
+ *
158
  * @author Vova Feldman (@svovaf)
159
  * @since 1.1.2
160
  *
161
  * @return string|null
162
  */
163
  function fs_get_ip() {
164
+ return empty( $_SERVER[ 'SERVER_ADDR' ] ) ?
165
+ null :
166
+ $_SERVER[ 'SERVER_ADDR' ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
  }
169
 
freemius/includes/fs-plugin-info-dialog.php CHANGED
@@ -1306,8 +1306,8 @@
1306
  <?php endif ?>
1307
  </div>
1308
  </div>
1309
- </div>
1310
  <?php endforeach ?>
 
1311
  <?php endif ?>
1312
  <?php endif ?>
1313
  <div>
1306
  <?php endif ?>
1307
  </div>
1308
  </div>
 
1309
  <?php endforeach ?>
1310
+ </div>
1311
  <?php endif ?>
1312
  <?php endif ?>
1313
  <div>
freemius/includes/managers/class-fs-admin-notice-manager.php CHANGED
@@ -160,7 +160,10 @@
160
  false,
161
  isset( $msg['wp_user_id'] ) ? $msg['wp_user_id'] : null,
162
  ! empty( $msg['plugin'] ) ? $msg['plugin'] : null,
163
- $is_network_and_blog_admins
 
 
 
164
  );
165
  }
166
  }
@@ -224,9 +227,6 @@
224
  return;
225
  }
226
 
227
-
228
- $show_admin_notices = ( ! $this->is_gutenberg_page() );
229
-
230
  foreach ( $this->_notices as $id => $msg ) {
231
  if ( isset( $msg['wp_user_id'] ) && is_numeric( $msg['wp_user_id'] ) ) {
232
  if ( get_current_user_id() != $msg['wp_user_id'] ) {
@@ -269,7 +269,7 @@
269
  $show_notice = call_user_func_array( 'fs_apply_filter', array(
270
  $this->_module_unique_affix,
271
  'show_admin_notice',
272
- $show_admin_notices,
273
  $msg
274
  ) );
275
 
@@ -323,6 +323,30 @@
323
  return false;
324
  }
325
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  /**
327
  * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
328
  *
@@ -339,6 +363,8 @@
339
  * @param string|null $plugin_title
340
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
341
  * and blog admin pages.
 
 
342
  *
343
  * @uses add_action()
344
  */
@@ -351,7 +377,9 @@
351
  $store_if_sticky = true,
352
  $wp_user_id = null,
353
  $plugin_title = null,
354
- $is_network_and_blog_admins = false
 
 
355
  ) {
356
  $notices_type = $this->get_notices_type();
357
 
@@ -371,14 +399,16 @@
371
  }
372
 
373
  $message_object = array(
374
- 'message' => $message,
375
- 'title' => $title,
376
- 'type' => $type,
377
- 'sticky' => $is_sticky,
378
- 'id' => $id,
379
- 'manager_id' => $this->_id,
380
- 'plugin' => ( ! is_null( $plugin_title ) ? $plugin_title : $this->_title ),
381
- 'wp_user_id' => $wp_user_id,
 
 
382
  );
383
 
384
  if ( $is_sticky && $store_if_sticky ) {
@@ -393,15 +423,16 @@
393
  * @since 1.0.7
394
  *
395
  * @param string|string[] $ids
 
396
  */
397
- function remove_sticky( $ids ) {
398
  if ( ! is_array( $ids ) ) {
399
  $ids = array( $ids );
400
  }
401
 
402
  foreach ( $ids as $id ) {
403
  // Remove from sticky storage.
404
- $this->_sticky_storage->remove( $id );
405
 
406
  if ( isset( $this->_notices[ $id ] ) ) {
407
  unset( $this->_notices[ $id ] );
@@ -437,14 +468,32 @@
437
  * @param string|null $plugin_title
438
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
439
  * and blog admin pages.
 
 
440
  */
441
- function add_sticky( $message, $id, $title = '', $type = 'success', $wp_user_id = null, $plugin_title = null, $is_network_and_blog_admins = false ) {
442
  if ( ! empty( $this->_module_unique_affix ) ) {
443
  $message = fs_apply_filter( $this->_module_unique_affix, "sticky_message_{$id}", $message );
444
  $title = fs_apply_filter( $this->_module_unique_affix, "sticky_title_{$id}", $title );
445
  }
446
 
447
- $this->add( $message, $title, $type, true, $id, true, $wp_user_id, $plugin_title, $is_network_and_blog_admins );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  }
449
 
450
  /**
@@ -452,9 +501,15 @@
452
  *
453
  * @author Vova Feldman (@svovaf)
454
  * @since 1.0.8
 
 
455
  */
456
- function clear_all_sticky() {
457
- $this->_sticky_storage->clear_all();
 
 
 
 
458
  }
459
 
460
  #--------------------------------------------------------------------------------
160
  false,
161
  isset( $msg['wp_user_id'] ) ? $msg['wp_user_id'] : null,
162
  ! empty( $msg['plugin'] ) ? $msg['plugin'] : null,
163
+ $is_network_and_blog_admins,
164
+ isset( $msg['dismissible'] ) ?
165
+ $msg['dismissible'] :
166
+ null
167
  );
168
  }
169
  }
227
  return;
228
  }
229
 
 
 
 
230
  foreach ( $this->_notices as $id => $msg ) {
231
  if ( isset( $msg['wp_user_id'] ) && is_numeric( $msg['wp_user_id'] ) ) {
232
  if ( get_current_user_id() != $msg['wp_user_id'] ) {
269
  $show_notice = call_user_func_array( 'fs_apply_filter', array(
270
  $this->_module_unique_affix,
271
  'show_admin_notice',
272
+ $this->show_admin_notices(),
273
  $msg
274
  ) );
275
 
323
  return false;
324
  }
325
 
326
+ /**
327
+ * Check if admin notices should be shown on page. E.g., we don't want to show notices in the Visual Editor.
328
+ *
329
+ * @author Xiaheng Chen (@xhchen)
330
+ * @since 2.4.2
331
+ *
332
+ * @return bool
333
+ */
334
+ function show_admin_notices() {
335
+ global $pagenow;
336
+
337
+ if ( 'about.php' === $pagenow ) {
338
+ // Don't show admin notices on the About page.
339
+ return false;
340
+ }
341
+
342
+ if ( $this->is_gutenberg_page() ) {
343
+ // Don't show admin notices in Gutenberg (visual editor).
344
+ return false;
345
+ }
346
+
347
+ return true;
348
+ }
349
+
350
  /**
351
  * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
352
  *
363
  * @param string|null $plugin_title
364
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
365
  * and blog admin pages.
366
+ * @param bool|null $is_dismissible
367
+ * @param array $data
368
  *
369
  * @uses add_action()
370
  */
377
  $store_if_sticky = true,
378
  $wp_user_id = null,
379
  $plugin_title = null,
380
+ $is_network_and_blog_admins = false,
381
+ $is_dismissible = null,
382
+ $data = array()
383
  ) {
384
  $notices_type = $this->get_notices_type();
385
 
399
  }
400
 
401
  $message_object = array(
402
+ 'message' => $message,
403
+ 'title' => $title,
404
+ 'type' => $type,
405
+ 'sticky' => $is_sticky,
406
+ 'id' => $id,
407
+ 'manager_id' => $this->_id,
408
+ 'plugin' => ( ! is_null( $plugin_title ) ? $plugin_title : $this->_title ),
409
+ 'wp_user_id' => $wp_user_id,
410
+ 'dismissible' => $is_dismissible,
411
+ 'data' => $data
412
  );
413
 
414
  if ( $is_sticky && $store_if_sticky ) {
423
  * @since 1.0.7
424
  *
425
  * @param string|string[] $ids
426
+ * @param bool $store
427
  */
428
+ function remove_sticky( $ids, $store = true ) {
429
  if ( ! is_array( $ids ) ) {
430
  $ids = array( $ids );
431
  }
432
 
433
  foreach ( $ids as $id ) {
434
  // Remove from sticky storage.
435
+ $this->_sticky_storage->remove( $id, $store );
436
 
437
  if ( isset( $this->_notices[ $id ] ) ) {
438
  unset( $this->_notices[ $id ] );
468
  * @param string|null $plugin_title
469
  * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
470
  * and blog admin pages.
471
+ * @param bool $is_dimissible
472
+ * @param array $data
473
  */
474
+ function add_sticky( $message, $id, $title = '', $type = 'success', $wp_user_id = null, $plugin_title = null, $is_network_and_blog_admins = false, $is_dimissible = true, $data = array() ) {
475
  if ( ! empty( $this->_module_unique_affix ) ) {
476
  $message = fs_apply_filter( $this->_module_unique_affix, "sticky_message_{$id}", $message );
477
  $title = fs_apply_filter( $this->_module_unique_affix, "sticky_title_{$id}", $title );
478
  }
479
 
480
+ $this->add( $message, $title, $type, true, $id, true, $wp_user_id, $plugin_title, $is_network_and_blog_admins, $is_dimissible, $data );
481
+ }
482
+
483
+ /**
484
+ * Retrieves the data of an sticky notice.
485
+ *
486
+ * @author Leo Fajardo (@leorw)
487
+ * @since 2.4.3
488
+ *
489
+ * @param string $id Message ID.
490
+ *
491
+ * @return array|null
492
+ */
493
+ function get_sticky( $id ) {
494
+ return isset( $this->_sticky_storage->{$id} ) ?
495
+ $this->_sticky_storage->{$id} :
496
+ null;
497
  }
498
 
499
  /**
501
  *
502
  * @author Vova Feldman (@svovaf)
503
  * @since 1.0.8
504
+ *
505
+ * @param bool $is_temporary @since 2.5.1
506
  */
507
+ function clear_all_sticky( $is_temporary = false ) {
508
+ if ( $is_temporary ) {
509
+ $this->_notices = array();
510
+ } else {
511
+ $this->_sticky_storage->clear_all();
512
+ }
513
  }
514
 
515
  #--------------------------------------------------------------------------------
freemius/includes/managers/class-fs-clone-manager.php ADDED
@@ -0,0 +1,1660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @author Leo Fajardo (@leorw)
7
+ * @since 2.5.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ /**
15
+ * Manages the detection of clones and provides the logged-in WordPress user with options for manually resolving them.
16
+ *
17
+ * @since 2.5.0
18
+ *
19
+ * @property int $clone_identification_timestamp
20
+ * @property int $temporary_duplicate_mode_selection_timestamp
21
+ * @property int $temporary_duplicate_notice_shown_timestamp
22
+ * @property string $request_handler_id
23
+ * @property int $request_handler_timestamp
24
+ * @property int $request_handler_retries_count
25
+ * @property bool $hide_manual_resolution
26
+ * @property array $new_blog_install_map
27
+ */
28
+ class FS_Clone_Manager {
29
+ /**
30
+ * @var FS_Option_Manager
31
+ */
32
+ private $_storage;
33
+ /**
34
+ * @var FS_Option_Manager
35
+ */
36
+ private $_network_storage;
37
+ /**
38
+ * @var FS_Admin_Notices
39
+ */
40
+ private $_notices;
41
+ /**
42
+ * @var FS_Logger
43
+ */
44
+ protected $_logger;
45
+
46
+ /**
47
+ * @var int 3 minutes
48
+ */
49
+ const CLONE_RESOLUTION_MAX_EXECUTION_TIME = 180;
50
+ /**
51
+ * @var int
52
+ */
53
+ const CLONE_RESOLUTION_MAX_RETRIES = 3;
54
+ /**
55
+ * @var int
56
+ */
57
+ const TEMPORARY_DUPLICATE_PERIOD = WP_FS__TIME_WEEK_IN_SEC * 2;
58
+ /**
59
+ * @var string
60
+ */
61
+ const OPTION_NAME = 'clone_resolution';
62
+ /**
63
+ * @var string
64
+ */
65
+ const OPTION_MANAGER_NAME = 'clone_management';
66
+ /**
67
+ * @var string
68
+ */
69
+ const OPTION_TEMPORARY_DUPLICATE = 'temporary_duplicate';
70
+ /**
71
+ * @var string
72
+ */
73
+ const OPTION_LONG_TERM_DUPLICATE = 'long_term_duplicate';
74
+ /**
75
+ * @var string
76
+ */
77
+ const OPTION_NEW_HOME = 'new_home';
78
+
79
+ #--------------------------------------------------------------------------------
80
+ #region Singleton
81
+ #--------------------------------------------------------------------------------
82
+
83
+ /**
84
+ * @var FS_Clone_Manager
85
+ */
86
+ private static $_instance;
87
+
88
+ /**
89
+ * @return FS_Clone_Manager
90
+ */
91
+ static function instance() {
92
+ if ( ! isset( self::$_instance ) ) {
93
+ self::$_instance = new self();
94
+ }
95
+
96
+ return self::$_instance;
97
+ }
98
+
99
+ #endregion
100
+
101
+ private function __construct() {
102
+ $this->_storage = FS_Option_Manager::get_manager( WP_FS___OPTION_PREFIX . self::OPTION_MANAGER_NAME, true );
103
+ $this->_network_storage = FS_Option_Manager::get_manager( WP_FS___OPTION_PREFIX . self::OPTION_MANAGER_NAME, true, true );
104
+
105
+ $this->maybe_migrate_options();
106
+
107
+ $this->_notices = FS_Admin_Notices::instance( 'global_clone_resolution_notices', '', '', true );
108
+ $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . '_clone_manager', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
109
+ }
110
+
111
+ /**
112
+ * Migrate clone resolution options from 2.5.0 array-based structure, to a new flat structure.
113
+ *
114
+ * The reason this logic is not in a separate migration script is that we want to be 100% sure data is migrated before any execution of clone logic.
115
+ *
116
+ * @todo Delete this one in the future.
117
+ */
118
+ private function maybe_migrate_options() {
119
+ $storages = array(
120
+ $this->_storage,
121
+ $this->_network_storage
122
+ );
123
+
124
+ foreach ( $storages as $storage ) {
125
+ $clone_data = $storage->get_option( self::OPTION_NAME );
126
+ if ( is_array( $clone_data ) && ! empty( $clone_data ) ) {
127
+ foreach ( $clone_data as $key => $val ) {
128
+ if ( ! is_null( $val ) ) {
129
+ $storage->set_option( $key, $val );
130
+ }
131
+ }
132
+
133
+ $storage->unset_option( self::OPTION_NAME, true );
134
+ }
135
+ }
136
+ }
137
+
138
+ /**
139
+ * @author Leo Fajardo (@leorw)
140
+ * @since 2.5.0
141
+ */
142
+ function _init() {
143
+ if ( is_admin() ) {
144
+ if ( Freemius::is_admin_post() ) {
145
+ add_action( 'admin_post_fs_clone_resolution', array( $this, '_handle_clone_resolution' ) );
146
+ }
147
+
148
+ if ( Freemius::is_ajax() ) {
149
+ Freemius::add_ajax_action_static( 'handle_clone_resolution', array( $this, '_clone_resolution_action_ajax_handler' ) );
150
+ } else {
151
+ if (
152
+ empty( $this->get_clone_identification_timestamp() ) &&
153
+ (
154
+ ! fs_is_network_admin() ||
155
+ ! ( $this->is_clone_resolution_options_notice_shown() || $this->is_temporary_duplicate_notice_shown() )
156
+ )
157
+ ) {
158
+ $this->hide_clone_admin_notices();
159
+ } else if ( ! Freemius::is_cron() && ! Freemius::is_admin_post() ) {
160
+ $this->try_resolve_clone_automatically();
161
+ $this->maybe_show_clone_admin_notice();
162
+
163
+ add_action( 'admin_footer', array( $this, '_add_clone_resolution_javascript' ) );
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Retrieves the timestamp that was stored when a clone was identified.
171
+ *
172
+ * @return int|null
173
+ */
174
+ function get_clone_identification_timestamp() {
175
+ return $this->get_option( 'clone_identification_timestamp', true );
176
+ }
177
+
178
+ /**
179
+ * @author Leo Fajardo (@leorw)
180
+ * @since 2.5.1
181
+ *
182
+ * @param string $sdk_last_version
183
+ */
184
+ function maybe_update_clone_resolution_support_flag( $sdk_last_version ) {
185
+ if ( null !== $this->hide_manual_resolution ) {
186
+ return;
187
+ }
188
+
189
+ $this->hide_manual_resolution = (
190
+ ! empty( $sdk_last_version ) &&
191
+ version_compare( $sdk_last_version, '2.5.0', '<' )
192
+ );
193
+ }
194
+
195
+ /**
196
+ * Stores the time when a clone was identified.
197
+ */
198
+ function store_clone_identification_timestamp() {
199
+ $this->clone_identification_timestamp = time();
200
+ }
201
+
202
+ /**
203
+ * Retrieves the timestamp for the temporary duplicate mode's expiration.
204
+ *
205
+ * @return int
206
+ */
207
+ function get_temporary_duplicate_expiration_timestamp() {
208
+ $temporary_duplicate_mode_start_timestamp = $this->was_temporary_duplicate_mode_selected() ?
209
+ $this->temporary_duplicate_mode_selection_timestamp :
210
+ $this->get_clone_identification_timestamp();
211
+
212
+ return ( $temporary_duplicate_mode_start_timestamp + self::TEMPORARY_DUPLICATE_PERIOD );
213
+ }
214
+
215
+ /**
216
+ * Determines if the SDK should handle clones. The SDK handles clones only up to 3 times with 3 min interval.
217
+ *
218
+ * @return bool
219
+ */
220
+ private function should_handle_clones() {
221
+ if ( ! isset( $this->request_handler_timestamp ) ) {
222
+ return true;
223
+ }
224
+
225
+ if ( $this->request_handler_retries_count >= self::CLONE_RESOLUTION_MAX_RETRIES ) {
226
+ return false;
227
+ }
228
+
229
+ // Give the logic that handles clones enough time to finish (it is given 3 minutes for now).
230
+ return ( time() > ( $this->request_handler_timestamp + self::CLONE_RESOLUTION_MAX_EXECUTION_TIME ) );
231
+ }
232
+
233
+ /**
234
+ * @author Leo Fajardo (@leorw)
235
+ * @since 2.5.1
236
+ *
237
+ * @return bool
238
+ */
239
+ function should_hide_manual_resolution() {
240
+ return ( true === $this->hide_manual_resolution );
241
+ }
242
+
243
+ /**
244
+ * Executes the clones handler logic if it should be executed, i.e., based on the return value of the should_handle_clones() method.
245
+ *
246
+ * @author Leo Fajardo (@leorw)
247
+ * @since 2.5.0
248
+ */
249
+ function maybe_run_clone_resolution() {
250
+ if ( ! $this->should_handle_clones() ) {
251
+ return;
252
+ }
253
+
254
+ $this->request_handler_retries_count = isset( $this->request_handler_retries_count ) ?
255
+ ( $this->request_handler_retries_count + 1 ) :
256
+ 1;
257
+
258
+ $this->request_handler_timestamp = time();
259
+
260
+ $handler_id = ( rand() . microtime() );
261
+ $this->request_handler_id = $handler_id;
262
+
263
+ // Add cookies to trigger request with the same user access permissions.
264
+ $cookies = array();
265
+ foreach ( $_COOKIE as $name => $value ) {
266
+ $cookies[] = new WP_Http_Cookie( array(
267
+ 'name' => $name,
268
+ 'value' => $value,
269
+ ) );
270
+ }
271
+
272
+ wp_remote_post(
273
+ admin_url( 'admin-post.php' ),
274
+ array(
275
+ 'method' => 'POST',
276
+ 'body' => array(
277
+ 'action' => 'fs_clone_resolution',
278
+ 'handler_id' => $handler_id,
279
+ ),
280
+ 'timeout' => 0.01,
281
+ 'blocking' => false,
282
+ 'sslverify' => false,
283
+ 'cookies' => $cookies,
284
+ )
285
+ );
286
+ }
287
+
288
+ /**
289
+ * Executes the clones handler logic.
290
+ *
291
+ * @author Leo Fajardo (@leorw)
292
+ * @since 2.5.0
293
+ */
294
+ function _handle_clone_resolution() {
295
+ $handler_id = fs_request_get( 'handler_id' );
296
+
297
+ if ( empty( $handler_id ) ) {
298
+ return;
299
+ }
300
+
301
+ if (
302
+ ! isset( $this->request_handler_id ) ||
303
+ $this->request_handler_id !== $handler_id
304
+ ) {
305
+ return;
306
+ }
307
+
308
+ if ( ! $this->try_automatic_resolution() ) {
309
+ $this->clear_temporary_duplicate_notice_shown_timestamp();
310
+ }
311
+ }
312
+
313
+ #--------------------------------------------------------------------------------
314
+ #region Automatic Clone Resolution
315
+ #--------------------------------------------------------------------------------
316
+
317
+ /**
318
+ * @var array All installs cache.
319
+ */
320
+ private $all_installs;
321
+
322
+ /**
323
+ * Checks if a given instance's install is a clone of another subsite in the network.
324
+ *
325
+ * @author Vova Feldman (@svovaf)
326
+ *
327
+ * @return FS_Site
328
+ */
329
+ private function find_network_subsite_clone_install( Freemius $instance ) {
330
+ if ( ! is_multisite() ) {
331
+ // Not a multi-site network.
332
+ return null;
333
+ }
334
+
335
+ if ( ! isset( $this->all_installs ) ) {
336
+ $this->all_installs = Freemius::get_all_modules_sites();
337
+ }
338
+
339
+ // Check if there's another blog that has the same site.
340
+ $module_type = $instance->get_module_type();
341
+ $sites_by_module_type = ! empty( $this->all_installs[ $module_type ] ) ?
342
+ $this->all_installs[ $module_type ] :
343
+ array();
344
+
345
+ $slug = $instance->get_slug();
346
+ $sites_by_slug = ! empty( $sites_by_module_type[ $slug ] ) ?
347
+ $sites_by_module_type[ $slug ] :
348
+ array();
349
+
350
+ $current_blog_id = get_current_blog_id();
351
+
352
+ $current_install = $instance->get_site();
353
+
354
+ foreach ( $sites_by_slug as $site ) {
355
+ if (
356
+ $current_install->id == $site->id &&
357
+ $current_blog_id != $site->blog_id
358
+ ) {
359
+ // Clone is identical to an install on another subsite in the network.
360
+ return $site;
361
+ }
362
+ }
363
+
364
+ return null;
365
+ }
366
+
367
+ /**
368
+ * Tries to find a different install of the context product that is associated with the current URL and loads it.
369
+ *
370
+ * @author Leo Fajardo (@leorw)
371
+ * @since 2.5.0
372
+ *
373
+ * @param Freemius $instance
374
+ * @param string $url
375
+ *
376
+ * @return object
377
+ */
378
+ private function find_other_install_by_url( Freemius $instance, $url ) {
379
+ $result = $instance->get_api_user_scope()->get( "/plugins/{$instance->get_id()}/installs.json?url=" . urlencode( $url ) . "&all=true", true );
380
+
381
+ $current_install = $instance->get_site();
382
+
383
+ if ( $instance->is_api_result_object( $result, 'installs' ) ) {
384
+ foreach ( $result->installs as $install ) {
385
+ if ( $install->id == $current_install->id ) {
386
+ continue;
387
+ }
388
+
389
+ if (
390
+ $instance->is_only_premium() &&
391
+ ! FS_Plugin_License::is_valid_id( $install->license_id )
392
+ ) {
393
+ continue;
394
+ }
395
+
396
+ // When searching for installs by a URL, the API will first strip any paths and search for any matching installs by the subdomain. Therefore, we need to test if there's a match between the current URL and the install's URL before continuing.
397
+ if ( $url !== fs_strip_url_protocol( untrailingslashit( $install->url ) ) ) {
398
+ continue;
399
+ }
400
+
401
+ // Found a different install that is associated with the current URL, load it and replace the current install with it if no updated install is found.
402
+ return $install;
403
+ }
404
+ }
405
+
406
+ return null;
407
+ }
408
+
409
+ /**
410
+ * Delete the current install associated with a given instance and opt-in/activate-license to create a fresh install.
411
+ *
412
+ * @author Vova Feldman (@svovaf)
413
+ * @since 2.5.0
414
+ *
415
+ * @param Freemius $instance
416
+ * @param string|false $license_key
417
+ *
418
+ * @return bool TRUE if successfully connected. FALSE if failed and had to restore install from backup.
419
+ */
420
+ private function delete_install_and_connect( Freemius $instance, $license_key = false ) {
421
+ $user = Freemius::_get_user_by_id( $instance->get_site()->user_id );
422
+
423
+ $instance->delete_current_install( true );
424
+
425
+ if ( ! is_object( $user ) ) {
426
+ // Get logged-in WordPress user.
427
+ $current_user = Freemius::_get_current_wp_user();
428
+
429
+ // Find the relevant FS user by email address.
430
+ $user = Freemius::_get_user_by_email( $current_user->user_email );
431
+ }
432
+
433
+ if ( is_object( $user ) ) {
434
+ // When a clone is found, we prefer to use the same user of the original install for the opt-in.
435
+ $instance->install_with_user( $user, $license_key, false, false );
436
+ } else {
437
+ // If no user is found, activate with the license.
438
+ $instance->opt_in(
439
+ false,
440
+ false,
441
+ false,
442
+ $license_key
443
+ );
444
+ }
445
+
446
+ if ( is_object( $instance->get_site() ) ) {
447
+ // Install successfully created.
448
+ return true;
449
+ }
450
+
451
+ // Restore from backup.
452
+ $instance->restore_backup_site();
453
+
454
+ return false;
455
+ }
456
+
457
+ /**
458
+ * Try to resolve the clone situation automatically.
459
+ *
460
+ * @param Freemius $instance
461
+ * @param string $current_url
462
+ * @param bool $is_localhost
463
+ * @param bool|null $is_clone_of_network_subsite
464
+ *
465
+ * @return bool If managed to automatically resolve the clone.
466
+ */
467
+ private function try_resolve_clone_automatically_by_instance(
468
+ Freemius $instance,
469
+ $current_url,
470
+ $is_localhost,
471
+ $is_clone_of_network_subsite = null
472
+ ) {
473
+ // Try to find a different install of the context product that is associated with the current URL.
474
+ $associated_install = $this->find_other_install_by_url( $instance, $current_url );
475
+
476
+ if ( is_object( $associated_install ) ) {
477
+ // Replace the current install with a different install that is associated with the current URL.
478
+ $instance->store_site( new FS_Site( clone $associated_install ) );
479
+ $instance->sync_install( array( 'is_new_site' => true ), true );
480
+
481
+ return true;
482
+ }
483
+
484
+ if ( ! $instance->is_premium() ) {
485
+ // For free products, opt-in with the context user to create new install.
486
+ return $this->delete_install_and_connect( $instance );
487
+ }
488
+
489
+ $license = $instance->_get_license();
490
+ $can_activate_license = ( is_object( $license ) && ! $license->is_utilized( $is_localhost ) );
491
+
492
+ if ( ! $can_activate_license ) {
493
+ // License can't be activated, therefore, can't be automatically resolved.
494
+ return false;
495
+ }
496
+
497
+ if ( ! WP_FS__IS_LOCALHOST_FOR_SERVER && ! $is_localhost ) {
498
+ $is_clone_of_network_subsite = ( ! is_null( $is_clone_of_network_subsite ) ) ?
499
+ $is_clone_of_network_subsite :
500
+ is_object( $this->find_network_subsite_clone_install( $instance ) );
501
+
502
+ if ( ! $is_clone_of_network_subsite ) {
503
+ return false;
504
+ }
505
+ }
506
+
507
+ // If the site is a clone of another subsite in the network, or a localhost one, try to auto activate the license.
508
+ return $this->delete_install_and_connect( $instance, $license->secret_key );
509
+ }
510
+
511
+ /**
512
+ * @author Leo Fajardo (@leorw)
513
+ * @since 2.5.0
514
+ */
515
+ private function try_resolve_clone_automatically() {
516
+ $clone_action = $this->get_clone_resolution_action_from_config();
517
+
518
+ if ( ! empty( $clone_action ) ) {
519
+ $this->try_resolve_clone_automatically_by_config( $clone_action );
520
+ return;
521
+ }
522
+
523
+ $this->try_automatic_resolution();
524
+ }
525
+
526
+ /**
527
+ * Tries to resolve the clone situation automatically based on the config in the wp-config.php file.
528
+ *
529
+ * @author Leo Fajardo (@leorw)
530
+ * @since 2.5.0
531
+ *
532
+ * @param string $clone_action
533
+ */
534
+ private function try_resolve_clone_automatically_by_config( $clone_action ) {
535
+ $fs_instances = array();
536
+
537
+ if ( self::OPTION_LONG_TERM_DUPLICATE === $clone_action ) {
538
+ $instances = Freemius::_get_all_instances();
539
+
540
+ foreach ( $instances as $instance ) {
541
+ if ( ! $instance->is_registered() ) {
542
+ continue;
543
+ }
544
+
545
+ if ( ! $instance->is_clone() ) {
546
+ continue;
547
+ }
548
+
549
+ $license = $instance->has_features_enabled_license() ?
550
+ $instance->_get_license() :
551
+ null;
552
+
553
+ if (
554
+ is_object( $license ) &&
555
+ ! $license->is_utilized(
556
+ ( WP_FS__IS_LOCALHOST_FOR_SERVER || FS_Site::is_localhost_by_address( Freemius::get_unfiltered_site_url() ) )
557
+ )
558
+ ) {
559
+ $fs_instances[] = $instance;
560
+ }
561
+ }
562
+
563
+ if ( empty( $fs_instances ) ) {
564
+ return;
565
+ }
566
+ }
567
+
568
+ $this->resolve_cloned_sites( $clone_action, $fs_instances );
569
+ }
570
+
571
+ /**
572
+ * @author Leo Fajard (@leorw)
573
+ * @since 2.5.0
574
+ *
575
+ * @return string|null
576
+ */
577
+ private function get_clone_resolution_action_from_config() {
578
+ if ( ! defined( 'FS__RESOLVE_CLONE_AS' ) ) {
579
+ return null;
580
+ }
581
+
582
+ if ( ! in_array(
583
+ FS__RESOLVE_CLONE_AS,
584
+ array(
585
+ self::OPTION_NEW_HOME,
586
+ self::OPTION_TEMPORARY_DUPLICATE,
587
+ self::OPTION_LONG_TERM_DUPLICATE,
588
+ )
589
+ ) ) {
590
+ return null;
591
+ }
592
+
593
+ return FS__RESOLVE_CLONE_AS;
594
+ }
595
+
596
+ /**
597
+ * Tries to recover the install of a newly created subsite or resolve it if it's a clone.
598
+ *
599
+ * @author Leo Fajardo (@leorw)
600
+ * @since 2.5.0
601
+ *
602
+ * @param Freemius $instance
603
+ */
604
+ function maybe_resolve_new_subsite_install_automatically( Freemius $instance ) {
605
+ if ( ! $instance->is_user_in_admin() ) {
606
+ // Try to recover an install or resolve a clone only when there's a user in admin to prevent doing it prematurely (e.g., the install can get replaced with clone data again).
607
+ return;
608
+ }
609
+
610
+ if ( ! is_multisite() ) {
611
+ return;
612
+ }
613
+
614
+ $new_blog_install_map = $this->new_blog_install_map;
615
+
616
+ if ( empty( $new_blog_install_map ) || ! is_array( $new_blog_install_map ) ) {
617
+ return;
618
+ }
619
+
620
+ $is_network_admin = fs_is_network_admin();
621
+
622
+ if ( ! $is_network_admin ) {
623
+ // If not in network admin, handle the current site.
624
+ $blog_id = get_current_blog_id();
625
+ } else {
626
+ // If in network admin, handle only the first site.
627
+ $blog_ids = array_keys( $new_blog_install_map );
628
+ $blog_id = $blog_ids[0];
629
+ }
630
+
631
+ if ( ! isset( $new_blog_install_map[ $blog_id ] ) ) {
632
+ // There's no site to handle.
633
+ return;
634
+ }
635
+
636
+ $expected_install_id = $new_blog_install_map[ $blog_id ]['install_id'];
637
+
638
+ $current_install = $instance->get_install_by_blog_id( $blog_id );
639
+ $current_install_id = is_object( $current_install ) ?
640
+ $current_install->id :
641
+ null;
642
+
643
+ if ( $expected_install_id == $current_install_id ) {
644
+ // Remove the current site's information from the map to prevent handling it again.
645
+ $this->remove_new_blog_install_info_from_storage( $blog_id );
646
+
647
+ return;
648
+ }
649
+
650
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-lock.php';
651
+
652
+ $lock = new FS_Lock( self::OPTION_NAME . '_subsite' );
653
+
654
+ if ( ! $lock->try_lock(60) ) {
655
+ return;
656
+ }
657
+
658
+ $instance->switch_to_blog( $blog_id );
659
+
660
+ $current_url = untrailingslashit( Freemius::get_unfiltered_site_url( null, true ) );
661
+ $current_install_url = is_object( $current_install ) ?
662
+ fs_strip_url_protocol( untrailingslashit( $current_install->url ) ) :
663
+ null;
664
+
665
+ // This can be `false` even if the install is a clone as the URL can be updated as part of the cloning process.
666
+ $is_clone = ( ! is_null( $current_install_url ) && $current_url !== $current_install_url );
667
+
668
+ if ( ! FS_Site::is_valid_id( $expected_install_id ) ) {
669
+ $expected_install = null;
670
+ } else {
671
+ $expected_install = $instance->fetch_install_by_id( $expected_install_id );
672
+ }
673
+
674
+ if ( FS_Api::is_api_result_entity( $expected_install ) ) {
675
+ // Replace the current install with the expected install.
676
+ $instance->store_site( new FS_Site( clone $expected_install ) );
677
+ $instance->sync_install( array( 'is_new_site' => true ), true );
678
+ } else {
679
+ $network_subsite_clone_install = null;
680
+
681
+ if ( ! $is_clone ) {
682
+ // It is possible that `$is_clone` is `false` but the install is actually a clone as the following call checks the install ID and not the URL.
683
+ $network_subsite_clone_install = $this->find_network_subsite_clone_install( $instance );
684
+ }
685
+
686
+ if ( $is_clone || is_object( $network_subsite_clone_install ) ) {
687
+ // If there's no expected install (or it couldn't be fetched) and the current install is a clone, try to resolve the clone automatically.
688
+ $is_localhost = FS_Site::is_localhost_by_address( $current_url );
689
+
690
+ $resolved = $this->try_resolve_clone_automatically_by_instance( $instance, $current_url, $is_localhost, is_object( $network_subsite_clone_install ) );
691
+
692
+ if ( ! $resolved && is_object( $network_subsite_clone_install ) ) {
693
+ if ( empty( $this->get_clone_identification_timestamp() ) ) {
694
+ $this->store_clone_identification_timestamp();
695
+ }
696
+
697
+ // Since the clone couldn't be identified based on the URL, replace the stored install with the cloned install so that the manual clone resolution notice will appear.
698
+ $instance->store_site( clone $network_subsite_clone_install );
699
+ }
700
+ }
701
+ }
702
+
703
+ $instance->restore_current_blog();
704
+
705
+ // Remove the current site's information from the map to prevent handling it again.
706
+ $this->remove_new_blog_install_info_from_storage( $blog_id );
707
+
708
+ $lock->unlock();
709
+ }
710
+
711
+ /**
712
+ * If a new install was created after creating a new subsite, its ID is stored in the blog-install map so that it can be recovered in case it's replaced with a clone install (e.g., when the newly created subsite is a clone). The IDs of the clone subsites that were created while not running this version of the SDK or a higher version will also be stored in the said map so that the clone manager can also try to resolve them later on.
713
+ *
714
+ * @author Leo Fajardo (@leorw)
715
+ * @since 2.5.0
716
+ *
717
+ * @param int $blog_id
718
+ * @param FS_Site $site
719
+ */
720
+ function store_blog_install_info( $blog_id, $site = null ) {
721
+ $new_blog_install_map = $this->new_blog_install_map;
722
+
723
+ if (
724
+ empty( $new_blog_install_map ) ||
725
+ ! is_array( $new_blog_install_map )
726
+ ) {
727
+ $new_blog_install_map = array();
728
+ }
729
+
730
+ $install_id = null;
731
+
732
+ if ( is_object( $site ) ) {
733
+ $install_id = $site->id;
734
+ }
735
+
736
+ $new_blog_install_map[ $blog_id ] = array( 'install_id' => $install_id );
737
+
738
+ $this->new_blog_install_map = $new_blog_install_map;
739
+ }
740
+
741
+ /**
742
+ * @author Leo Fajardo (@leorw)
743
+ * @since 2.5.0
744
+ *
745
+ * @param int $blog_id
746
+ */
747
+ private function remove_new_blog_install_info_from_storage( $blog_id ) {
748
+ $new_blog_install_map = $this->new_blog_install_map;
749
+
750
+ unset( $new_blog_install_map[ $blog_id ] );
751
+ $this->new_blog_install_map = $new_blog_install_map;
752
+ }
753
+
754
+ /**
755
+ * Tries to resolve all clones automatically.
756
+ *
757
+ * @author Leo Fajardo (@leorw)
758
+ * @since 2.5.0
759
+ *
760
+ * @return bool If managed to automatically resolve all clones.
761
+ */
762
+ private function try_automatic_resolution() {
763
+ $this->_logger->entrance();
764
+
765
+ require_once WP_FS__DIR_INCLUDES . '/class-fs-lock.php';
766
+
767
+ $lock = new FS_Lock( self::OPTION_NAME );
768
+
769
+ /**
770
+ * Try to acquire lock for the next 60 sec based on the thread ID.
771
+ */
772
+ if ( ! $lock->try_lock( 60 ) ) {
773
+ return false;
774
+ }
775
+
776
+ $current_url = untrailingslashit( Freemius::get_unfiltered_site_url( null, true ) );
777
+ $is_localhost = FS_Site::is_localhost_by_address( $current_url );
778
+
779
+ $require_manual_resolution = false;
780
+
781
+ $instances = Freemius::_get_all_instances();
782
+
783
+ foreach ( $instances as $instance ) {
784
+ if ( ! $instance->is_registered() ) {
785
+ continue;
786
+ }
787
+
788
+ if ( ! $instance->is_clone() ) {
789
+ continue;
790
+ }
791
+
792
+ if ( ! $this->try_resolve_clone_automatically_by_instance( $instance, $current_url, $is_localhost ) ) {
793
+ $require_manual_resolution = true;
794
+ }
795
+ }
796
+
797
+ // Create a 1-day lock.
798
+ $lock->lock( WP_FS__TIME_24_HOURS_IN_SEC );
799
+
800
+ return ( ! $require_manual_resolution );
801
+ }
802
+
803
+ #endregion
804
+
805
+ #--------------------------------------------------------------------------------
806
+ #region Manual Clone Resolution
807
+ #--------------------------------------------------------------------------------
808
+
809
+ /**
810
+ * @author Leo Fajardo (@leorw)
811
+ * @since 2.5.0
812
+ */
813
+ function _add_clone_resolution_javascript() {
814
+ $vars = array( 'ajax_action' => Freemius::get_ajax_action_static( 'handle_clone_resolution' ) );
815
+
816
+ fs_require_once_template( 'clone-resolution-js.php', $vars );
817
+ }
818
+
819
+ /**
820
+ * @author Leo Fajardo (@leorw)
821
+ * @since 2.5.0
822
+ */
823
+ function _clone_resolution_action_ajax_handler() {
824
+ $this->_logger->entrance();
825
+
826
+ check_ajax_referer( Freemius::get_ajax_action_static( 'handle_clone_resolution' ), 'security' );
827
+
828
+ $clone_action = fs_request_get( 'clone_action' );
829
+ $blog_id = is_multisite() ?
830
+ fs_request_get( 'blog_id' ) :
831
+ 0;
832
+
833
+ if ( is_multisite() && $blog_id == get_current_blog_id() ) {
834
+ $blog_id = 0;
835
+ }
836
+
837
+ if ( empty( $clone_action ) ) {
838
+ Freemius::shoot_ajax_failure( array(
839
+ 'message' => fs_text_inline( 'Invalid clone resolution action.', 'invalid-clone-resolution-action-error' ),
840
+ 'redirect_url' => '',
841
+ ) );
842
+ }
843
+
844
+ $result = $this->resolve_cloned_sites( $clone_action, array(), $blog_id );
845
+
846
+ Freemius::shoot_ajax_success( $result );
847
+ }
848
+
849
+ /**
850
+ * @author Leo Fajardo (@leorw)
851
+ * @since 2.5.0
852
+ *
853
+ * @param string $clone_action
854
+ * @param Freemius[] $fs_instances
855
+ * @param int $blog_id
856
+ *
857
+ * @return array
858
+ */
859
+ private function resolve_cloned_sites( $clone_action, $fs_instances = array(), $blog_id = 0 ) {
860
+ $this->_logger->entrance();
861
+
862
+ $result = array();
863
+
864
+ $instances_with_clone = array();
865
+ $instances_with_clone_count = 0;
866
+ $install_by_instance_id = array();
867
+
868
+ $instances = ( ! empty( $fs_instances ) ) ?
869
+ $fs_instances :
870
+ Freemius::_get_all_instances();
871
+
872
+ $should_switch_to_blog = ( $blog_id > 0 );
873
+
874
+ foreach ( $instances as $instance ) {
875
+ if ( $should_switch_to_blog ) {
876
+ $instance->switch_to_blog( $blog_id );
877
+ }
878
+
879
+ if ( $instance->is_registered() && $instance->is_clone() ) {
880
+ $instances_with_clone[] = $instance;
881
+
882
+ $instances_with_clone_count ++;
883
+
884
+ $install_by_instance_id[ $instance->get_id() ] = $instance->get_site();
885
+ }
886
+ }
887
+
888
+ if ( self::OPTION_TEMPORARY_DUPLICATE === $clone_action ) {
889
+ $this->store_temporary_duplicate_timestamp();
890
+ } else {
891
+ $redirect_url = '';
892
+
893
+ foreach ( $instances_with_clone as $instance ) {
894
+ if ( $should_switch_to_blog ) {
895
+ $instance->switch_to_blog( $blog_id );
896
+ }
897
+
898
+ $has_error = false;
899
+
900
+ if ( self::OPTION_NEW_HOME === $clone_action ) {
901
+ $instance->sync_install( array( 'is_new_site' => true ), true );
902
+
903
+ if ( $instance->is_clone() ) {
904
+ $has_error = true;
905
+ }
906
+ } else {
907
+ $instance->_handle_long_term_duplicate();
908
+
909
+ if ( ! is_object( $instance->get_site() ) ) {
910
+ $has_error = true;
911
+ }
912
+ }
913
+
914
+ if ( $has_error && 1 === $instances_with_clone_count ) {
915
+ $redirect_url = $instance->get_activation_url();
916
+ }
917
+ }
918
+
919
+ $result = ( array( 'redirect_url' => $redirect_url ) );
920
+ }
921
+
922
+ foreach ( $instances_with_clone as $instance ) {
923
+ if ( $should_switch_to_blog ) {
924
+ $instance->switch_to_blog( $blog_id );
925
+ }
926
+
927
+ // No longer a clone, send an update.
928
+ if ( ! $instance->is_clone() ) {
929
+ $instance->send_clone_resolution_update(
930
+ $clone_action,
931
+ $install_by_instance_id[ $instance->get_id() ]
932
+ );
933
+ }
934
+ }
935
+
936
+ if ( 'temporary_duplicate_license_activation' !== $clone_action ) {
937
+ $this->remove_clone_resolution_options_notice();
938
+ } else {
939
+ $this->remove_temporary_duplicate_notice();
940
+ }
941
+
942
+ if ( $should_switch_to_blog ) {
943
+ foreach ( $instances as $instance ) {
944
+ $instance->restore_current_blog();
945
+ }
946
+ }
947
+
948
+ return $result;
949
+ }
950
+
951
+ /**
952
+ * @author Leo Fajardo (@leorw)
953
+ * @since 2.5.0
954
+ */
955
+ private function hide_clone_admin_notices() {
956
+ $this->remove_clone_resolution_options_notice( false );
957
+ $this->remove_temporary_duplicate_notice( false );
958
+ }
959
+
960
+ /**
961
+ * @author Leo Fajardo (@leorw)
962
+ * @since 2.5.0
963
+ */
964
+ function maybe_show_clone_admin_notice() {
965
+ $this->_logger->entrance();
966
+
967
+ if ( fs_is_network_admin() ) {
968
+ $existing_notice_ids = $this->maybe_remove_notices();
969
+
970
+ if ( ! empty( $existing_notice_ids ) ) {
971
+ fs_enqueue_local_style( 'fs_clone_resolution_notice', '/admin/clone-resolution.css' );
972
+ }
973
+
974
+ return;
975
+ }
976
+
977
+ $first_instance_with_clone = null;
978
+
979
+ $site_urls = array();
980
+ $sites_with_license_urls = array();
981
+ $sites_with_premium_version_count = 0;
982
+ $product_ids = array();
983
+ $product_titles = array();
984
+
985
+ $instances = Freemius::_get_all_instances();
986
+
987
+ foreach ( $instances as $instance ) {
988
+ if ( ! $instance->is_registered() ) {
989
+ continue;
990
+ }
991
+
992
+ if ( ! $instance->is_clone( true ) ) {
993
+ continue;
994
+ }
995
+
996
+ $install = $instance->get_site();
997
+
998
+ $site_urls[] = $install->url;
999
+ $product_ids[] = $instance->get_id();
1000
+ $product_titles[] = $instance->get_plugin_title();
1001
+
1002
+ if ( is_null( $first_instance_with_clone ) ) {
1003
+ $first_instance_with_clone = $instance;
1004
+ }
1005
+
1006
+ if ( is_object( $instance->_get_license() ) ) {
1007
+ $sites_with_license_urls[] = $install->url;
1008
+ }
1009
+
1010
+ if ( $instance->is_premium() ) {
1011
+ $sites_with_premium_version_count ++;
1012
+ }
1013
+ }
1014
+
1015
+ if ( empty( $site_urls ) && empty( $sites_with_license_urls ) ) {
1016
+ $this->hide_clone_admin_notices();
1017
+
1018
+ return;
1019
+ }
1020
+
1021
+ $site_urls = array_unique( $site_urls );
1022
+ $sites_with_license_urls = array_unique( $sites_with_license_urls );
1023
+
1024
+ $module_label = fs_text_inline( 'products', 'products' );
1025
+ $admin_notice_module_title = null;
1026
+
1027
+ $has_temporary_duplicate_mode_expired = $this->has_temporary_duplicate_mode_expired();
1028
+
1029
+ if (
1030
+ ! $this->was_temporary_duplicate_mode_selected() ||
1031
+ $has_temporary_duplicate_mode_expired
1032
+ ) {
1033
+ if ( ! empty( $site_urls ) ) {
1034
+ fs_enqueue_local_style( 'fs_clone_resolution_notice', '/admin/clone-resolution.css' );
1035
+
1036
+ $doc_url = 'https://freemius.com/help/documentation/wordpress-sdk/safe-mode-clone-resolution-duplicate-website/';
1037
+
1038
+ if ( 1 === count( $instances ) ) {
1039
+ $doc_url = fs_apply_filter(
1040
+ $first_instance_with_clone->get_unique_affix(),
1041
+ 'clone_resolution_documentation_url',
1042
+ $doc_url
1043
+ );
1044
+ }
1045
+
1046
+ $this->add_manual_clone_resolution_admin_notice(
1047
+ $product_ids,
1048
+ $product_titles,
1049
+ $site_urls,
1050
+ Freemius::get_unfiltered_site_url(),
1051
+ ( count( $site_urls ) === count( $sites_with_license_urls ) ),
1052
+ ( count( $site_urls ) === $sites_with_premium_version_count ),
1053
+ $doc_url
1054
+ );
1055
+ }
1056
+
1057
+ return;
1058
+ }
1059
+
1060
+ if ( empty( $sites_with_license_urls ) ) {
1061
+ return;
1062
+ }
1063
+
1064
+ if ( ! $this->is_temporary_duplicate_notice_shown() ) {
1065
+ $last_time_temporary_duplicate_notice_shown = $this->temporary_duplicate_notice_shown_timestamp;
1066
+ $was_temporary_duplicate_notice_shown_before = is_numeric( $last_time_temporary_duplicate_notice_shown );
1067
+
1068
+ if ( $was_temporary_duplicate_notice_shown_before ) {
1069
+ $temporary_duplicate_mode_expiration_timestamp = $this->get_temporary_duplicate_expiration_timestamp();
1070
+ $current_time = time();
1071
+
1072
+ if (
1073
+ $current_time > $temporary_duplicate_mode_expiration_timestamp ||
1074
+ $current_time < ( $temporary_duplicate_mode_expiration_timestamp - ( 2 * WP_FS__TIME_24_HOURS_IN_SEC ) )
1075
+ ) {
1076
+ // Do not show the notice if the temporary duplicate mode has already expired or it will expire more than 2 days from now.
1077
+ return;
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ if ( 1 === count( $sites_with_license_urls ) ) {
1083
+ $module_label = $first_instance_with_clone->get_module_label( true );
1084
+ $admin_notice_module_title = $first_instance_with_clone->get_plugin_title();
1085
+ }
1086
+
1087
+ fs_enqueue_local_style( 'fs_clone_resolution_notice', '/admin/clone-resolution.css' );
1088
+
1089
+ $this->add_temporary_duplicate_sticky_notice(
1090
+ $product_ids,
1091
+ $this->get_temporary_duplicate_admin_notice_string( $sites_with_license_urls, $product_titles, $module_label ),
1092
+ $admin_notice_module_title
1093
+ );
1094
+ }
1095
+
1096
+ /**
1097
+ * Removes the notices from the storage if the context product is either no longer active on the context subsite or it's active but there's no longer any clone. This prevents the notices from being shown on the network-level admin page when they are no longer relevant.
1098
+ *
1099
+ * @author Leo Fajardo (@leorw)
1100
+ * @since 2.5.1
1101
+ *
1102
+ * @return string[]
1103
+ */
1104
+ private function maybe_remove_notices() {
1105
+ $notices = array(
1106
+ 'clone_resolution_options_notice' => $this->_notices->get_sticky( 'clone_resolution_options_notice', true ),
1107
+ 'temporary_duplicate_notice' => $this->_notices->get_sticky( 'temporary_duplicate_notice', true ),
1108
+ );
1109
+
1110
+ $instances = Freemius::_get_all_instances();
1111
+
1112
+ foreach ( $notices as $id => $notice ) {
1113
+ if ( ! is_array( $notice ) ) {
1114
+ unset( $notices[ $id ] );
1115
+ continue;
1116
+ }
1117
+
1118
+ if ( empty( $notice['data'] ) || ! is_array( $notice['data'] ) ) {
1119
+ continue;
1120
+ }
1121
+
1122
+ if ( empty( $notice['data']['product_ids'] ) || empty( $notice['data']['blog_id'] ) ) {
1123
+ continue;
1124
+ }
1125
+
1126
+ $product_ids = $notice['data']['product_ids'];
1127
+ $blog_id = $notice['data']['blog_id'];
1128
+ $has_clone = false;
1129
+
1130
+ if ( ! is_null( get_site( $blog_id ) ) ) {
1131
+ foreach ( $product_ids as $product_id ) {
1132
+ if ( ! isset( $instances[ 'm_' . $product_id ] ) ) {
1133
+ continue;
1134
+ }
1135
+
1136
+ $instance = $instances[ 'm_' . $product_id ];
1137
+
1138
+ $plugin_basename = $instance->get_plugin_basename();
1139
+
1140
+ $is_plugin_active = is_plugin_active_for_network( $plugin_basename );
1141
+
1142
+ if ( ! $is_plugin_active ) {
1143
+ switch_to_blog( $blog_id );
1144
+
1145
+ $is_plugin_active = is_plugin_active( $plugin_basename );
1146
+
1147
+ restore_current_blog();
1148
+ }
1149
+
1150
+ if ( ! $is_plugin_active ) {
1151
+ continue;
1152
+ }
1153
+
1154
+ $install = $instance->get_install_by_blog_id( $blog_id );
1155
+
1156
+ if ( ! is_object( $install ) ) {
1157
+ continue;
1158
+ }
1159
+
1160
+ $subsite_url = Freemius::get_unfiltered_site_url( $blog_id, true, true );
1161
+
1162
+ $has_clone = ( fs_strip_url_protocol( trailingslashit( $install->url ) ) !== $subsite_url );
1163
+ }
1164
+ }
1165
+
1166
+ if ( ! $has_clone ) {
1167
+ $this->_notices->remove_sticky( $id, true, false );
1168
+ unset( $notices[ $id ] );
1169
+ }
1170
+ }
1171
+
1172
+ return array_keys( $notices );
1173
+ }
1174
+
1175
+ /**
1176
+ * Adds a notice that provides the logged-in WordPress user with manual clone resolution options.
1177
+ *
1178
+ * @param number[] $product_ids
1179
+ * @param string[] $site_urls
1180
+ * @param string $current_url
1181
+ * @param bool $has_license
1182
+ * @param bool $is_premium
1183
+ * @param string $doc_url
1184
+ */
1185
+ private function add_manual_clone_resolution_admin_notice(
1186
+ $product_ids,
1187
+ $product_titles,
1188
+ $site_urls,
1189
+ $current_url,
1190
+ $has_license,
1191
+ $is_premium,
1192
+ $doc_url
1193
+ ) {
1194
+ $this->_logger->entrance();
1195
+
1196
+ $total_sites = count( $site_urls );
1197
+ $sites_list = '';
1198
+
1199
+ $total_products = count( $product_titles );
1200
+ $products_list = '';
1201
+
1202
+ if ( 1 === $total_products ) {
1203
+ $notice_header = sprintf(
1204
+ '<div class="fs-notice-header"><p>%s</p></div>',
1205
+ fs_esc_html_inline( '%1$s has been placed into safe mode because we noticed that %2$s is an exact copy of %3$s.', 'single-cloned-site-safe-mode-message' )
1206
+ );
1207
+ } else {
1208
+ $notice_header = sprintf(
1209
+ '<div class="fs-notice-header"><p>%s</p></div>',
1210
+ ( 1 === $total_sites ) ?
1211
+ fs_esc_html_inline( 'The products below have been placed into safe mode because we noticed that %2$s is an exact copy of %3$s:%1$s', 'multiple-products-cloned-site-safe-mode-message' ) :
1212
+ fs_esc_html_inline( 'The products below have been placed into safe mode because we noticed that %2$s is an exact copy of these sites:%3$s%1$s', 'multiple-products-multiple-cloned-sites-safe-mode-message' )
1213
+ );
1214
+
1215
+ foreach ( $product_titles as $product_title ) {
1216
+ $products_list .= sprintf( '<li>%s</li>', $product_title );
1217
+ }
1218
+
1219
+ $products_list = '<ol>' . $products_list . '</ol>';
1220
+
1221
+ foreach ( $site_urls as $site_url ) {
1222
+ $sites_list .= sprintf(
1223
+ '<li><a href="%s" target="_blank">%s</a></li>',
1224
+ $site_url,
1225
+ fs_strip_url_protocol( $site_url )
1226
+ );
1227
+ }
1228
+
1229
+ $sites_list = '<ol>' . $sites_list . '</ol>';
1230
+ }
1231
+
1232
+ $remote_site_link = '<b>' . (1 === $total_sites ?
1233
+ sprintf(
1234
+ '<a href="%s" target="_blank">%s</a>',
1235
+ $site_urls[0],
1236
+ fs_strip_url_protocol( $site_urls[0] )
1237
+ ) :
1238
+ fs_text_inline( 'the above-mentioned sites', 'above-mentioned-sites' )) . '</b>';
1239
+
1240
+ $current_site_link = sprintf(
1241
+ '<b><a href="%s" target="_blank">%s</a></b>',
1242
+ $current_url,
1243
+ fs_strip_url_protocol( $current_url )
1244
+ );
1245
+
1246
+ $button_template = '<button class="button" data-clone-action="%s">%s</button>';
1247
+ $option_template = '<div class="fs-clone-resolution-option"><strong>%s</strong><p>%s</p><div>%s</div></div>';
1248
+
1249
+ $duplicate_option = sprintf(
1250
+ $option_template,
1251
+ fs_esc_html_inline( 'Is %2$s a duplicate of %4$s?', 'duplicate-site-confirmation-message' ),
1252
+ fs_esc_html_inline( 'Yes, %2$s is a duplicate of %4$s for the purpose of testing, staging, or development.', 'duplicate-site-message' ),
1253
+ ( $this->has_temporary_duplicate_mode_expired() ?
1254
+ sprintf(
1255
+ $button_template,
1256
+ 'long_term_duplicate',
1257
+ fs_text_inline( 'Long-Term Duplicate', 'long-term-duplicate' )
1258
+ ) :
1259
+ sprintf(
1260
+ $button_template,
1261
+ 'temporary_duplicate',
1262
+ fs_text_inline( 'Duplicate Website', 'duplicate-site' )
1263
+ ) )
1264
+ );
1265
+
1266
+ $migration_option = sprintf(
1267
+ $option_template,
1268
+ fs_esc_html_inline( 'Is %2$s the new home of %4$s?', 'migrate-site-confirmation-message' ),
1269
+ sprintf(
1270
+ fs_esc_html_inline( 'Yes, %%2$s is replacing %%4$s. I would like to migrate my %s from %%4$s to %%2$s.', 'migrate-site-message' ),
1271
+ ( $has_license ? fs_text_inline( 'license', 'license' ) : fs_text_inline( 'data', 'data' ) )
1272
+ ),
1273
+ sprintf(
1274
+ $button_template,
1275
+ 'new_home',
1276
+ $has_license ?
1277
+ fs_text_inline( 'Migrate License', 'migrate-product-license' ) :
1278
+ fs_text_inline( 'Migrate', 'migrate-product-data' )
1279
+ )
1280
+ );
1281
+
1282
+ $new_website = sprintf(
1283
+ $option_template,
1284
+ fs_esc_html_inline( 'Is %2$s a new website?', 'new-site-confirmation-message' ),
1285
+ fs_esc_html_inline( 'Yes, %2$s is a new and different website that is separate from %4$s.', 'new-site-message' ) .
1286
+ ($is_premium ?
1287
+ ' ' . fs_text_inline( 'It requires license activation.', 'new-site-requires-license-activation-message' ) :
1288
+ ''
1289
+ ),
1290
+ sprintf(
1291
+ $button_template,
1292
+ 'new_website',
1293
+ ( ! $is_premium || ! $has_license ) ?
1294
+ fs_text_inline( 'New Website', 'new-website' ) :
1295
+ fs_text_inline( 'Activate License', 'activate-license' )
1296
+ )
1297
+ );
1298
+
1299
+ $blog_id = get_current_blog_id();
1300
+
1301
+ /**
1302
+ * %1$s - single product's title or product titles list.
1303
+ * %2$s - site's URL.
1304
+ * %3$s - single install's URL or install URLs list.
1305
+ * %4$s - Clone site's link or "the above-mentioned sites" if there are multiple clone sites.
1306
+ */
1307
+ $message = sprintf(
1308
+ $notice_header .
1309
+ '<div class="fs-clone-resolution-options-container" data-ajax-url="' . esc_attr( admin_url( 'admin-ajax.php?_fs_network_admin=false', 'relative' ) ) . '" data-blog-id="' . $blog_id . '">' .
1310
+ $duplicate_option .
1311
+ $migration_option .
1312
+ $new_website . '</div>' .
1313
+ sprintf( '<div class="fs-clone-documentation-container">Unsure what to do? <a href="%s" target="_blank">Read more here</a>.</div>', $doc_url ),
1314
+ // %1$s
1315
+ ( 1 === $total_products ?
1316
+ sprintf( '<b>%s</b>', $product_titles[0] ) :
1317
+ ( 1 === $total_sites ?
1318
+ sprintf( '<div>%s</div>', $products_list ) :
1319
+ sprintf( '<div><p><strong>%s</strong>:</p>%s</div>', fs_esc_html_x_inline( 'Products', 'Clone resolution admin notice products list label', 'products' ), $products_list ) )
1320
+ ),
1321
+ // %2$s
1322
+ $current_site_link,
1323
+ // %3$s
1324
+ ( 1 === $total_sites ?
1325
+ $remote_site_link :
1326
+ $sites_list ),
1327
+ // %4$s
1328
+ $remote_site_link
1329
+ );
1330
+
1331
+ $this->_notices->add_sticky(
1332
+ $message,
1333
+ 'clone_resolution_options_notice',
1334
+ '',
1335
+ 'warn',
1336
+ true,
1337
+ null,
1338
+ null,
1339
+ true,
1340
+ // Intentionally not dismissible.
1341
+ false,
1342
+ array(
1343
+ 'product_ids' => $product_ids,
1344
+ 'blog_id' => $blog_id
1345
+ )
1346
+ );
1347
+ }
1348
+
1349
+ #endregion
1350
+
1351
+ #--------------------------------------------------------------------------------
1352
+ #region Temporary Duplicate (Short Term)
1353
+ #--------------------------------------------------------------------------------
1354
+
1355
+ /**
1356
+ * @author Leo Fajardo (@leorw)
1357
+ * @since 2.5.0
1358
+ *
1359
+ * @return string
1360
+ */
1361
+ private function get_temporary_duplicate_admin_notice_string(
1362
+ $site_urls,
1363
+ $product_titles,
1364
+ $module_label
1365
+ ) {
1366
+ $this->_logger->entrance();
1367
+
1368
+ $temporary_duplicate_end_date = $this->get_temporary_duplicate_expiration_timestamp();
1369
+ $temporary_duplicate_end_date = date( 'M j, Y', $temporary_duplicate_end_date );
1370
+
1371
+ $current_url = Freemius::get_unfiltered_site_url();
1372
+ $current_site_link = sprintf(
1373
+ '<b><a href="%s" target="_blank">%s</a></b>',
1374
+ $current_url,
1375
+ fs_strip_url_protocol( $current_url )
1376
+ );
1377
+
1378
+ $total_sites = count( $site_urls );
1379
+ $sites_list = '';
1380
+
1381
+ $total_products = count( $product_titles );
1382
+ $products_list = '';
1383
+
1384
+ if ( $total_sites > 1 ) {
1385
+ foreach ( $site_urls as $site_url ) {
1386
+ $sites_list .= sprintf(
1387
+ '<li><a href="%s" target="_blank">%s</a></li>',
1388
+ $site_url,
1389
+ fs_strip_url_protocol( $site_url )
1390
+ );
1391
+ }
1392
+
1393
+ $sites_list = '<ol class="fs-sites-list">' . $sites_list . '</ol>';
1394
+ }
1395
+
1396
+ if ( $total_products > 1 ) {
1397
+ foreach ( $product_titles as $product_title ) {
1398
+ $products_list .= sprintf( '<li>%s</li>', $product_title );
1399
+ }
1400
+
1401
+ $products_list = '<ol>' . $products_list . '</ol>';
1402
+ }
1403
+
1404
+ return sprintf(
1405
+ sprintf(
1406
+ '<div>%s</div>',
1407
+ ( 1 === $total_sites ?
1408
+ sprintf( '<p>%s</p>', fs_esc_html_inline( 'You marked this website, %s, as a temporary duplicate of %s.', 'temporary-duplicate-message' ) ) :
1409
+ sprintf( '<p>%s:</p>', fs_esc_html_inline( 'You marked this website, %s, as a temporary duplicate of these sites', 'temporary-duplicate-of-sites-message' ) ) . '%s' )
1410
+ ) . '%s',
1411
+ $current_site_link,
1412
+ ( 1 === $total_sites ?
1413
+ sprintf(
1414
+ '<b><a href="%s" target="_blank">%s</a></b>',
1415
+ $site_urls[0],
1416
+ fs_strip_url_protocol( $site_urls[0] )
1417
+ ) :
1418
+ $sites_list ),
1419
+ sprintf(
1420
+ '<div class="fs-clone-resolution-options-container fs-duplicate-site-options" data-ajax-url="%s" data-blog-id="' . get_current_blog_id() . '"><p>%s</p>%s<p>%s</p></div>',
1421
+ esc_attr( admin_url( 'admin-ajax.php?_fs_network_admin=false', 'relative' ) ),
1422
+ sprintf(
1423
+ fs_esc_html_inline( "%s automatic security & feature updates and paid functionality will keep working without interruptions until %s (or when your license expires, whatever comes first).", 'duplicate-site-confirmation-message' ),
1424
+ ( 1 === $total_products ?
1425
+ sprintf(
1426
+ fs_esc_html_x_inline( "The %s's", '"The <product_label>", e.g.: "The plugin"', 'the-product-x'),
1427
+ "<strong>{$module_label}</strong>"
1428
+ ) :
1429
+ fs_esc_html_inline( "The following products'", 'the-following-products' ) ),
1430
+ sprintf( '<strong>%s</strong>', $temporary_duplicate_end_date )
1431
+ ),
1432
+ ( 1 === $total_products ?
1433
+ '' :
1434
+ sprintf( '<div>%s</div>', $products_list )
1435
+ ),
1436
+ sprintf(
1437
+ fs_esc_html_inline( 'If this is a long term duplicate, to keep automatic updates and paid functionality after %s, please %s.', 'duplicate-site-message' ),
1438
+ sprintf( '<strong>%s</strong>', $temporary_duplicate_end_date),
1439
+ sprintf( '<a href="#" id="fs_temporary_duplicate_license_activation_link" data-clone-action="temporary_duplicate_license_activation">%s</a>', fs_esc_html_inline( 'activate a license here', 'activate-license-here' ) )
1440
+ )
1441
+ )
1442
+ );
1443
+ }
1444
+
1445
+ /**
1446
+ * Determines if the temporary duplicate mode has already expired.
1447
+ *
1448
+ * @return bool
1449
+ */
1450
+ function has_temporary_duplicate_mode_expired() {
1451
+ $temporary_duplicate_mode_start_timestamp = $this->was_temporary_duplicate_mode_selected() ?
1452
+ $this->get_option( 'temporary_duplicate_mode_selection_timestamp', true ) :
1453
+ $this->get_clone_identification_timestamp();
1454
+
1455
+ if ( ! is_numeric( $temporary_duplicate_mode_start_timestamp ) ) {
1456
+ return false;
1457
+ }
1458
+
1459
+ return ( time() > ( $temporary_duplicate_mode_start_timestamp + self::TEMPORARY_DUPLICATE_PERIOD ) );
1460
+ }
1461
+
1462
+ /**
1463
+ * Determines if the logged-in WordPress user manually selected the temporary duplicate mode for the site.
1464
+ *
1465
+ * @return bool
1466
+ */
1467
+ function was_temporary_duplicate_mode_selected() {
1468
+ return is_numeric( $this->temporary_duplicate_mode_selection_timestamp );
1469
+ }
1470
+
1471
+ /**
1472
+ * Stores the time when the logged-in WordPress user selected the temporary duplicate mode for the site.
1473
+ */
1474
+ private function store_temporary_duplicate_timestamp() {
1475
+ $this->temporary_duplicate_mode_selection_timestamp = time();
1476
+ }
1477
+
1478
+ /**
1479
+ * Removes the notice that is shown when the logged-in WordPress user has selected the temporary duplicate mode for the site.
1480
+ *
1481
+ * @param bool $store
1482
+ */
1483
+ function remove_clone_resolution_options_notice( $store = true ) {
1484
+ $this->_notices->remove_sticky( 'clone_resolution_options_notice', true, $store );
1485
+ }
1486
+
1487
+ /**
1488
+ * Removes the notice that is shown when the logged-in WordPress user has selected the temporary duplicate mode for the site.
1489
+ *
1490
+ * @param bool $store
1491
+ */
1492
+ function remove_temporary_duplicate_notice( $store = true ) {
1493
+ $this->_notices->remove_sticky( 'temporary_duplicate_notice', true, $store );
1494
+ }
1495
+
1496
+ /**
1497
+ * Determines if the manual clone resolution options notice is currently being shown.
1498
+ *
1499
+ * @return bool
1500
+ */
1501
+ function is_clone_resolution_options_notice_shown() {
1502
+ return $this->_notices->has_sticky( 'clone_resolution_options_notice', true );
1503
+ }
1504
+
1505
+ /**
1506
+ * Determines if the temporary duplicate notice is currently being shown.
1507
+ *
1508
+ * @return bool
1509
+ */
1510
+ function is_temporary_duplicate_notice_shown() {
1511
+ return $this->_notices->has_sticky( 'temporary_duplicate_notice', true );
1512
+ }
1513
+
1514
+ /**
1515
+ * Determines if a site was marked as a temporary duplicate and if it's still a temporary duplicate.
1516
+ *
1517
+ * @return bool
1518
+ */
1519
+ function is_temporary_duplicate_by_blog_id( $blog_id ) {
1520
+ $timestamp = $this->get_option( 'temporary_duplicate_mode_selection_timestamp', false, $blog_id );
1521
+
1522
+ return (
1523
+ is_numeric( $timestamp ) &&
1524
+ time() < ( $timestamp + self::TEMPORARY_DUPLICATE_PERIOD )
1525
+ );
1526
+ }
1527
+
1528
+ /**
1529
+ * Determines the last time the temporary duplicate notice was shown.
1530
+ *
1531
+ * @return int|null
1532
+ */
1533
+ function last_time_temporary_duplicate_notice_was_shown() {
1534
+ return $this->temporary_duplicate_notice_shown_timestamp;
1535
+ }
1536
+
1537
+ /**
1538
+ * Clears the time that has been stored when the temporary duplicate notice was shown.
1539
+ */
1540
+ function clear_temporary_duplicate_notice_shown_timestamp() {
1541
+ unset( $this->temporary_duplicate_notice_shown_timestamp );
1542
+ }
1543
+
1544
+ /**
1545
+ * Adds a temporary duplicate notice that provides the logged-in WordPress user with an option to activate a license for the site.
1546
+ *
1547
+ * @param number[] $product_ids
1548
+ * @param string $message
1549
+ * @param string|null $plugin_title
1550
+ */
1551
+ function add_temporary_duplicate_sticky_notice(
1552
+ $product_ids,
1553
+ $message,
1554
+ $plugin_title = null
1555
+ ) {
1556
+ $this->_logger->entrance();
1557
+
1558
+ $this->_notices->add_sticky(
1559
+ $message,
1560
+ 'temporary_duplicate_notice',
1561
+ '',
1562
+ 'promotion',
1563
+ true,
1564
+ null,
1565
+ $plugin_title,
1566
+ true,
1567
+ true,
1568
+ array(
1569
+ 'product_ids' => $product_ids,
1570
+ 'blog_id' => get_current_blog_id()
1571
+ )
1572
+ );
1573
+
1574
+ $this->temporary_duplicate_notice_shown_timestamp = time();
1575
+ }
1576
+
1577
+ #endregion
1578
+
1579
+ /**
1580
+ * @author Leo Fajardo
1581
+ * @since 2.5.0
1582
+ *
1583
+ * @param string $key
1584
+ *
1585
+ * @return bool
1586
+ */
1587
+ private function should_use_network_storage( $key ) {
1588
+ return ( 'new_blog_install_map' === $key );
1589
+ }
1590
+
1591
+ /**
1592
+ * @param string $key
1593
+ * @param number|null $blog_id
1594
+ *
1595
+ * @return FS_Option_Manager
1596
+ */
1597
+ private function get_storage( $key, $blog_id = null ) {
1598
+ if ( is_numeric( $blog_id ) ){
1599
+ return FS_Option_Manager::get_manager( WP_FS___OPTION_PREFIX . self::OPTION_MANAGER_NAME, true, $blog_id );
1600
+ }
1601
+
1602
+ return $this->should_use_network_storage( $key ) ?
1603
+ $this->_network_storage :
1604
+ $this->_storage;
1605
+ }
1606
+
1607
+ /**
1608
+ * @param string $name
1609
+ * @param bool $flush
1610
+ * @param number|null $blog_id
1611
+ *
1612
+ * @return mixed
1613
+ */
1614
+ private function get_option( $name, $flush = false, $blog_id = null ) {
1615
+ return $this->get_storage( $name, $blog_id )->get_option( $name, null, $flush );
1616
+ }
1617
+
1618
+ #--------------------------------------------------------------------------------
1619
+ #region Magic methods
1620
+ #--------------------------------------------------------------------------------
1621
+
1622
+ /**
1623
+ * @param string $name
1624
+ * @param int|string $value
1625
+ */
1626
+ function __set( $name, $value ) {
1627
+ $this->get_storage( $name )->set_option( $name, $value, true );
1628
+ }
1629
+
1630
+ /**
1631
+ * @param string $name
1632
+ *
1633
+ * @return bool
1634
+ */
1635
+ function __isset( $name ) {
1636
+ return $this->get_storage( $name )->has_option( $name, true );
1637
+ }
1638
+
1639
+ /**
1640
+ * @param string $name
1641
+ */
1642
+ function __unset( $name ) {
1643
+ $this->get_storage( $name )->unset_option( $name, true );
1644
+ }
1645
+
1646
+ /**
1647
+ * @param string $name
1648
+ *
1649
+ * @return null|int|string
1650
+ */
1651
+ function __get( $name ) {
1652
+ return $this->get_option(
1653
+ $name,
1654
+ // Reload storage from DB when accessing request_handler_* options to avoid race conditions.
1655
+ fs_starts_with( $name, 'request_handler' )
1656
+ );
1657
+ }
1658
+
1659
+ #endregion
1660
+ }
freemius/includes/managers/class-fs-key-value-storage.php CHANGED
@@ -298,6 +298,7 @@
298
  return $this->get( $k, null );
299
  }
300
 
 
301
  function offsetSet( $k, $v ) {
302
  if ( is_null( $k ) ) {
303
  throw new Exception( 'Can\'t append value to request params.' );
@@ -306,14 +307,17 @@
306
  }
307
  }
308
 
 
309
  function offsetExists( $k ) {
310
  return array_key_exists( $k, $this->_data );
311
  }
312
 
 
313
  function offsetUnset( $k ) {
314
  unset( $this->$k );
315
  }
316
 
 
317
  function offsetGet( $k ) {
318
  return $this->get( $k, null );
319
  }
@@ -325,6 +329,7 @@
325
  * @link http://php.net/manual/en/iterator.current.php
326
  * @return mixed Can return any type.
327
  */
 
328
  public function current() {
329
  return current( $this->_data );
330
  }
@@ -336,6 +341,7 @@
336
  * @link http://php.net/manual/en/iterator.next.php
337
  * @return void Any returned value is ignored.
338
  */
 
339
  public function next() {
340
  next( $this->_data );
341
  }
@@ -347,6 +353,7 @@
347
  * @link http://php.net/manual/en/iterator.key.php
348
  * @return mixed scalar on success, or null on failure.
349
  */
 
350
  public function key() {
351
  return key( $this->_data );
352
  }
@@ -359,6 +366,7 @@
359
  * @return boolean The return value will be casted to boolean and then evaluated.
360
  * Returns true on success or false on failure.
361
  */
 
362
  public function valid() {
363
  $key = key( $this->_data );
364
 
@@ -372,6 +380,7 @@
372
  * @link http://php.net/manual/en/iterator.rewind.php
373
  * @return void Any returned value is ignored.
374
  */
 
375
  public function rewind() {
376
  reset( $this->_data );
377
  }
@@ -386,6 +395,7 @@
386
  * <p>
387
  * The return value is cast to an integer.
388
  */
 
389
  public function count() {
390
  return count( $this->_data );
391
  }
298
  return $this->get( $k, null );
299
  }
300
 
301
+ #[ReturnTypeWillChange]
302
  function offsetSet( $k, $v ) {
303
  if ( is_null( $k ) ) {
304
  throw new Exception( 'Can\'t append value to request params.' );
307
  }
308
  }
309
 
310
+ #[ReturnTypeWillChange]
311
  function offsetExists( $k ) {
312
  return array_key_exists( $k, $this->_data );
313
  }
314
 
315
+ #[ReturnTypeWillChange]
316
  function offsetUnset( $k ) {
317
  unset( $this->$k );
318
  }
319
 
320
+ #[ReturnTypeWillChange]
321
  function offsetGet( $k ) {
322
  return $this->get( $k, null );
323
  }
329
  * @link http://php.net/manual/en/iterator.current.php
330
  * @return mixed Can return any type.
331
  */
332
+ #[ReturnTypeWillChange]
333
  public function current() {
334
  return current( $this->_data );
335
  }
341
  * @link http://php.net/manual/en/iterator.next.php
342
  * @return void Any returned value is ignored.
343
  */
344
+ #[ReturnTypeWillChange]
345
  public function next() {
346
  next( $this->_data );
347
  }
353
  * @link http://php.net/manual/en/iterator.key.php
354
  * @return mixed scalar on success, or null on failure.
355
  */
356
+ #[ReturnTypeWillChange]
357
  public function key() {
358
  return key( $this->_data );
359
  }
366
  * @return boolean The return value will be casted to boolean and then evaluated.
367
  * Returns true on success or false on failure.
368
  */
369
+ #[ReturnTypeWillChange]
370
  public function valid() {
371
  $key = key( $this->_data );
372
 
380
  * @link http://php.net/manual/en/iterator.rewind.php
381
  * @return void Any returned value is ignored.
382
  */
383
+ #[ReturnTypeWillChange]
384
  public function rewind() {
385
  reset( $this->_data );
386
  }
395
  * <p>
396
  * The return value is cast to an integer.
397
  */
398
+ #[ReturnTypeWillChange]
399
  public function count() {
400
  return count( $this->_data );
401
  }
freemius/includes/managers/class-fs-option-manager.php CHANGED
@@ -11,14 +11,11 @@
11
  }
12
 
13
  /**
14
- * 3-layer lazy options manager.
15
- * layer 3: Memory
16
- * layer 2: Cache (if there's any caching plugin and if WP_FS__DEBUG_SDK is FALSE)
17
- * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB
18
- * queries.
19
  *
20
- * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to
21
- * explicitly call store().
22
  *
23
  * Class Freemius_Option_Manager
24
  */
@@ -157,59 +154,33 @@
157
  function load( $flush = false ) {
158
  $this->_logger->entrance();
159
 
160
- $option_name = $this->get_option_manager_name();
161
-
162
- if ( $flush || ! isset( $this->_options ) ) {
163
- if ( isset( $this->_options ) ) {
164
- // Clear prev options.
165
- $this->clear();
166
- }
167
-
168
- $cache_group = $this->get_cache_group();
169
-
170
- if ( WP_FS__DEBUG_SDK ) {
171
-
172
- // Don't use cache layer in DEBUG mode.
173
- $load_options = empty( $this->_options );
174
-
175
- } else {
176
-
177
- $this->_options = wp_cache_get(
178
- $option_name,
179
- $cache_group
180
- );
181
 
182
- $load_options = ( false === $this->_options );
183
- }
 
 
184
 
185
- $cached = true;
186
 
187
- if ( $load_options ) {
188
- if ( $this->_is_network_storage ) {
189
- $this->_options = get_site_option( $option_name );
190
- } else if ( $this->_blog_id > 0 ) {
191
- $this->_options = get_blog_option( $this->_blog_id, $option_name );
192
- } else {
193
- $this->_options = get_option( $option_name );
194
- }
195
 
196
- if ( is_string( $this->_options ) ) {
197
- $this->_options = json_decode( $this->_options );
198
- }
199
 
200
  // $this->_logger->info('get_option = ' . var_export($this->_options, true));
201
 
202
- if ( false === $this->_options ) {
203
- $this->clear();
204
- }
205
-
206
- $cached = false;
207
- }
208
-
209
- if ( ! WP_FS__DEBUG_SDK && ! $cached ) {
210
- // Set non encoded cache.
211
- wp_cache_set( $option_name, $this->_options, $cache_group );
212
- }
213
  }
214
  }
215
 
@@ -272,10 +243,15 @@
272
  * @since 1.0.6
273
  *
274
  * @param string $option
 
275
  *
276
  * @return bool
277
  */
278
- function has_option( $option ) {
 
 
 
 
279
  return array_key_exists( $option, $this->_options );
280
  }
281
 
@@ -285,14 +261,15 @@
285
  *
286
  * @param string $option
287
  * @param mixed $default
 
288
  *
289
  * @return mixed
290
  */
291
- function get_option( $option, $default = null ) {
292
  $this->_logger->entrance( 'option = ' . $option );
293
 
294
- if ( ! $this->is_loaded() ) {
295
- $this->load();
296
  }
297
 
298
  if ( is_array( $this->_options ) ) {
@@ -310,7 +287,7 @@
310
  /**
311
  * If it's an object, return a clone of the object, otherwise,
312
  * external changes of the object will actually change the value
313
- * of the object in the options manager which may lead to an unexpected
314
  * behaviour and data integrity when a store() call is triggered.
315
  *
316
  * Example:
@@ -436,10 +413,6 @@
436
  } else {
437
  update_option( $option_name, $this->_options, $this->_autoload );
438
  }
439
-
440
- if ( ! WP_FS__DEBUG_SDK ) {
441
- wp_cache_set( $option_name, $this->_options, $this->get_cache_group() );
442
- }
443
  }
444
 
445
  /**
@@ -499,23 +472,5 @@
499
  return $this->_id;
500
  }
501
 
502
- /**
503
- * @author Vova Feldman (@svovaf)
504
- * @since 2.0.0
505
- *
506
- * @return string
507
- */
508
- private function get_cache_group() {
509
- $group = WP_FS__SLUG;
510
-
511
- if ( $this->_is_network_storage ) {
512
- $group .= '_ms';
513
- } else if ( $this->_blog_id > 0 ) {
514
- $group .= "_s{$this->_blog_id}";
515
- }
516
-
517
- return $group;
518
- }
519
-
520
  #endregion
521
  }
11
  }
12
 
13
  /**
14
+ * 2-layer lazy options manager.
15
+ * layer 2: Memory
16
+ * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB queries.
 
 
17
  *
18
+ * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to explicitly call store().
 
19
  *
20
  * Class Freemius_Option_Manager
21
  */
154
  function load( $flush = false ) {
155
  $this->_logger->entrance();
156
 
157
+ if ( ! $flush && isset( $this->_options ) ) {
158
+ return;
159
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
+ if ( isset( $this->_options ) ) {
162
+ // Clear prev options.
163
+ $this->clear();
164
+ }
165
 
166
+ $option_name = $this->get_option_manager_name();
167
 
168
+ if ( $this->_is_network_storage ) {
169
+ $this->_options = get_site_option( $option_name );
170
+ } else if ( $this->_blog_id > 0 ) {
171
+ $this->_options = get_blog_option( $this->_blog_id, $option_name );
172
+ } else {
173
+ $this->_options = get_option( $option_name );
174
+ }
 
175
 
176
+ if ( is_string( $this->_options ) ) {
177
+ $this->_options = json_decode( $this->_options );
178
+ }
179
 
180
  // $this->_logger->info('get_option = ' . var_export($this->_options, true));
181
 
182
+ if ( false === $this->_options ) {
183
+ $this->clear();
 
 
 
 
 
 
 
 
 
184
  }
185
  }
186
 
243
  * @since 1.0.6
244
  *
245
  * @param string $option
246
+ * @param bool $flush
247
  *
248
  * @return bool
249
  */
250
+ function has_option( $option, $flush = false ) {
251
+ if ( ! $this->is_loaded() || $flush ) {
252
+ $this->load( $flush );
253
+ }
254
+
255
  return array_key_exists( $option, $this->_options );
256
  }
257
 
261
  *
262
  * @param string $option
263
  * @param mixed $default
264
+ * @param bool $flush
265
  *
266
  * @return mixed
267
  */
268
+ function get_option( $option, $default = null, $flush = false ) {
269
  $this->_logger->entrance( 'option = ' . $option );
270
 
271
+ if ( ! $this->is_loaded() || $flush ) {
272
+ $this->load( $flush );
273
  }
274
 
275
  if ( is_array( $this->_options ) ) {
287
  /**
288
  * If it's an object, return a clone of the object, otherwise,
289
  * external changes of the object will actually change the value
290
+ * of the object in the option manager which may lead to an unexpected
291
  * behaviour and data integrity when a store() call is triggered.
292
  *
293
  * Example:
413
  } else {
414
  update_option( $option_name, $this->_options, $this->_autoload );
415
  }
 
 
 
 
416
  }
417
 
418
  /**
472
  return $this->_id;
473
  }
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  #endregion
476
  }
freemius/includes/managers/class-fs-permission-manager.php ADDED
@@ -0,0 +1,698 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2022, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * This class is responsible for managing the user permissions.
15
+ *
16
+ * @author Vova Feldman (@svovaf)
17
+ * @since 2.5.1
18
+ */
19
+ class FS_Permission_Manager {
20
+ /**
21
+ * @var Freemius
22
+ */
23
+ private $_fs;
24
+ /**
25
+ * @var FS_Storage
26
+ */
27
+ private $_storage;
28
+
29
+ /**
30
+ * @var array<number,self>
31
+ */
32
+ private static $_instances = array();
33
+
34
+ const PERMISSION_USER = 'user';
35
+ const PERMISSION_SITE = 'site';
36
+ const PERMISSION_EVENTS = 'events';
37
+ const PERMISSION_ESSENTIALS = 'essentials';
38
+ const PERMISSION_DIAGNOSTIC = 'diagnostic';
39
+ const PERMISSION_EXTENSIONS = 'extensions';
40
+ const PERMISSION_NEWSLETTER = 'newsletter';
41
+
42
+ /**
43
+ * @param Freemius $fs
44
+ *
45
+ * @return self
46
+ */
47
+ static function instance( Freemius $fs ) {
48
+ $id = $fs->get_id();
49
+
50
+ if ( ! isset( self::$_instances[ $id ] ) ) {
51
+ self::$_instances[ $id ] = new self( $fs );
52
+ }
53
+
54
+ return self::$_instances[ $id ];
55
+ }
56
+
57
+ /**
58
+ * @param Freemius $fs
59
+ */
60
+ protected function __construct( Freemius $fs ) {
61
+ $this->_fs = $fs;
62
+ $this->_storage = FS_Storage::instance( $fs->get_module_type(), $fs->get_slug() );
63
+ }
64
+
65
+ /**
66
+ * @return string[]
67
+ */
68
+ static function get_all_permission_ids() {
69
+ return array(
70
+ self::PERMISSION_USER,
71
+ self::PERMISSION_SITE,
72
+ self::PERMISSION_EVENTS,
73
+ self::PERMISSION_ESSENTIALS,
74
+ self::PERMISSION_DIAGNOSTIC,
75
+ self::PERMISSION_EXTENSIONS,
76
+ self::PERMISSION_NEWSLETTER,
77
+ );
78
+ }
79
+
80
+ /**
81
+ * @return string[]
82
+ */
83
+ static function get_api_managed_permission_ids() {
84
+ return array(
85
+ self::PERMISSION_USER,
86
+ self::PERMISSION_SITE,
87
+ self::PERMISSION_EXTENSIONS,
88
+ );
89
+ }
90
+
91
+ /**
92
+ * @param string $permission
93
+ *
94
+ * @return bool
95
+ */
96
+ static function is_supported_permission( $permission ) {
97
+ return in_array( $permission, self::get_all_permission_ids() );
98
+ }
99
+
100
+ /**
101
+ * @param bool $is_license_activation
102
+ * @param array[] $extra_permissions
103
+ *
104
+ * @return array[]
105
+ */
106
+ function get_permissions( $is_license_activation, array $extra_permissions = array() ) {
107
+ return $is_license_activation ?
108
+ $this->get_license_activation_permissions( $extra_permissions ) :
109
+ $this->get_opt_in_permissions( $extra_permissions );
110
+ }
111
+
112
+ #--------------------------------------------------------------------------------
113
+ #region Opt-In Permissions
114
+ #--------------------------------------------------------------------------------
115
+
116
+ /**
117
+ * @param array[] $extra_permissions
118
+ *
119
+ * @return array[]
120
+ */
121
+ function get_opt_in_permissions(
122
+ array $extra_permissions = array(),
123
+ $load_default_from_storage = false,
124
+ $is_optional = false
125
+ ) {
126
+ $permissions = array_merge(
127
+ $this->get_opt_in_required_permissions( $load_default_from_storage ),
128
+ $this->get_opt_in_optional_permissions( $load_default_from_storage, $is_optional ),
129
+ $extra_permissions
130
+ );
131
+
132
+ return $this->get_sorted_permissions_by_priority( $permissions );
133
+ }
134
+
135
+ /**
136
+ * @param bool $load_default_from_storage
137
+ *
138
+ * @return array[]
139
+ */
140
+ function get_opt_in_required_permissions( $load_default_from_storage = false ) {
141
+ return array( $this->get_user_permission( $load_default_from_storage ) );
142
+ }
143
+
144
+ /**
145
+ * @param bool $load_default_from_storage
146
+ * @param bool $is_optional
147
+ *
148
+ * @return array[]
149
+ */
150
+ function get_opt_in_optional_permissions(
151
+ $load_default_from_storage = false,
152
+ $is_optional = false
153
+ ) {
154
+ return array_merge(
155
+ $this->get_opt_in_diagnostic_permissions( $load_default_from_storage, $is_optional ),
156
+ array( $this->get_extensions_permission(
157
+ false,
158
+ false,
159
+ $load_default_from_storage
160
+ ) )
161
+ );
162
+ }
163
+
164
+ /**
165
+ * @param bool $load_default_from_storage
166
+ * @param bool $is_optional
167
+ *
168
+ * @return array[]
169
+ */
170
+ function get_opt_in_diagnostic_permissions(
171
+ $load_default_from_storage = false,
172
+ $is_optional = false
173
+ ) {
174
+ // Alias.
175
+ $fs = $this->_fs;
176
+
177
+ $permissions = array();
178
+
179
+ $permissions[] = $this->get_permission(
180
+ self::PERMISSION_SITE,
181
+ 'admin-links',
182
+ $fs->get_text_inline( 'View Basic Website Info', 'permissions-site' ),
183
+ $fs->get_text_inline( 'Homepage URL & title, WP & PHP versions, and site language', 'permissions-site_desc' ),
184
+ sprintf(
185
+ /* translators: %s: 'Plugin' or 'Theme' */
186
+ $fs->get_text_inline( 'To provide additional functionality that\'s relevant to your website, avoid WordPress or PHP version incompatibilities that can break your website, and recognize which languages & regions the %s should be translated and tailored to.', 'permissions-site_tooltip' ),
187
+ $fs->get_module_label( true )
188
+ ),
189
+ 10,
190
+ $is_optional,
191
+ true,
192
+ $load_default_from_storage
193
+ );
194
+
195
+ $permissions[] = $this->get_permission(
196
+ self::PERMISSION_EVENTS,
197
+ 'admin-' . ( $fs->is_plugin() ? 'plugins' : 'appearance' ),
198
+ sprintf( $fs->get_text_inline( 'View Basic %s Info', 'permissions-events' ), $fs->get_module_label() ),
199
+ sprintf(
200
+ /* translators: %s: 'Plugin' or 'Theme' */
201
+ $fs->get_text_inline( 'Current %s & SDK versions, and if active or uninstalled', 'permissions-events_desc' ),
202
+ $fs->get_module_label( true )
203
+ ),
204
+ '',
205
+ 20,
206
+ $is_optional,
207
+ true,
208
+ $load_default_from_storage
209
+ );
210
+
211
+ return $permissions;
212
+ }
213
+
214
+ #endregion
215
+
216
+ #--------------------------------------------------------------------------------
217
+ #region License Activation Permissions
218
+ #--------------------------------------------------------------------------------
219
+
220
+ /**
221
+ * @param array[] $extra_permissions
222
+ *
223
+ * @return array[]
224
+ */
225
+ function get_license_activation_permissions(
226
+ array $extra_permissions = array(),
227
+ $include_optional_label = true
228
+ ) {
229
+ $permissions = array_merge(
230
+ $this->get_license_required_permissions(),
231
+ $this->get_license_optional_permissions( $include_optional_label ),
232
+ $extra_permissions
233
+ );
234
+
235
+ return $this->get_sorted_permissions_by_priority( $permissions );
236
+ }
237
+
238
+ /**
239
+ * @param bool $load_default_from_storage
240
+ *
241
+ * @return array[]
242
+ */
243
+ function get_license_required_permissions( $load_default_from_storage = false ) {
244
+ // Alias.
245
+ $fs = $this->_fs;
246
+
247
+ $permissions = array();
248
+
249
+ $permissions[] = $this->get_permission(
250
+ self::PERMISSION_ESSENTIALS,
251
+ 'admin-links',
252
+ $fs->get_text_inline( 'View License Essentials', 'permissions-essentials' ),
253
+ $fs->get_text_inline(
254
+ sprintf(
255
+ /* translators: %s: 'Plugin' or 'Theme' */
256
+ 'Homepage URL, %s version, SDK version',
257
+ $fs->get_module_label()
258
+ ),
259
+ 'permissions-essentials_desc'
260
+ ),
261
+ sprintf(
262
+ /* translators: %s: 'Plugin' or 'Theme' */
263
+ $fs->get_text_inline( 'To let you manage & control where the license is activated and ensure %s security & feature updates are only delivered to websites you authorize.', 'permissions-essentials_tooltip' ),
264
+ $fs->get_module_label( true )
265
+ ),
266
+ 10,
267
+ false,
268
+ true,
269
+ $load_default_from_storage
270
+ );
271
+
272
+ $permissions[] = $this->get_permission(
273
+ self::PERMISSION_EVENTS,
274
+ 'admin-' . ( $fs->is_plugin() ? 'plugins' : 'appearance' ),
275
+ sprintf( $fs->get_text_inline( 'View %s State', 'permissions-events' ), $fs->get_module_label() ),
276
+ sprintf(
277
+ /* translators: %s: 'Plugin' or 'Theme' */
278
+ $fs->get_text_inline( 'Is active, deactivated, or uninstalled', 'permissions-events_desc-paid' ),
279
+ $fs->get_module_label( true )
280
+ ),
281
+ sprintf( $fs->get_text_inline( 'So you can reuse the license when the %s is no longer active.', 'permissions-events_tooltip' ), $fs->get_module_label( true ) ),
282
+ 20,
283
+ false,
284
+ true,
285
+ $load_default_from_storage
286
+ );
287
+
288
+ return $permissions;
289
+ }
290
+
291
+ /**
292
+ * @return array[]
293
+ */
294
+ function get_license_optional_permissions(
295
+ $include_optional_label = false,
296
+ $load_default_from_storage = false
297
+ ) {
298
+ return array(
299
+ $this->get_diagnostic_permission( $include_optional_label, $load_default_from_storage ),
300
+ $this->get_extensions_permission( true, $include_optional_label, $load_default_from_storage ),
301
+ );
302
+ }
303
+
304
+ /**
305
+ * @param bool $include_optional_label
306
+ * @param bool $load_default_from_storage
307
+ *
308
+ * @return array
309
+ */
310
+ function get_diagnostic_permission(
311
+ $include_optional_label = false,
312
+ $load_default_from_storage = false
313
+ ) {
314
+ return $this->get_permission(
315
+ self::PERMISSION_DIAGNOSTIC,
316
+ 'wordpress-alt',
317
+ $this->_fs->get_text_inline( 'View Diagnostic Info', 'permissions-diagnostic' ) . ( $include_optional_label ? ' (' . $this->_fs->get_text_inline( 'optional' ) . ')' : '' ),
318
+ $this->_fs->get_text_inline( 'WordPress & PHP versions, site language & title', 'permissions-diagnostic_desc' ),
319
+ sprintf(
320
+ /* translators: %s: 'Plugin' or 'Theme' */
321
+ $this->_fs->get_text_inline( 'To avoid breaking your website due to WordPress or PHP version incompatibilities, and recognize which languages & regions the %s should be translated and tailored to.', 'permissions-diagnostic_tooltip' ),
322
+ $this->_fs->get_module_label( true )
323
+ ),
324
+ 25,
325
+ true,
326
+ true,
327
+ $load_default_from_storage
328
+ );
329
+ }
330
+
331
+ #endregion
332
+
333
+ #--------------------------------------------------------------------------------
334
+ #region Common Permissions
335
+ #--------------------------------------------------------------------------------
336
+
337
+ /**
338
+ * @param bool $is_license_activation
339
+ * @param bool $include_optional_label
340
+ * @param bool $load_default_from_storage
341
+ *
342
+ * @return array
343
+ */
344
+ function get_extensions_permission(
345
+ $is_license_activation,
346
+ $include_optional_label = false,
347
+ $load_default_from_storage = false
348
+ ) {
349
+ $is_on_by_default = ! $is_license_activation;
350
+
351
+ return $this->get_permission(
352
+ self::PERMISSION_EXTENSIONS,
353
+ 'block-default',
354
+ $this->_fs->get_text_inline( 'View Plugins & Themes List', 'permissions-extensions' ) . ( $is_license_activation ? ( $include_optional_label ? ' (' . $this->_fs->get_text_inline( 'optional' ) . ')' : '' ) : '' ),
355
+ $this->_fs->get_text_inline( 'Names, slugs, versions, and if active or not', 'permissions-extensions_desc' ),
356
+ $this->_fs->get_text_inline( 'To ensure compatibility and avoid conflicts with your installed plugins and themes.', 'permissions-events_tooltip' ),
357
+ 25,
358
+ true,
359
+ $is_on_by_default,
360
+ $load_default_from_storage
361
+ );
362
+ }
363
+
364
+ /**
365
+ * @param bool $load_default_from_storage
366
+ *
367
+ * @return array
368
+ */
369
+ function get_user_permission( $load_default_from_storage = false ) {
370
+ return $this->get_permission(
371
+ self::PERMISSION_USER,
372
+ 'admin-users',
373
+ $this->_fs->get_text_inline( 'View Basic Profile Info', 'permissions-profile' ),
374
+ $this->_fs->get_text_inline( 'Your WordPress user\'s: first & last name, and email address', 'permissions-profile_desc' ),
375
+ $this->_fs->get_text_inline( 'Never miss important updates, get security warnings before they become public knowledge, and receive notifications about special offers and awesome new features.', 'permissions-profile_tooltip' ),
376
+ 5,
377
+ false,
378
+ true,
379
+ $load_default_from_storage
380
+ );
381
+ }
382
+
383
+ #endregion
384
+
385
+ #--------------------------------------------------------------------------------
386
+ #region Optional Permissions
387
+ #--------------------------------------------------------------------------------
388
+
389
+ /**
390
+ * @return array[]
391
+ */
392
+ function get_newsletter_permission() {
393
+ return $this->get_permission(
394
+ self::PERMISSION_NEWSLETTER,
395
+ 'email-alt',
396
+ $this->_fs->get_text_inline( 'Newsletter', 'permissions-newsletter' ),
397
+ $this->_fs->get_text_inline( 'Updates, announcements, marketing, no spam', 'permissions-newsletter_desc' ),
398
+ '',
399
+ 15
400
+ );
401
+ }
402
+
403
+ #endregion
404
+
405
+ #--------------------------------------------------------------------------------
406
+ #region Permissions Storage
407
+ #--------------------------------------------------------------------------------
408
+
409
+ /**
410
+ * @param int|null $blog_id
411
+ *
412
+ * @return bool
413
+ */
414
+ function is_extensions_tracking_allowed( $blog_id = null ) {
415
+ return $this->is_permission_allowed( self::PERMISSION_EXTENSIONS, ! $this->_fs->is_premium(), $blog_id );
416
+ }
417
+
418
+ /**
419
+ * @param int|null $blog_id
420
+ *
421
+ * @return bool
422
+ */
423
+ function is_essentials_tracking_allowed( $blog_id = null ) {
424
+ return $this->is_permission_allowed( self::PERMISSION_ESSENTIALS, true, $blog_id );
425
+ }
426
+
427
+ /**
428
+ * @param bool $default
429
+ *
430
+ * @return bool
431
+ */
432
+ function is_diagnostic_tracking_allowed( $default = true ) {
433
+ return $this->_fs->is_premium() ?
434
+ $this->is_permission_allowed( self::PERMISSION_DIAGNOSTIC, $default ) :
435
+ $this->is_permission_allowed( self::PERMISSION_SITE, $default );
436
+ }
437
+
438
+ /**
439
+ * @param int|null $blog_id
440
+ *
441
+ * @return bool
442
+ */
443
+ function is_homepage_url_tracking_allowed( $blog_id = null ) {
444
+ return $this->is_permission_allowed( $this->get_site_permission_name(), true, $blog_id );
445
+ }
446
+
447
+ /**
448
+ * @param int|null $blog_id
449
+ *
450
+ * @return bool
451
+ */
452
+ function update_site_tracking( $is_enabled, $blog_id = null, $only_if_not_set = false ) {
453
+ $permissions = $this->get_site_tracking_permission_names();
454
+
455
+ $result = true;
456
+ foreach ( $permissions as $permission ) {
457
+ if ( ! $only_if_not_set || ! $this->is_permission_set( $permission, $blog_id ) ) {
458
+ $result = ( $result && $this->update_permission_tracking_flag( $permission, $is_enabled, $blog_id ) );
459
+ }
460
+ }
461
+
462
+ return $result;
463
+ }
464
+
465
+ /**
466
+ * @param string $permission
467
+ * @param bool $default
468
+ * @param int|null $blog_id
469
+ *
470
+ * @return bool
471
+ */
472
+ function is_permission_allowed( $permission, $default = false, $blog_id = null ) {
473
+ if ( ! self::is_supported_permission( $permission ) ) {
474
+ return $default;
475
+ }
476
+
477
+ return $this->is_permission( $permission, true, $blog_id );
478
+ }
479
+
480
+ /**
481
+ * @param string $permission
482
+ * @param bool $is_allowed
483
+ * @param int|null $blog_id
484
+ *
485
+ * @return bool
486
+ */
487
+ function is_permission( $permission, $is_allowed, $blog_id = null ) {
488
+ if ( ! self::is_supported_permission( $permission ) ) {
489
+ return false;
490
+ }
491
+
492
+ $tag = "is_{$permission}_tracking_allowed";
493
+
494
+ return ( $is_allowed === $this->_fs->apply_filters(
495
+ $tag,
496
+ $this->_storage->get(
497
+ $tag,
498
+ $this->get_permission_default( $permission ),
499
+ $blog_id,
500
+ FS_Storage::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED
501
+ )
502
+ ) );
503
+ }
504
+
505
+ /**
506
+ * @param string $permission
507
+ * @param int|null $blog_id
508
+ *
509
+ * @return bool
510
+ */
511
+ function is_permission_set( $permission, $blog_id = null ) {
512
+ $tag = "is_{$permission}_tracking_allowed";
513
+
514
+ $permission = $this->_storage->get(
515
+ $tag,
516
+ null,
517
+ $blog_id,
518
+ FS_Storage::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED
519
+ );
520
+
521
+ return is_bool( $permission );
522
+ }
523
+
524
+ /**
525
+ * @param string[] $permissions
526
+ * @param bool $is_allowed
527
+ *
528
+ * @return bool `true` if all given permissions are in sync with `$is_allowed`.
529
+ */
530
+ function are_permissions( $permissions, $is_allowed, $blog_id = null ) {
531
+ foreach ( $permissions as $permission ) {
532
+ if ( ! $this->is_permission( $permission, $is_allowed, $blog_id ) ) {
533
+ return false;
534
+ }
535
+ }
536
+
537
+ return true;
538
+ }
539
+
540
+ /**
541
+ * @param string $permission
542
+ * @param bool $is_enabled
543
+ * @param int|null $blog_id
544
+ *
545
+ * @return bool `false` if permission not supported or `$is_enabled` is not a boolean.
546
+ */
547
+ function update_permission_tracking_flag( $permission, $is_enabled, $blog_id = null ) {
548
+ if ( is_bool( $is_enabled ) && self::is_supported_permission( $permission ) ) {
549
+ $this->_storage->store(
550
+ "is_{$permission}_tracking_allowed",
551
+ $is_enabled,
552
+ $blog_id,
553
+ FS_Storage::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED
554
+ );
555
+
556
+ return true;
557
+ }
558
+
559
+ return false;
560
+ }
561
+
562
+ /**
563
+ * @param array<string,bool> $permissions
564
+ */
565
+ function update_permissions_tracking_flag( $permissions ) {
566
+ foreach ( $permissions as $permission => $is_enabled ) {
567
+ $this->update_permission_tracking_flag( $permission, $is_enabled );
568
+ }
569
+ }
570
+
571
+ #endregion
572
+
573
+
574
+ /**
575
+ * @param string $permission
576
+ *
577
+ * @return bool
578
+ */
579
+ function get_permission_default( $permission ) {
580
+ if (
581
+ $this->_fs->is_premium() &&
582
+ self::PERMISSION_EXTENSIONS === $permission
583
+ ) {
584
+ return false;
585
+ }
586
+
587
+ // All permissions except for the extensions in paid version are on by default when the user opts in to usage tracking.
588
+ return true;
589
+ }
590
+
591
+ /**
592
+ * @return string
593
+ */
594
+ function get_site_permission_name() {
595
+ return $this->_fs->is_premium() ?
596
+ self::PERMISSION_ESSENTIALS :
597
+ self::PERMISSION_SITE;
598
+ }
599
+
600
+ /**
601
+ * @return string[]
602
+ */
603
+ function get_site_tracking_permission_names() {
604
+ return $this->_fs->is_premium() ?
605
+ array(
606
+ FS_Permission_Manager::PERMISSION_ESSENTIALS,
607
+ FS_Permission_Manager::PERMISSION_EVENTS,
608
+ ) :
609
+ array( FS_Permission_Manager::PERMISSION_SITE );
610
+ }
611
+
612
+ #--------------------------------------------------------------------------------
613
+ #region Rendering
614
+ #--------------------------------------------------------------------------------
615
+
616
+ /**
617
+ * @param array $permission
618
+ */
619
+ function render_permission( array $permission ) {
620
+ fs_require_template( 'connect/permission.php', $permission );
621
+ }
622
+
623
+ /**
624
+ * @param array $permissions_group
625
+ */
626
+ function render_permissions_group( array $permissions_group ) {
627
+ $permissions_group[ 'fs' ] = $this->_fs;
628
+
629
+ fs_require_template( 'connect/permissions-group.php', $permissions_group );
630
+ }
631
+
632
+ function require_permissions_js() {
633
+ fs_require_once_template( 'js/permissions.php', $params );
634
+ }
635
+
636
+ #endregion
637
+
638
+ #--------------------------------------------------------------------------------
639
+ #region Helper Methods
640
+ #--------------------------------------------------------------------------------
641
+
642
+ /**
643
+ * @param string $id
644
+ * @param string $dashicon
645
+ * @param string $label
646
+ * @param string $desc
647
+ * @param string $tooltip
648
+ * @param int $priority
649
+ * @param bool $is_optional
650
+ * @param bool $is_on_by_default
651
+ * @param bool $load_from_storage
652
+ *
653
+ * @return array
654
+ */
655
+ private function get_permission(
656
+ $id,
657
+ $dashicon,
658
+ $label,
659
+ $desc,
660
+ $tooltip = '',
661
+ $priority = 10,
662
+ $is_optional = false,
663
+ $is_on_by_default = true,
664
+ $load_from_storage = false
665
+ ) {
666
+ $is_on = $load_from_storage ?
667
+ $this->is_permission_allowed( $id, $is_on_by_default ) :
668
+ $is_on_by_default;
669
+
670
+ return array(
671
+ 'id' => $id,
672
+ 'icon-class' => $this->_fs->apply_filters( "permission_{$id}_icon", "dashicons dashicons-{$dashicon}" ),
673
+ 'label' => $this->_fs->apply_filters( "permission_{$id}_label", $label ),
674
+ 'tooltip' => $this->_fs->apply_filters( "permission_{$id}_tooltip", $tooltip ),
675
+ 'desc' => $this->_fs->apply_filters( "permission_{$id}_desc", $desc ),
676
+ 'priority' => $this->_fs->apply_filters( "permission_{$id}_priority", $priority ),
677
+ 'optional' => $is_optional,
678
+ 'default' => $this->_fs->apply_filters( "permission_{$id}_default", $is_on ),
679
+ );
680
+ }
681
+
682
+ /**
683
+ * @param array $permissions
684
+ *
685
+ * @return array[]
686
+ */
687
+ private function get_sorted_permissions_by_priority( array $permissions ) {
688
+ // Allow filtering of the permissions list.
689
+ $permissions = $this->_fs->apply_filters( 'permission_list', $permissions );
690
+
691
+ // Sort by priority.
692
+ uasort( $permissions, 'fs_sort_by_priority' );
693
+
694
+ return $permissions;
695
+ }
696
+
697
+ #endregion
698
+ }
freemius/includes/managers/class-fs-plugin-manager.php CHANGED
@@ -211,10 +211,23 @@
211
  * @return bool|\FS_Plugin
212
  */
213
  function get() {
214
- return isset( $this->_module ) ?
215
- $this->_module :
216
- false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  }
218
-
219
-
220
  }
211
  * @return bool|\FS_Plugin
212
  */
213
  function get() {
214
+ if ( isset( $this->_module ) ) {
215
+ return $this->_module;
216
+ }
217
+
218
+ if ( empty( $this->_module_id ) ) {
219
+ return false;
220
+ }
221
+
222
+ /**
223
+ * Return an FS_Plugin entity that has its `id` and `is_live` properties set (`is_live` is initialized in the FS_Plugin constructor) to avoid triggering an error that is relevant to these properties when the FS_Plugin entity is used before the `parse_settings()` method is called. This can happen when creating a regular WordPress site by cloning a subsite of a multisite network and the data that is stored in the network-level storage is not cloned.
224
+ *
225
+ * @author Leo Fajardo (@leorw)
226
+ * @since 2.5.0
227
+ */
228
+ $plugin = new FS_Plugin();
229
+ $plugin->id = $this->_module_id;
230
+
231
+ return $plugin;
232
  }
 
 
233
  }
freemius/includes/sdk/FreemiusBase.php CHANGED
@@ -46,174 +46,172 @@
46
  require_once FS_SDK__EXCEPTIONS_PATH . $e . '.php';
47
  }
48
 
49
- if ( class_exists( 'Freemius_Api_Base' ) ) {
50
- return;
51
- }
52
-
53
- abstract class Freemius_Api_Base {
54
- const VERSION = '1.0.4';
55
- const FORMAT = 'json';
56
-
57
- protected $_id;
58
- protected $_public;
59
- protected $_secret;
60
- protected $_scope;
61
- protected $_isSandbox;
62
-
63
- /**
64
- * @param string $pScope 'app', 'developer', 'plugin', 'user' or 'install'.
65
- * @param number $pID Element's id.
66
- * @param string $pPublic Public key.
67
- * @param string $pSecret Element's secret key.
68
- * @param bool $pIsSandbox Whether or not to run API in sandbox mode.
69
- */
70
- public function Init( $pScope, $pID, $pPublic, $pSecret, $pIsSandbox = false ) {
71
- $this->_id = $pID;
72
- $this->_public = $pPublic;
73
- $this->_secret = $pSecret;
74
- $this->_scope = $pScope;
75
- $this->_isSandbox = $pIsSandbox;
76
- }
77
-
78
- public function IsSandbox() {
79
- return $this->_isSandbox;
80
- }
81
-
82
- function CanonizePath( $pPath ) {
83
- $pPath = trim( $pPath, '/' );
84
- $query_pos = strpos( $pPath, '?' );
85
- $query = '';
86
-
87
- if ( false !== $query_pos ) {
88
- $query = substr( $pPath, $query_pos );
89
- $pPath = substr( $pPath, 0, $query_pos );
90
- }
91
-
92
- // Trim '.json' suffix.
93
- $format_length = strlen( '.' . self::FORMAT );
94
- $start = $format_length * ( - 1 ); //negative
95
- if ( substr( strtolower( $pPath ), $start ) === ( '.' . self::FORMAT ) ) {
96
- $pPath = substr( $pPath, 0, strlen( $pPath ) - $format_length );
97
- }
98
-
99
- switch ( $this->_scope ) {
100
- case 'app':
101
- $base = '/apps/' . $this->_id;
102
- break;
103
- case 'developer':
104
- $base = '/developers/' . $this->_id;
105
- break;
106
- case 'user':
107
- $base = '/users/' . $this->_id;
108
- break;
109
- case 'plugin':
110
- $base = '/plugins/' . $this->_id;
111
- break;
112
- case 'install':
113
- $base = '/installs/' . $this->_id;
114
- break;
115
- default:
116
- throw new Freemius_Exception( 'Scope not implemented.' );
117
- }
118
-
119
- return '/v' . FS_API__VERSION . $base .
120
- ( ! empty( $pPath ) ? '/' : '' ) . $pPath .
121
- ( ( false === strpos( $pPath, '.' ) ) ? '.' . self::FORMAT : '' ) . $query;
122
- }
123
-
124
- abstract function MakeRequest( $pCanonizedPath, $pMethod = 'GET', $pParams = array() );
125
-
126
- /**
127
- * @param string $pPath
128
- * @param string $pMethod
129
- * @param array $pParams
130
- *
131
- * @return object[]|object|null
132
- */
133
- private function _Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
134
- $pMethod = strtoupper( $pMethod );
135
-
136
- try {
137
- $result = $this->MakeRequest( $pPath, $pMethod, $pParams );
138
- } catch ( Freemius_Exception $e ) {
139
- // Map to error object.
140
- $result = (object) $e->getResult();
141
- } catch ( Exception $e ) {
142
- // Map to error object.
143
- $result = (object) array(
144
- 'error' => (object) array(
145
- 'type' => 'Unknown',
146
- 'message' => $e->getMessage() . ' (' . $e->getFile() . ': ' . $e->getLine() . ')',
147
- 'code' => 'unknown',
148
- 'http' => 402
149
- )
150
- );
151
- }
152
-
153
- return $result;
154
- }
155
-
156
- public function Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
157
- return $this->_Api( $this->CanonizePath( $pPath ), $pMethod, $pParams );
158
- }
159
-
160
- /**
161
- * Base64 decoding that does not need to be urldecode()-ed.
162
- *
163
- * Exactly the same as PHP base64 encode except it uses
164
- * `-` instead of `+`
165
- * `_` instead of `/`
166
- * No padded =
167
- *
168
- * @param string $input Base64UrlEncoded() string
169
- *
170
- * @return string
171
- */
172
- protected static function Base64UrlDecode( $input ) {
173
- /**
174
- * IMPORTANT NOTE:
175
- * This is a hack suggested by @otto42 and @greenshady from
176
- * the theme's review team. The usage of base64 for API
177
- * signature encoding was approved in a Slack meeting
178
- * held on Tue (10/25 2016).
179
- *
180
- * @todo Remove this hack once the base64 error is removed from the Theme Check.
181
- *
182
- * @since 1.2.2
183
- * @author Vova Feldman (@svovaf)
184
- */
185
- $fn = 'base64' . '_decode';
186
- return $fn( strtr( $input, '-_', '+/' ) );
187
- }
188
-
189
- /**
190
- * Base64 encoding that does not need to be urlencode()ed.
191
- *
192
- * Exactly the same as base64 encode except it uses
193
- * `-` instead of `+
194
- * `_` instead of `/`
195
- *
196
- * @param string $input string
197
- *
198
- * @return string Base64 encoded string
199
- */
200
- protected static function Base64UrlEncode( $input ) {
201
- /**
202
- * IMPORTANT NOTE:
203
- * This is a hack suggested by @otto42 and @greenshady from
204
- * the theme's review team. The usage of base64 for API
205
- * signature encoding was approved in a Slack meeting
206
- * held on Tue (10/25 2016).
207
- *
208
- * @todo Remove this hack once the base64 error is removed from the Theme Check.
209
- *
210
- * @since 1.2.2
211
- * @author Vova Feldman (@svovaf)
212
- */
213
- $fn = 'base64' . '_encode';
214
- $str = strtr( $fn( $input ), '+/', '-_' );
215
- $str = str_replace( '=', '', $str );
216
-
217
- return $str;
218
- }
219
- }
46
  require_once FS_SDK__EXCEPTIONS_PATH . $e . '.php';
47
  }
48
 
49
+ if ( ! class_exists( 'Freemius_Api_Base' ) ) {
50
+ abstract class Freemius_Api_Base {
51
+ const VERSION = '1.0.4';
52
+ const FORMAT = 'json';
53
+
54
+ protected $_id;
55
+ protected $_public;
56
+ protected $_secret;
57
+ protected $_scope;
58
+ protected $_isSandbox;
59
+
60
+ /**
61
+ * @param string $pScope 'app', 'developer', 'plugin', 'user' or 'install'.
62
+ * @param number $pID Element's id.
63
+ * @param string $pPublic Public key.
64
+ * @param string $pSecret Element's secret key.
65
+ * @param bool $pIsSandbox Whether or not to run API in sandbox mode.
66
+ */
67
+ public function Init( $pScope, $pID, $pPublic, $pSecret, $pIsSandbox = false ) {
68
+ $this->_id = $pID;
69
+ $this->_public = $pPublic;
70
+ $this->_secret = $pSecret;
71
+ $this->_scope = $pScope;
72
+ $this->_isSandbox = $pIsSandbox;
73
+ }
74
+
75
+ public function IsSandbox() {
76
+ return $this->_isSandbox;
77
+ }
78
+
79
+ function CanonizePath( $pPath ) {
80
+ $pPath = trim( $pPath, '/' );
81
+ $query_pos = strpos( $pPath, '?' );
82
+ $query = '';
83
+
84
+ if ( false !== $query_pos ) {
85
+ $query = substr( $pPath, $query_pos );
86
+ $pPath = substr( $pPath, 0, $query_pos );
87
+ }
88
+
89
+ // Trim '.json' suffix.
90
+ $format_length = strlen( '.' . self::FORMAT );
91
+ $start = $format_length * ( - 1 ); //negative
92
+ if ( substr( strtolower( $pPath ), $start ) === ( '.' . self::FORMAT ) ) {
93
+ $pPath = substr( $pPath, 0, strlen( $pPath ) - $format_length );
94
+ }
95
+
96
+ switch ( $this->_scope ) {
97
+ case 'app':
98
+ $base = '/apps/' . $this->_id;
99
+ break;
100
+ case 'developer':
101
+ $base = '/developers/' . $this->_id;
102
+ break;
103
+ case 'user':
104
+ $base = '/users/' . $this->_id;
105
+ break;
106
+ case 'plugin':
107
+ $base = '/plugins/' . $this->_id;
108
+ break;
109
+ case 'install':
110
+ $base = '/installs/' . $this->_id;
111
+ break;
112
+ default:
113
+ throw new Freemius_Exception( 'Scope not implemented.' );
114
+ }
115
+
116
+ return '/v' . FS_API__VERSION . $base .
117
+ ( ! empty( $pPath ) ? '/' : '' ) . $pPath .
118
+ ( ( false === strpos( $pPath, '.' ) ) ? '.' . self::FORMAT : '' ) . $query;
119
+ }
120
+
121
+ abstract function MakeRequest( $pCanonizedPath, $pMethod = 'GET', $pParams = array() );
122
+
123
+ /**
124
+ * @param string $pPath
125
+ * @param string $pMethod
126
+ * @param array $pParams
127
+ *
128
+ * @return object[]|object|null
129
+ */
130
+ private function _Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
131
+ $pMethod = strtoupper( $pMethod );
132
+
133
+ try {
134
+ $result = $this->MakeRequest( $pPath, $pMethod, $pParams );
135
+ } catch ( Freemius_Exception $e ) {
136
+ // Map to error object.
137
+ $result = (object) $e->getResult();
138
+ } catch ( Exception $e ) {
139
+ // Map to error object.
140
+ $result = (object) array(
141
+ 'error' => (object) array(
142
+ 'type' => 'Unknown',
143
+ 'message' => $e->getMessage() . ' (' . $e->getFile() . ': ' . $e->getLine() . ')',
144
+ 'code' => 'unknown',
145
+ 'http' => 402
146
+ )
147
+ );
148
+ }
149
+
150
+ return $result;
151
+ }
152
+
153
+ public function Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
154
+ return $this->_Api( $this->CanonizePath( $pPath ), $pMethod, $pParams );
155
+ }
156
+
157
+ /**
158
+ * Base64 decoding that does not need to be urldecode()-ed.
159
+ *
160
+ * Exactly the same as PHP base64 encode except it uses
161
+ * `-` instead of `+`
162
+ * `_` instead of `/`
163
+ * No padded =
164
+ *
165
+ * @param string $input Base64UrlEncoded() string
166
+ *
167
+ * @return string
168
+ */
169
+ protected static function Base64UrlDecode( $input ) {
170
+ /**
171
+ * IMPORTANT NOTE:
172
+ * This is a hack suggested by @otto42 and @greenshady from
173
+ * the theme's review team. The usage of base64 for API
174
+ * signature encoding was approved in a Slack meeting
175
+ * held on Tue (10/25 2016).
176
+ *
177
+ * @todo Remove this hack once the base64 error is removed from the Theme Check.
178
+ *
179
+ * @since 1.2.2
180
+ * @author Vova Feldman (@svovaf)
181
+ */
182
+ $fn = 'base64' . '_decode';
183
+ return $fn( strtr( $input, '-_', '+/' ) );
184
+ }
185
+
186
+ /**
187
+ * Base64 encoding that does not need to be urlencode()ed.
188
+ *
189
+ * Exactly the same as base64 encode except it uses
190
+ * `-` instead of `+
191
+ * `_` instead of `/`
192
+ *
193
+ * @param string $input string
194
+ *
195
+ * @return string Base64 encoded string
196
+ */
197
+ protected static function Base64UrlEncode( $input ) {
198
+ /**
199
+ * IMPORTANT NOTE:
200
+ * This is a hack suggested by @otto42 and @greenshady from
201
+ * the theme's review team. The usage of base64 for API
202
+ * signature encoding was approved in a Slack meeting
203
+ * held on Tue (10/25 2016).
204
+ *
205
+ * @todo Remove this hack once the base64 error is removed from the Theme Check.
206
+ *
207
+ * @since 1.2.2
208
+ * @author Vova Feldman (@svovaf)
209
+ */
210
+ $fn = 'base64' . '_encode';
211
+ $str = strtr( $fn( $input ), '+/', '-_' );
212
+ $str = str_replace( '=', '', $str );
213
+
214
+ return $str;
215
+ }
216
+ }
217
+ }
 
 
freemius/includes/sdk/FreemiusWordPress.php CHANGED
@@ -85,10 +85,7 @@
85
  define( 'FS_API__SANDBOX_ADDRESS', '://sandbox-api.freemius.com' );
86
  }
87
 
88
- if ( class_exists( 'Freemius_Api_WordPress' ) ) {
89
- return;
90
- }
91
-
92
  class Freemius_Api_WordPress extends Freemius_Api_Base {
93
  private static $_logger = array();
94
 
@@ -305,6 +302,8 @@
305
  * @return mixed
306
  */
307
  private static function ExecuteRequest( $pUrl, &$pWPRemoteArgs ) {
 
 
308
  $start = microtime( true );
309
 
310
  $response = wp_remote_request( $pUrl, $pWPRemoteArgs );
@@ -327,7 +326,7 @@
327
  $response['body'] :
328
  json_encode( $response->get_error_messages() ),
329
  'code' => ! $is_http_error ? $response['response']['code'] : null,
330
- 'backtrace' => debug_backtrace(),
331
  );
332
  }
333
 
@@ -713,3 +712,4 @@
713
 
714
  #endregion
715
  }
 
85
  define( 'FS_API__SANDBOX_ADDRESS', '://sandbox-api.freemius.com' );
86
  }
87
 
88
+ if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
 
 
 
89
  class Freemius_Api_WordPress extends Freemius_Api_Base {
90
  private static $_logger = array();
91
 
302
  * @return mixed
303
  */
304
  private static function ExecuteRequest( $pUrl, &$pWPRemoteArgs ) {
305
+ $bt = debug_backtrace();
306
+
307
  $start = microtime( true );
308
 
309
  $response = wp_remote_request( $pUrl, $pWPRemoteArgs );
326
  $response['body'] :
327
  json_encode( $response->get_error_messages() ),
328
  'code' => ! $is_http_error ? $response['response']['code'] : null,
329
+ 'backtrace' => $bt,
330
  );
331
  }
332
 
712
 
713
  #endregion
714
  }
715
+ }
freemius/includes/supplements/fs-migration-2.5.1.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ if ( ! function_exists( 'fs_migrate_251' ) ) {
14
+ function fs_migrate_251( Freemius $fs, $install_by_blog_id ) {
15
+ $permission_manager = FS_Permission_Manager::instance( $fs );
16
+
17
+ /**
18
+ * @var FS_Site $install
19
+ */
20
+ foreach ( $install_by_blog_id as $blog_id => $install ) {
21
+ if ( true === $install->is_disconnected ) {
22
+ $permission_manager->update_site_tracking(
23
+ false,
24
+ ( 0 == $blog_id ) ? null : $blog_id,
25
+ // Update only if permissions are not yet set.
26
+ true
27
+ );
28
+ }
29
+ }
30
+ }
31
+ }
freemius/languages/freemius-cs_CZ.mo CHANGED
Binary file
freemius/languages/freemius-da_DK.mo CHANGED
Binary file
freemius/languages/freemius-de_DE.mo ADDED
Binary file
freemius/languages/freemius-en.mo CHANGED
Binary file
freemius/languages/freemius-es_ES.mo CHANGED
Binary file
freemius/languages/freemius-fr_FR.mo CHANGED
Binary file
freemius/languages/freemius-he_IL.mo CHANGED
Binary file
freemius/languages/freemius-hu_HU.mo CHANGED
Binary file
freemius/languages/freemius-it_IT.mo CHANGED
Binary file
freemius/languages/freemius-ja.mo CHANGED
Binary file
freemius/languages/freemius-nl_NL.mo CHANGED
Binary file
freemius/languages/freemius-ru_RU.mo CHANGED
Binary file
freemius/languages/freemius-ta.mo CHANGED
Binary file
freemius/languages/freemius-zh_CN.mo CHANGED
Binary file
freemius/languages/freemius.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2021 freemius
2
  # This file is distributed under the same license as the freemius package.
3
  msgid ""
4
  msgstr ""
@@ -16,795 +16,807 @@ msgstr ""
16
  "X-Poedit-SourceCharset: UTF-8\n"
17
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18
 
19
- #: includes/class-freemius.php:1919, templates/account.php:912
20
  msgid "An update to a Beta version will replace your installed version of %s with the latest Beta release - use with caution, and not on production sites. You have been warned."
21
  msgstr ""
22
 
23
- #: includes/class-freemius.php:1926
24
  msgid "Would you like to proceed with the update?"
25
  msgstr ""
26
 
27
- #: includes/class-freemius.php:2138
28
  msgid "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
29
  msgstr ""
30
 
31
- #: includes/class-freemius.php:2140
32
  msgid "Error"
33
  msgstr ""
34
 
35
- #: includes/class-freemius.php:2540
36
  msgid "I found a better %s"
37
  msgstr ""
38
 
39
- #: includes/class-freemius.php:2542
40
  msgid "What's the %s's name?"
41
  msgstr ""
42
 
43
- #: includes/class-freemius.php:2548
44
- msgid "It's a temporary %s. I'm just debugging an issue."
45
  msgstr ""
46
 
47
- #: includes/class-freemius.php:2550
48
  msgid "Deactivation"
49
  msgstr ""
50
 
51
- #: includes/class-freemius.php:2551
52
  msgid "Theme Switch"
53
  msgstr ""
54
 
55
- #: includes/class-freemius.php:2560, templates/forms/resend-key.php:24, templates/forms/user-change.php:29
56
  msgid "Other"
57
  msgstr ""
58
 
59
- #: includes/class-freemius.php:2568
60
  msgid "I no longer need the %s"
61
  msgstr ""
62
 
63
- #: includes/class-freemius.php:2575
64
  msgid "I only needed the %s for a short period"
65
  msgstr ""
66
 
67
- #: includes/class-freemius.php:2581
68
  msgid "The %s broke my site"
69
  msgstr ""
70
 
71
- #: includes/class-freemius.php:2588
72
  msgid "The %s suddenly stopped working"
73
  msgstr ""
74
 
75
- #: includes/class-freemius.php:2598
76
  msgid "I can't pay for it anymore"
77
  msgstr ""
78
 
79
- #: includes/class-freemius.php:2600
80
  msgid "What price would you feel comfortable paying?"
81
  msgstr ""
82
 
83
- #: includes/class-freemius.php:2606
84
  msgid "I don't like to share my information with you"
85
  msgstr ""
86
 
87
- #: includes/class-freemius.php:2627
88
  msgid "The %s didn't work"
89
  msgstr ""
90
 
91
- #: includes/class-freemius.php:2637
92
  msgid "I couldn't understand how to make it work"
93
  msgstr ""
94
 
95
- #: includes/class-freemius.php:2645
96
  msgid "The %s is great, but I need specific feature that you don't support"
97
  msgstr ""
98
 
99
- #: includes/class-freemius.php:2647
100
  msgid "What feature?"
101
  msgstr ""
102
 
103
- #: includes/class-freemius.php:2651
104
  msgid "The %s is not working"
105
  msgstr ""
106
 
107
- #: includes/class-freemius.php:2653
108
  msgid "Kindly share what didn't work so we can fix it for future users..."
109
  msgstr ""
110
 
111
- #: includes/class-freemius.php:2657
112
  msgid "It's not what I was looking for"
113
  msgstr ""
114
 
115
- #: includes/class-freemius.php:2659
116
  msgid "What you've been looking for?"
117
  msgstr ""
118
 
119
- #: includes/class-freemius.php:2663
120
  msgid "The %s didn't work as expected"
121
  msgstr ""
122
 
123
- #: includes/class-freemius.php:2665
124
  msgid "What did you expect?"
125
  msgstr ""
126
 
127
- #: includes/class-freemius.php:3520, templates/debug.php:20
128
  msgid "Freemius Debug"
129
  msgstr ""
130
 
131
- #: includes/class-freemius.php:4272
132
  msgid "I don't know what is cURL or how to install it, help me!"
133
  msgstr ""
134
 
135
- #: includes/class-freemius.php:4274
136
  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."
137
  msgstr ""
138
 
139
- #: includes/class-freemius.php:4281
140
  msgid "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
141
  msgstr ""
142
 
143
- #: includes/class-freemius.php:4386
144
  msgid "Yes - do your thing"
145
  msgstr ""
146
 
147
- #: includes/class-freemius.php:4391
148
  msgid "No - just deactivate"
149
  msgstr ""
150
 
151
- #: includes/class-freemius.php:4436, includes/class-freemius.php:4930, includes/class-freemius.php:6191, includes/class-freemius.php:13368, includes/class-freemius.php:14110, includes/class-freemius.php:17542, includes/class-freemius.php:17647, includes/class-freemius.php:17822, includes/class-freemius.php:20056, includes/class-freemius.php:20414, includes/class-freemius.php:20424, includes/class-freemius.php:21109, includes/class-freemius.php:22015, includes/class-freemius.php:22148, includes/class-freemius.php:22304, templates/add-ons.php:57
152
  msgctxt "exclamation"
153
  msgid "Oops"
154
  msgstr ""
155
 
156
- #: includes/class-freemius.php:4505
157
  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."
158
  msgstr ""
159
 
160
- #: includes/class-freemius.php:4927
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  msgctxt "addonX cannot run without pluginY"
162
  msgid "%s cannot run without %s."
163
  msgstr ""
164
 
165
- #: includes/class-freemius.php:4928
166
  msgctxt "addonX cannot run..."
167
  msgid "%s cannot run without the plugin."
168
  msgstr ""
169
 
170
- #: includes/class-freemius.php:5127, includes/class-freemius.php:5152, includes/class-freemius.php:21180
171
- msgid "Unexpected API error. Please contact the %s's author with the following error."
172
  msgstr ""
173
 
174
- #: includes/class-freemius.php:5857
175
  msgid "Premium %s version was successfully activated."
176
  msgstr ""
177
 
178
- #: includes/class-freemius.php:5869, includes/class-freemius.php:7774
179
  msgctxt "Used to express elation, enthusiasm, or triumph (especially in electronic communication)."
180
  msgid "W00t"
181
  msgstr ""
182
 
183
- #: includes/class-freemius.php:5884
184
  msgid "You have a %s license."
185
  msgstr ""
186
 
187
- #: includes/class-freemius.php:5888, includes/class-freemius.php:16947, includes/class-freemius.php:16958, includes/class-freemius.php:20325, includes/class-freemius.php:20689, includes/class-freemius.php:20758, includes/class-freemius.php:20930
188
- msgctxt "interjection expressing joy or exuberance"
189
- msgid "Yee-haw"
190
- msgstr ""
191
-
192
- #: includes/class-freemius.php:6174
193
  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."
194
  msgstr ""
195
 
196
- #: includes/class-freemius.php:6178
197
  msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
198
  msgstr ""
199
 
200
- #: includes/class-freemius.php:6187, templates/add-ons.php:186, templates/account/partials/addon.php:381
201
  msgid "More information about %s"
202
  msgstr ""
203
 
204
- #: includes/class-freemius.php:6188
205
  msgid "Purchase License"
206
  msgstr ""
207
 
208
- #: includes/class-freemius.php:7125, templates/connect.php:171
209
  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 %s."
210
  msgstr ""
211
 
212
- #: includes/class-freemius.php:7129
213
  msgid "start the trial"
214
  msgstr ""
215
 
216
- #: includes/class-freemius.php:7130, templates/connect.php:175
217
  msgid "complete the install"
218
  msgstr ""
219
 
220
- #: includes/class-freemius.php:7249
221
  msgid "You are just one step away - %s"
222
  msgstr ""
223
 
224
- #: includes/class-freemius.php:7252
225
  msgctxt "%s - plugin name. As complete \"PluginX\" activation now"
226
  msgid "Complete \"%s\" Activation Now"
227
  msgstr ""
228
 
229
- #: includes/class-freemius.php:7334
230
  msgid "We made a few tweaks to the %s, %s"
231
  msgstr ""
232
 
233
- #: includes/class-freemius.php:7338
234
  msgid "Opt in to make \"%s\" better!"
235
  msgstr ""
236
 
237
- #: includes/class-freemius.php:7773
238
  msgid "The upgrade of %s was successfully completed."
239
  msgstr ""
240
 
241
- #: includes/class-freemius.php:10255, includes/class-fs-plugin-updater.php:1087, includes/class-fs-plugin-updater.php:1282, includes/class-fs-plugin-updater.php:1289, templates/auto-installation.php:32
242
  msgid "Add-On"
243
  msgstr ""
244
 
245
- #: includes/class-freemius.php:10257, templates/account.php:394, templates/account.php:402, templates/debug.php:358, templates/debug.php:549
246
  msgid "Plugin"
247
  msgstr ""
248
 
249
- #: includes/class-freemius.php:10258, templates/account.php:395, templates/account.php:403, templates/debug.php:358, templates/debug.php:549, templates/forms/deactivation/form.php:71
250
  msgid "Theme"
251
  msgstr ""
252
 
253
- #: includes/class-freemius.php:13188
254
  msgid "An unknown error has occurred while trying to toggle the license's white-label mode."
255
  msgstr ""
256
 
257
- #: includes/class-freemius.php:13202
258
  msgid "Your %s license was flagged as white-labeled to hide sensitive information from the WP Admin (e.g. your email, license key, prices, billing address & invoices). If you ever wish to revert it back, you can easily do it through your %s. If this was a mistake you can also %s."
259
  msgstr ""
260
 
261
- #: includes/class-freemius.php:13207
262
  msgid "User Dashboard"
263
  msgstr ""
264
 
265
- #: includes/class-freemius.php:13208
266
  msgid "revert it now"
267
  msgstr ""
268
 
269
- #: includes/class-freemius.php:13266
270
  msgid "An unknown error has occurred while trying to set the user's beta mode."
271
  msgstr ""
272
 
273
- #: includes/class-freemius.php:13339
274
  msgid "Invalid new user ID or email address."
275
  msgstr ""
276
 
277
- #: includes/class-freemius.php:13369, includes/class-freemius.php:22259
278
  msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
279
  msgstr ""
280
 
281
- #: includes/class-freemius.php:13370, includes/class-freemius.php:22260
282
  msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
283
  msgstr ""
284
 
285
- #: includes/class-freemius.php:13377, includes/class-freemius.php:22267
286
  msgid "Change Ownership"
287
  msgstr ""
288
 
289
- #: includes/class-freemius.php:13977
290
  msgid "Invalid site details collection."
291
  msgstr ""
292
 
293
- #: includes/class-freemius.php:14097
294
  msgid "We couldn't find your email address in the system, are you sure it's the right address?"
295
  msgstr ""
296
 
297
- #: includes/class-freemius.php:14099
298
  msgid "We can't see any active licenses associated with that email address, are you sure it's the right address?"
299
  msgstr ""
300
 
301
- #: includes/class-freemius.php:14373
302
- msgid "Account is pending activation."
303
  msgstr ""
304
 
305
- #: includes/class-freemius.php:14485, templates/forms/premium-versions-upgrade-handler.php:47
306
  msgid "Buy a license now"
307
  msgstr ""
308
 
309
- #: includes/class-freemius.php:14497, templates/forms/premium-versions-upgrade-handler.php:46
310
  msgid "Renew your license now"
311
  msgstr ""
312
 
313
- #: includes/class-freemius.php:14501
314
  msgid "%s to access version %s security & feature updates, and support."
315
  msgstr ""
316
 
317
- #: includes/class-freemius.php:16929
318
- msgid "%s activation was successfully completed."
319
  msgstr ""
320
 
321
- #: includes/class-freemius.php:16943
322
  msgid "Your account was successfully activated with the %s plan."
323
  msgstr ""
324
 
325
- #: includes/class-freemius.php:16954, includes/class-freemius.php:20754
326
  msgid "Your trial has been successfully started."
327
  msgstr ""
328
 
329
- #: includes/class-freemius.php:17540, includes/class-freemius.php:17645, includes/class-freemius.php:17820
330
  msgid "Couldn't activate %s."
331
  msgstr ""
332
 
333
- #: includes/class-freemius.php:17541, includes/class-freemius.php:17646, includes/class-freemius.php:17821
334
  msgid "Please contact us with the following message:"
335
  msgstr ""
336
 
337
- #: includes/class-freemius.php:17642, templates/forms/data-debug-mode.php:162
338
  msgid "An unknown error has occurred."
339
  msgstr ""
340
 
341
- #: includes/class-freemius.php:18178, includes/class-freemius.php:23340
342
  msgid "Upgrade"
343
  msgstr ""
344
 
345
- #: includes/class-freemius.php:18184
346
  msgid "Start Trial"
347
  msgstr ""
348
 
349
- #: includes/class-freemius.php:18186
350
  msgid "Pricing"
351
  msgstr ""
352
 
353
- #: includes/class-freemius.php:18266, includes/class-freemius.php:18268
354
  msgid "Affiliation"
355
  msgstr ""
356
 
357
- #: includes/class-freemius.php:18296, includes/class-freemius.php:18298, templates/account.php:242, templates/debug.php:324
358
  msgid "Account"
359
  msgstr ""
360
 
361
- #: includes/class-freemius.php:18312, includes/class-freemius.php:18314, includes/customizer/class-fs-customizer-support-section.php:60
362
  msgid "Contact Us"
363
  msgstr ""
364
 
365
- #: includes/class-freemius.php:18325, includes/class-freemius.php:18327, includes/class-freemius.php:23354, templates/account.php:121, templates/account/partials/addon.php:44
366
  msgid "Add-Ons"
367
  msgstr ""
368
 
369
- #: includes/class-freemius.php:18361
370
  msgctxt "ASCII arrow left icon"
371
  msgid "&#x2190;"
372
  msgstr ""
373
 
374
- #: includes/class-freemius.php:18361
375
  msgctxt "ASCII arrow right icon"
376
  msgid "&#x27a4;"
377
  msgstr ""
378
 
379
- #: includes/class-freemius.php:18363, templates/pricing.php:109
380
  msgctxt "noun"
381
  msgid "Pricing"
382
  msgstr ""
383
 
384
- #: includes/class-freemius.php:18576, includes/customizer/class-fs-customizer-support-section.php:67
385
  msgid "Support Forum"
386
  msgstr ""
387
 
388
- #: includes/class-freemius.php:19550
389
  msgid "Your email has been successfully verified - you are AWESOME!"
390
  msgstr ""
391
 
392
- #: includes/class-freemius.php:19551
393
  msgctxt "a positive response"
394
  msgid "Right on"
395
  msgstr ""
396
 
397
- #: includes/class-freemius.php:20057
398
  msgid "seems like the key you entered doesn't match our records."
399
  msgstr ""
400
 
401
- #: includes/class-freemius.php:20081
402
  msgid "Debug mode was successfully enabled and will be automatically disabled in 60 min. You can also disable it earlier by clicking the \"Stop Debug\" link."
403
  msgstr ""
404
 
405
- #: includes/class-freemius.php:20316
406
  msgid "Your %s Add-on plan was successfully upgraded."
407
  msgstr ""
408
 
409
- #: includes/class-freemius.php:20318
410
  msgid "%s Add-on was successfully purchased."
411
  msgstr ""
412
 
413
- #: includes/class-freemius.php:20321
414
  msgid "Download the latest version"
415
  msgstr ""
416
 
417
- #: includes/class-freemius.php:20407
418
  msgid "Your server is blocking the access to Freemius' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s"
419
  msgstr ""
420
 
421
- #: includes/class-freemius.php:20413, includes/class-freemius.php:20423, includes/class-freemius.php:20889, includes/class-freemius.php:20978
422
  msgid "Error received from the server:"
423
  msgstr ""
424
 
425
- #: includes/class-freemius.php:20423
426
  msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
427
  msgstr ""
428
 
429
- #: includes/class-freemius.php:20651, includes/class-freemius.php:20894, includes/class-freemius.php:20949, includes/class-freemius.php:21056
430
  msgctxt "something somebody says when they are thinking about what you have just said."
431
  msgid "Hmm"
432
  msgstr ""
433
 
434
- #: includes/class-freemius.php:20664
435
  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."
436
  msgstr ""
437
 
438
- #: includes/class-freemius.php:20665, templates/account.php:123, templates/add-ons.php:250, templates/account/partials/addon.php:46
439
  msgctxt "trial period"
440
  msgid "Trial"
441
  msgstr ""
442
 
443
- #: includes/class-freemius.php:20670
444
  msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
445
  msgstr ""
446
 
447
- #: includes/class-freemius.php:20674, includes/class-freemius.php:20733
448
  msgid "Please contact us here"
449
  msgstr ""
450
 
451
- #: includes/class-freemius.php:20685
452
  msgid "Your plan was successfully activated."
453
  msgstr ""
454
 
455
- #: includes/class-freemius.php:20686
456
  msgid "Your plan was successfully upgraded."
457
  msgstr ""
458
 
459
- #: includes/class-freemius.php:20703
460
  msgid "Your plan was successfully changed to %s."
461
  msgstr ""
462
 
463
- #: includes/class-freemius.php:20719
464
  msgid "Your license has expired. You can still continue using the free %s forever."
465
  msgstr ""
466
 
467
- #: includes/class-freemius.php:20721
468
  msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
469
  msgstr ""
470
 
471
- #: includes/class-freemius.php:20729
472
  msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
473
  msgstr ""
474
 
475
- #: includes/class-freemius.php:20742
476
  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."
477
  msgstr ""
478
 
479
- #: includes/class-freemius.php:20768
480
  msgid "Your free trial has expired. You can still continue using all our free features."
481
  msgstr ""
482
 
483
- #: includes/class-freemius.php:20770
484
  msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
485
  msgstr ""
486
 
487
- #: includes/class-freemius.php:20885
488
  msgid "It looks like the license could not be activated."
489
  msgstr ""
490
 
491
- #: includes/class-freemius.php:20927
492
  msgid "Your license was successfully activated."
493
  msgstr ""
494
 
495
- #: includes/class-freemius.php:20953
496
  msgid "It looks like your site currently doesn't have an active license."
497
  msgstr ""
498
 
499
- #: includes/class-freemius.php:20977
500
  msgid "It looks like the license deactivation failed."
501
  msgstr ""
502
 
503
- #: includes/class-freemius.php:21006
504
  msgid "Your %s license was successfully deactivated."
505
  msgstr ""
506
 
507
- #: includes/class-freemius.php:21007
508
  msgid "Your license was successfully deactivated, you are back to the %s plan."
509
  msgstr ""
510
 
511
- #: includes/class-freemius.php:21010
512
  msgid "O.K"
513
  msgstr ""
514
 
515
- #: includes/class-freemius.php:21063
516
  msgid "Seems like we are having some temporary issue with your subscription cancellation. Please try again in few minutes."
517
  msgstr ""
518
 
519
- #: includes/class-freemius.php:21072
520
  msgid "Your subscription was successfully cancelled. Your %s plan license will expire in %s."
521
  msgstr ""
522
 
523
- #: includes/class-freemius.php:21114
524
  msgid "You are already running the %s in a trial mode."
525
  msgstr ""
526
 
527
- #: includes/class-freemius.php:21125
528
  msgid "You already utilized a trial before."
529
  msgstr ""
530
 
531
- #: includes/class-freemius.php:21139
532
  msgid "Plan %s do not exist, therefore, can't start a trial."
533
  msgstr ""
534
 
535
- #: includes/class-freemius.php:21150
536
  msgid "Plan %s does not support a trial period."
537
  msgstr ""
538
 
539
- #: includes/class-freemius.php:21161
540
  msgid "None of the %s's plans supports a trial period."
541
  msgstr ""
542
 
543
- #: includes/class-freemius.php:21211
544
  msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
545
  msgstr ""
546
 
547
- #: includes/class-freemius.php:21247
548
  msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
549
  msgstr ""
550
 
551
- #: includes/class-freemius.php:21266
552
  msgid "Your %s free trial was successfully cancelled."
553
  msgstr ""
554
 
555
- #: includes/class-freemius.php:21582
556
  msgid "Version %s was released."
557
  msgstr ""
558
 
559
- #: includes/class-freemius.php:21582
560
  msgid "Please download %s."
561
  msgstr ""
562
 
563
- #: includes/class-freemius.php:21589
564
  msgid "the latest %s version here"
565
  msgstr ""
566
 
567
- #: includes/class-freemius.php:21594
568
  msgid "New"
569
  msgstr ""
570
 
571
- #: includes/class-freemius.php:21599
572
  msgid "Seems like you got the latest release."
573
  msgstr ""
574
 
575
- #: includes/class-freemius.php:21600
576
  msgid "You are all good!"
577
  msgstr ""
578
 
579
- #: includes/class-freemius.php:21903
580
  msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
581
  msgstr ""
582
 
583
- #: includes/class-freemius.php:22043
584
  msgid "Site successfully opted in."
585
  msgstr ""
586
 
587
- #: includes/class-freemius.php:22044, includes/class-freemius.php:23050
588
  msgid "Awesome"
589
  msgstr ""
590
 
591
- #: includes/class-freemius.php:22060, templates/forms/optout.php:41
592
- msgid "We appreciate your help in making the %s better by letting us track some usage data."
593
  msgstr ""
594
 
595
- #: includes/class-freemius.php:22061
596
  msgid "Thank you!"
597
  msgstr ""
598
 
599
- #: includes/class-freemius.php:22068
600
- msgid "We will no longer be sending any usage data of %s on %s to %s."
 
 
 
 
601
  msgstr ""
602
 
603
- #: includes/class-freemius.php:22226
604
- 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."
605
  msgstr ""
606
 
607
- #: includes/class-freemius.php:22232
608
  msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
609
  msgstr ""
610
 
611
- #: includes/class-freemius.php:22237
612
  msgid "%s is the new owner of the account."
613
  msgstr ""
614
 
615
- #: includes/class-freemius.php:22239
616
  msgctxt "as congratulations"
617
  msgid "Congrats"
618
  msgstr ""
619
 
620
- #: includes/class-freemius.php:22275
621
- msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
622
- msgstr ""
623
-
624
- #: includes/class-freemius.php:22287
625
  msgid "Please provide your full name."
626
  msgstr ""
627
 
628
- #: includes/class-freemius.php:22292
629
  msgid "Your name was successfully updated."
630
  msgstr ""
631
 
632
- #: includes/class-freemius.php:22353
633
  msgid "You have successfully updated your %s."
634
  msgstr ""
635
 
636
- #: includes/class-freemius.php:22412
637
  msgid "Is this your client's site? %s if you wish to hide sensitive info like your email, license key, prices, billing address & invoices from the WP Admin."
638
  msgstr ""
639
 
640
- #: includes/class-freemius.php:22415
641
  msgid "Click here"
642
  msgstr ""
643
 
644
- #: includes/class-freemius.php:22513
 
 
 
 
645
  msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
646
  msgstr ""
647
 
648
- #: includes/class-freemius.php:22514
649
  msgctxt "advance notice of something that will need attention."
650
  msgid "Heads up"
651
  msgstr ""
652
 
653
- #: includes/class-freemius.php:23090
654
  msgctxt "exclamation"
655
  msgid "Hey"
656
  msgstr ""
657
 
658
- #: includes/class-freemius.php:23090
659
  msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
660
  msgstr ""
661
 
662
- #: includes/class-freemius.php:23098
663
  msgid "No commitment for %s days - cancel anytime!"
664
  msgstr ""
665
 
666
- #: includes/class-freemius.php:23099
667
  msgid "No credit card required"
668
  msgstr ""
669
 
670
- #: includes/class-freemius.php:23106, templates/forms/trial-start.php:53
671
  msgctxt "call to action"
672
  msgid "Start free trial"
673
  msgstr ""
674
 
675
- #: includes/class-freemius.php:23183
676
  msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
677
  msgstr ""
678
 
679
- #: includes/class-freemius.php:23192
680
  msgid "Learn more"
681
  msgstr ""
682
 
683
- #: includes/class-freemius.php:23378, templates/account.php:558, templates/account.php:708, templates/connect.php:179, templates/connect.php:461, templates/forms/license-activation.php:27, templates/account/partials/addon.php:321
684
  msgid "Activate License"
685
  msgstr ""
686
 
687
- #: includes/class-freemius.php:23379, templates/account.php:652, templates/account.php:707, templates/account/partials/addon.php:322, templates/account/partials/site.php:271
688
  msgid "Change License"
689
  msgstr ""
690
 
691
- #: includes/class-freemius.php:23500, templates/account/partials/site.php:169
692
  msgid "Opt Out"
693
  msgstr ""
694
 
695
- #: includes/class-freemius.php:23502, includes/class-freemius.php:23508, templates/account/partials/site.php:49, templates/account/partials/site.php:169
696
  msgid "Opt In"
697
  msgstr ""
698
 
699
- #: includes/class-freemius.php:23738
700
  msgid " The paid version of %1$s is already installed. Please activate it to start benefiting the %2$s features. %3$s"
701
  msgstr ""
702
 
703
- #: includes/class-freemius.php:23746
704
  msgid "Activate %s features"
705
  msgstr ""
706
 
707
- #: includes/class-freemius.php:23759
708
  msgid "Please follow these steps to complete the upgrade"
709
  msgstr ""
710
 
711
- #: includes/class-freemius.php:23763
712
  msgid "Download the latest %s version"
713
  msgstr ""
714
 
715
- #: includes/class-freemius.php:23767
716
  msgid "Upload and activate the downloaded version"
717
  msgstr ""
718
 
719
- #: includes/class-freemius.php:23769
720
  msgid "How to upload and activate?"
721
  msgstr ""
722
 
723
- #: includes/class-freemius.php:23903
724
  msgid "%sClick here%s to choose the sites where you'd like to activate the license on."
725
  msgstr ""
726
 
727
- #: includes/class-freemius.php:24072
728
  msgid "Auto installation only works for opted-in users."
729
  msgstr ""
730
 
731
- #: includes/class-freemius.php:24082, includes/class-freemius.php:24115, includes/class-fs-plugin-updater.php:1261, includes/class-fs-plugin-updater.php:1275
732
  msgid "Invalid module ID."
733
  msgstr ""
734
 
735
- #: includes/class-freemius.php:24091, includes/class-fs-plugin-updater.php:1297
736
  msgid "Premium version already active."
737
  msgstr ""
738
 
739
- #: includes/class-freemius.php:24098
740
  msgid "You do not have a valid license to access the premium version."
741
  msgstr ""
742
 
743
- #: includes/class-freemius.php:24105
744
  msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
745
  msgstr ""
746
 
747
- #: includes/class-freemius.php:24123, includes/class-fs-plugin-updater.php:1296
748
  msgid "Premium add-on version already installed."
749
  msgstr ""
750
 
751
- #: includes/class-freemius.php:24473
752
  msgid "View paid features"
753
  msgstr ""
754
 
755
- #: includes/class-freemius.php:24795
756
  msgid "Thank you so much for using %s and its add-ons!"
757
  msgstr ""
758
 
759
- #: includes/class-freemius.php:24796
760
  msgid "Thank you so much for using %s!"
761
  msgstr ""
762
 
763
- #: includes/class-freemius.php:24802
764
  msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
765
  msgstr ""
766
 
767
- #: includes/class-freemius.php:24806
768
  msgid "Thank you so much for using our products!"
769
  msgstr ""
770
 
771
- #: includes/class-freemius.php:24807
772
  msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
773
  msgstr ""
774
 
775
- #: includes/class-freemius.php:24826
776
  msgid "%s and its add-ons"
777
  msgstr ""
778
 
779
- #: includes/class-freemius.php:24835
780
  msgid "Products"
781
  msgstr ""
782
 
783
- #: includes/class-freemius.php:24842, templates/connect.php:275
784
  msgid "Yes"
785
  msgstr ""
786
 
787
- #: includes/class-freemius.php:24843, templates/connect.php:276
788
  msgid "send me security & feature updates, educational content and offers."
789
  msgstr ""
790
 
791
- #: includes/class-freemius.php:24844, templates/connect.php:281
792
  msgid "No"
793
  msgstr ""
794
 
795
- #: includes/class-freemius.php:24846, templates/connect.php:283
796
  msgid "do %sNOT%s send me security & feature updates, educational content and offers."
797
  msgstr ""
798
 
799
- #: includes/class-freemius.php:24856
800
  msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard :-)"
801
  msgstr ""
802
 
803
- #: includes/class-freemius.php:24858, templates/connect.php:290
804
  msgid "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
805
  msgstr ""
806
 
807
- #: includes/class-freemius.php:25140
808
  msgid "License key is empty."
809
  msgstr ""
810
 
@@ -816,31 +828,31 @@ msgstr ""
816
  msgid "Buy license"
817
  msgstr ""
818
 
819
- #: includes/class-fs-plugin-updater.php:327, includes/class-fs-plugin-updater.php:360
820
  msgid "There is a %s of %s available."
821
  msgstr ""
822
 
823
- #: includes/class-fs-plugin-updater.php:329, includes/class-fs-plugin-updater.php:365
824
  msgid "new Beta version"
825
  msgstr ""
826
 
827
- #: includes/class-fs-plugin-updater.php:330, includes/class-fs-plugin-updater.php:366
828
  msgid "new version"
829
  msgstr ""
830
 
831
- #: includes/class-fs-plugin-updater.php:389
832
  msgid "Important Upgrade Notice:"
833
  msgstr ""
834
 
835
- #: includes/class-fs-plugin-updater.php:1326
836
  msgid "Installing plugin: %s"
837
  msgstr ""
838
 
839
- #: includes/class-fs-plugin-updater.php:1367
840
  msgid "Unable to connect to the filesystem. Please confirm your credentials."
841
  msgstr ""
842
 
843
- #: includes/class-fs-plugin-updater.php:1549
844
  msgid "The remote plugin package does not contain a folder with the desired slug and renaming did not work."
845
  msgstr ""
846
 
@@ -848,7 +860,7 @@ msgstr ""
848
  msgid "Purchase More"
849
  msgstr ""
850
 
851
- #: includes/fs-plugin-info-dialog.php:542, templates/account/partials/addon.php:385
852
  msgctxt "verb"
853
  msgid "Purchase"
854
  msgstr ""
@@ -861,7 +873,7 @@ msgstr ""
861
  msgid "Install Free Version Update Now"
862
  msgstr ""
863
 
864
- #: includes/fs-plugin-info-dialog.php:745, templates/account.php:641
865
  msgid "Install Update Now"
866
  msgstr ""
867
 
@@ -869,7 +881,7 @@ msgstr ""
869
  msgid "Install Free Version Now"
870
  msgstr ""
871
 
872
- #: includes/fs-plugin-info-dialog.php:755, templates/add-ons.php:323, templates/auto-installation.php:111, templates/account/partials/addon.php:365, templates/account/partials/addon.php:418
873
  msgid "Install Now"
874
  msgstr ""
875
 
@@ -878,20 +890,20 @@ msgctxt "as download latest version"
878
  msgid "Download Latest Free Version"
879
  msgstr ""
880
 
881
- #: includes/fs-plugin-info-dialog.php:772, templates/account.php:101, templates/add-ons.php:37, templates/account/partials/addon.php:25
882
  msgctxt "as download latest version"
883
  msgid "Download Latest"
884
  msgstr ""
885
 
886
- #: includes/fs-plugin-info-dialog.php:787, templates/add-ons.php:329, templates/account/partials/addon.php:356, templates/account/partials/addon.php:412
887
  msgid "Activate this add-on"
888
  msgstr ""
889
 
890
- #: includes/fs-plugin-info-dialog.php:789, templates/connect.php:458
891
  msgid "Activate Free Version"
892
  msgstr ""
893
 
894
- #: includes/fs-plugin-info-dialog.php:790, templates/account.php:125, templates/add-ons.php:330, templates/account/partials/addon.php:48
895
  msgid "Activate"
896
  msgstr ""
897
 
@@ -1020,7 +1032,7 @@ msgstr ""
1020
  msgid "Details"
1021
  msgstr ""
1022
 
1023
- #: includes/fs-plugin-info-dialog.php:1318, templates/account.php:112, templates/debug.php:201, templates/debug.php:238, templates/debug.php:455, templates/account/partials/addon.php:36
1024
  msgctxt "product version"
1025
  msgid "Version"
1026
  msgstr ""
@@ -1034,7 +1046,7 @@ msgstr ""
1034
  msgid "Last Updated"
1035
  msgstr ""
1036
 
1037
- #: includes/fs-plugin-info-dialog.php:1337, templates/account.php:527
1038
  msgctxt "x-ago"
1039
  msgid "%s ago"
1040
  msgstr ""
@@ -1143,293 +1155,281 @@ msgstr ""
1143
  msgid "Latest Free Version Installed"
1144
  msgstr ""
1145
 
1146
- #: templates/account.php:102, templates/forms/subscription-cancellation.php:96, templates/account/partials/addon.php:26, templates/account/partials/site.php:311
1147
  msgid "Downgrading your plan"
1148
  msgstr ""
1149
 
1150
- #: templates/account.php:103, templates/forms/subscription-cancellation.php:97, templates/account/partials/addon.php:27, templates/account/partials/site.php:312
1151
  msgid "Cancelling the subscription"
1152
  msgstr ""
1153
 
1154
  #. translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription'
1155
- #: templates/account.php:105, templates/forms/subscription-cancellation.php:99, templates/account/partials/site.php:314
1156
  msgid "%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s."
1157
  msgstr ""
1158
 
1159
- #: templates/account.php:106, templates/forms/subscription-cancellation.php:100, templates/account/partials/addon.php:30, templates/account/partials/site.php:315
1160
  msgid "Please note that we will not be able to grandfather outdated pricing for renewals/new subscriptions after a cancellation. If you choose to renew the subscription manually in the future, after a price increase, which typically occurs once a year, you will be charged the updated price."
1161
  msgstr ""
1162
 
1163
- #: templates/account.php:107, templates/forms/subscription-cancellation.php:106, templates/account/partials/addon.php:31
1164
  msgid "Cancelling the trial will immediately block access to all premium features. Are you sure?"
1165
  msgstr ""
1166
 
1167
- #: templates/account.php:108, templates/forms/subscription-cancellation.php:101, templates/account/partials/addon.php:32, templates/account/partials/site.php:316
1168
  msgid "You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support."
1169
  msgstr ""
1170
 
1171
- #: templates/account.php:109, templates/forms/subscription-cancellation.php:102, templates/account/partials/addon.php:33, templates/account/partials/site.php:317
1172
  msgid "Once your license expires you can still use the Free version but you will NOT have access to the %s features."
1173
  msgstr ""
1174
 
1175
  #. translators: %s: Plan title (e.g. "Professional")
1176
- #: templates/account.php:111, templates/account/partials/activate-license-button.php:31, templates/account/partials/addon.php:35
1177
  msgid "Activate %s Plan"
1178
  msgstr ""
1179
 
1180
  #. translators: %s: Time period (e.g. Auto renews in "2 months")
1181
- #: templates/account.php:114, templates/account/partials/addon.php:38, templates/account/partials/site.php:291
1182
  msgid "Auto renews in %s"
1183
  msgstr ""
1184
 
1185
  #. translators: %s: Time period (e.g. Expires in "2 months")
1186
- #: templates/account.php:116, templates/account/partials/addon.php:40, templates/account/partials/site.php:293
1187
  msgid "Expires in %s"
1188
  msgstr ""
1189
 
1190
- #: templates/account.php:117
1191
  msgctxt "as synchronize license"
1192
  msgid "Sync License"
1193
  msgstr ""
1194
 
1195
- #: templates/account.php:118, templates/account/partials/addon.php:41
1196
  msgid "Cancel Trial"
1197
  msgstr ""
1198
 
1199
- #: templates/account.php:119, templates/account/partials/addon.php:42
1200
  msgid "Change Plan"
1201
  msgstr ""
1202
 
1203
- #: templates/account.php:120, templates/account/partials/addon.php:43
1204
  msgctxt "verb"
1205
  msgid "Upgrade"
1206
  msgstr ""
1207
 
1208
- #: templates/account.php:122, templates/account/partials/addon.php:45, templates/account/partials/site.php:318
1209
  msgctxt "verb"
1210
  msgid "Downgrade"
1211
  msgstr ""
1212
 
1213
- #: templates/account.php:124, templates/add-ons.php:246, templates/plugin-info/features.php:72, templates/account/partials/addon.php:47, templates/account/partials/site.php:33
1214
  msgid "Free"
1215
  msgstr ""
1216
 
1217
- #: templates/account.php:126, templates/debug.php:371, includes/customizer/class-fs-customizer-upsell-control.php:110, templates/account/partials/addon.php:49
1218
  msgctxt "as product pricing plan"
1219
  msgid "Plan"
1220
  msgstr ""
1221
 
1222
- #: templates/account.php:127
1223
  msgid "Bundle Plan"
1224
  msgstr ""
1225
 
1226
- #: templates/account.php:250
1227
  msgid "Free Trial"
1228
  msgstr ""
1229
 
1230
- #: templates/account.php:261
1231
  msgid "Account Details"
1232
  msgstr ""
1233
 
1234
- #: templates/account.php:268, templates/forms/data-debug-mode.php:33
1235
  msgid "Start Debug"
1236
  msgstr ""
1237
 
1238
- #: templates/account.php:270
1239
  msgid "Stop Debug"
1240
  msgstr ""
1241
 
1242
- #: templates/account.php:277
1243
  msgid "Billing & Invoices"
1244
  msgstr ""
1245
 
1246
- #: templates/account.php:288
1247
- 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?"
1248
- msgstr ""
1249
-
1250
- #: templates/account.php:290
1251
- msgid "Deletion is not temporary. Only delete if you no longer want to use this %s anymore. Are you sure you would like to continue with the deletion?"
1252
- msgstr ""
1253
-
1254
- #: templates/account.php:293
1255
- msgid "Delete Account"
1256
- msgstr ""
1257
-
1258
- #: templates/account.php:305, templates/account/partials/addon.php:231, templates/account/partials/deactivate-license-button.php:35
1259
  msgid "Deactivate License"
1260
  msgstr ""
1261
 
1262
- #: templates/account.php:328, templates/forms/subscription-cancellation.php:125
1263
  msgid "Are you sure you want to proceed?"
1264
  msgstr ""
1265
 
1266
- #: templates/account.php:328, templates/account/partials/addon.php:255
1267
  msgid "Cancel Subscription"
1268
  msgstr ""
1269
 
1270
- #: templates/account.php:357, templates/account/partials/addon.php:340
1271
  msgctxt "as synchronize"
1272
  msgid "Sync"
1273
  msgstr ""
1274
 
1275
- #: templates/account.php:372, templates/debug.php:505
1276
  msgid "Name"
1277
  msgstr ""
1278
 
1279
- #: templates/account.php:378, templates/debug.php:506
1280
  msgid "Email"
1281
  msgstr ""
1282
 
1283
- #: templates/account.php:385, templates/debug.php:369, templates/debug.php:555
1284
  msgid "User ID"
1285
  msgstr ""
1286
 
1287
- #: templates/account.php:403, templates/account.php:721, templates/account.php:754, templates/debug.php:236, templates/debug.php:363, templates/debug.php:452, templates/debug.php:504, templates/debug.php:553, templates/debug.php:632, templates/account/payments.php:35, templates/debug/logger.php:21
1288
  msgid "ID"
1289
  msgstr ""
1290
 
1291
- #: templates/account.php:410
1292
  msgid "Site ID"
1293
  msgstr ""
1294
 
1295
- #: templates/account.php:413
1296
  msgid "No ID"
1297
  msgstr ""
1298
 
1299
- #: templates/account.php:418, templates/debug.php:243, templates/debug.php:372, templates/debug.php:456, templates/debug.php:508, templates/account/partials/site.php:227
1300
  msgid "Public Key"
1301
  msgstr ""
1302
 
1303
- #: templates/account.php:424, templates/debug.php:373, templates/debug.php:457, templates/debug.php:509, templates/account/partials/site.php:239
1304
  msgid "Secret Key"
1305
  msgstr ""
1306
 
1307
- #: templates/account.php:427
1308
  msgctxt "as secret encryption key missing"
1309
  msgid "No Secret"
1310
  msgstr ""
1311
 
1312
- #: templates/account.php:454, templates/account/partials/site.php:120, templates/account/partials/site.php:122
1313
  msgid "Trial"
1314
  msgstr ""
1315
 
1316
- #: templates/account.php:481, templates/debug.php:561, templates/account/partials/site.php:260
1317
  msgid "License Key"
1318
  msgstr ""
1319
 
1320
- #: templates/account.php:512
1321
  msgid "Join the Beta program"
1322
  msgstr ""
1323
 
1324
- #: templates/account.php:518
1325
  msgid "not verified"
1326
  msgstr ""
1327
 
1328
- #: templates/account.php:527, templates/account/partials/addon.php:190
1329
  msgid "Expired"
1330
  msgstr ""
1331
 
1332
- #: templates/account.php:587
1333
  msgid "Premium version"
1334
  msgstr ""
1335
 
1336
- #: templates/account.php:589
1337
  msgid "Free version"
1338
  msgstr ""
1339
 
1340
- #: templates/account.php:601
1341
  msgid "Verify Email"
1342
  msgstr ""
1343
 
1344
- #: templates/account.php:615
1345
  msgid "Download %s Version"
1346
  msgstr ""
1347
 
1348
- #: templates/account.php:631
1349
  msgid "Download Paid Version"
1350
  msgstr ""
1351
 
1352
- #: templates/account.php:649, templates/account.php:892, templates/account/partials/site.php:248, templates/account/partials/site.php:270
1353
  msgctxt "verb"
1354
  msgid "Show"
1355
  msgstr ""
1356
 
1357
- #: templates/account.php:664
1358
  msgid "What is your %s?"
1359
  msgstr ""
1360
 
1361
- #: templates/account.php:672, templates/account/billing.php:21
1362
  msgctxt "verb"
1363
  msgid "Edit"
1364
  msgstr ""
1365
 
1366
- #: templates/account.php:676, templates/forms/user-change.php:27
1367
  msgid "Change User"
1368
  msgstr ""
1369
 
1370
- #: templates/account.php:700
1371
  msgid "Sites"
1372
  msgstr ""
1373
 
1374
- #: templates/account.php:713
1375
  msgid "Search by address"
1376
  msgstr ""
1377
 
1378
- #: templates/account.php:722, templates/debug.php:366
1379
  msgid "Address"
1380
  msgstr ""
1381
 
1382
- #: templates/account.php:723
1383
  msgid "License"
1384
  msgstr ""
1385
 
1386
- #: templates/account.php:724
1387
  msgid "Plan"
1388
  msgstr ""
1389
 
1390
- #: templates/account.php:757
1391
  msgctxt "as software license"
1392
  msgid "License"
1393
  msgstr ""
1394
 
1395
- #: templates/account.php:886
1396
  msgctxt "verb"
1397
  msgid "Hide"
1398
  msgstr ""
1399
 
1400
- #: templates/account.php:908, templates/forms/data-debug-mode.php:31
1401
  msgid "Processing"
1402
  msgstr ""
1403
 
1404
- #: templates/account.php:911
1405
  msgid "Get updates for bleeding edge Beta versions of %s."
1406
  msgstr ""
1407
 
1408
- #: templates/account.php:969
1409
  msgid "Cancelling %s"
1410
  msgstr ""
1411
 
1412
- #: templates/account.php:969, templates/account.php:986, templates/forms/subscription-cancellation.php:27, templates/forms/deactivation/form.php:133
1413
  msgid "trial"
1414
  msgstr ""
1415
 
1416
- #: templates/account.php:984, templates/forms/deactivation/form.php:150
1417
  msgid "Cancelling %s..."
1418
  msgstr ""
1419
 
1420
- #: templates/account.php:987, templates/forms/subscription-cancellation.php:28, templates/forms/deactivation/form.php:134
1421
  msgid "subscription"
1422
  msgstr ""
1423
 
1424
- #: templates/account.php:1001
1425
  msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
1426
  msgstr ""
1427
 
1428
- #: templates/account.php:1075
1429
  msgid "Disabling white-label mode"
1430
  msgstr ""
1431
 
1432
- #: templates/account.php:1076
1433
  msgid "Enabling white-label mode"
1434
  msgstr ""
1435
 
@@ -1455,7 +1455,7 @@ msgctxt "installed add-on"
1455
  msgid "Installed"
1456
  msgstr ""
1457
 
1458
- #: templates/admin-notice.php:13, templates/forms/license-activation.php:222, templates/forms/resend-key.php:77
1459
  msgctxt "as close a window"
1460
  msgid "Dismiss"
1461
  msgstr ""
@@ -1489,198 +1489,147 @@ msgid "PCI compliant"
1489
  msgstr ""
1490
 
1491
  #. translators: %s: name (e.g. Hey John,)
1492
- #: templates/connect.php:112
1493
  msgctxt "greeting"
1494
  msgid "Hey %s,"
1495
  msgstr ""
1496
 
1497
- #: templates/connect.php:162
 
 
 
 
 
 
 
 
1498
  msgid "Allow & Continue"
1499
  msgstr ""
1500
 
1501
- #: templates/connect.php:166
1502
  msgid "Re-send activation email"
1503
  msgstr ""
1504
 
1505
- #: templates/connect.php:170
1506
  msgid "Thanks %s!"
1507
  msgstr ""
1508
 
1509
- #: templates/connect.php:180, templates/forms/license-activation.php:46
1510
- msgid "Agree & Activate License"
1511
  msgstr ""
1512
 
1513
- #: templates/connect.php:184
1514
- msgid "Welcome to %s! To get started, please enter your license key:"
1515
  msgstr ""
1516
 
1517
- #: templates/connect.php:191
1518
- msgid "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s."
1519
  msgstr ""
1520
 
1521
- #: templates/connect.php:192
1522
- msgid "Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s."
 
1523
  msgstr ""
1524
 
1525
- #: templates/connect.php:198
1526
- msgid "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
1527
  msgstr ""
1528
 
1529
- #: templates/connect.php:199
1530
- msgid "Never miss an important update - opt in to our security & feature updates notifications, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
1531
  msgstr ""
1532
 
1533
- #: templates/connect.php:233
 
 
 
 
1534
  msgid "We're excited to introduce the Freemius network-level integration."
1535
  msgstr ""
1536
 
1537
- #: templates/connect.php:236
1538
  msgid "During the update process we detected %d site(s) that are still pending license activation."
1539
  msgstr ""
1540
 
1541
- #: templates/connect.php:238
1542
  msgid "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
1543
  msgstr ""
1544
 
1545
- #: templates/connect.php:240
1546
  msgid "%s's paid features"
1547
  msgstr ""
1548
 
1549
- #: templates/connect.php:245
1550
  msgid "Alternatively, you can skip it for now and activate the license later, in your %s's network-level Account page."
1551
  msgstr ""
1552
 
1553
- #: templates/connect.php:247
1554
  msgid "During the update process we detected %s site(s) in the network that are still pending your attention."
1555
  msgstr ""
1556
 
1557
- #: templates/connect.php:256, templates/forms/data-debug-mode.php:35, templates/forms/license-activation.php:49
1558
  msgid "License key"
1559
  msgstr ""
1560
 
1561
- #: templates/connect.php:259, templates/forms/license-activation.php:22
1562
  msgid "Can't find your license key?"
1563
  msgstr ""
1564
 
1565
- #: templates/connect.php:318, templates/connect.php:700, templates/forms/deactivation/retry-skip.php:20
1566
  msgctxt "verb"
1567
  msgid "Skip"
1568
  msgstr ""
1569
 
1570
- #: templates/connect.php:321
1571
  msgid "Delegate to Site Admins"
1572
  msgstr ""
1573
 
1574
- #: templates/connect.php:321
1575
  msgid "If you click it, this decision will be delegated to the sites administrators."
1576
  msgstr ""
1577
 
1578
- #: templates/connect.php:346
1579
  msgid "License issues?"
1580
  msgstr ""
1581
 
1582
- #: templates/connect.php:362
1583
- msgid "Your Profile Overview"
1584
- msgstr ""
1585
-
1586
- #: templates/connect.php:363
1587
- msgid "Name and email address"
1588
- msgstr ""
1589
-
1590
- #: templates/connect.php:370
1591
- msgid "So you can manage and control your license remotely from the User Dashboard."
1592
- msgstr ""
1593
-
1594
- #: templates/connect.php:371
1595
- msgid "Your Site Overview"
1596
- msgstr ""
1597
-
1598
- #: templates/connect.php:372
1599
- msgid "Site URL, WP version, PHP info"
1600
- msgstr ""
1601
-
1602
- #: templates/connect.php:379
1603
- msgid "Admin Notices"
1604
- msgstr ""
1605
-
1606
- #: templates/connect.php:380, templates/connect.php:398
1607
- msgid "Updates, announcements, marketing, no spam"
1608
- msgstr ""
1609
-
1610
- #: templates/connect.php:387
1611
- msgid "So you can reuse the license when the %s is no longer active."
1612
- msgstr ""
1613
-
1614
- #: templates/connect.php:388
1615
- msgid "Current %s Status"
1616
- msgstr ""
1617
-
1618
- #: templates/connect.php:389
1619
- msgid "Active, deactivated, or uninstalled"
1620
- msgstr ""
1621
-
1622
- #: templates/connect.php:397
1623
- msgid "Newsletter"
1624
- msgstr ""
1625
-
1626
- #: templates/connect.php:405
1627
- msgid "Plugins & Themes"
1628
- msgstr ""
1629
-
1630
- #: templates/connect.php:405
1631
- msgid "optional"
1632
- msgstr ""
1633
-
1634
- #: templates/connect.php:406
1635
- msgid "To help us troubleshoot any potential issues that may arise from other plugin or theme conflicts."
1636
- msgstr ""
1637
-
1638
- #: templates/connect.php:407
1639
- msgid "Title, slug, version, and is active"
1640
- msgstr ""
1641
-
1642
- #: templates/connect.php:424
1643
- msgid "The %1$s will periodically send %2$s to %3$s for security & feature updates delivery, and license management."
1644
- msgstr ""
1645
-
1646
- #: templates/connect.php:426
1647
- msgid "diagnostic data"
1648
- msgstr ""
1649
-
1650
- #: templates/connect.php:427
1651
- msgid "Freemius is our licensing and software updates engine"
1652
  msgstr ""
1653
 
1654
  #: templates/connect.php:430
1655
- msgid "What permissions are being granted?"
1656
  msgstr ""
1657
 
1658
- #: templates/connect.php:457
1659
  msgid "Don't have a license key?"
1660
  msgstr ""
1661
 
1662
- #: templates/connect.php:460
1663
  msgid "Have a license key?"
1664
  msgstr ""
1665
 
1666
- #: templates/connect.php:468
 
 
 
 
1667
  msgid "Privacy Policy"
1668
  msgstr ""
1669
 
1670
- #: templates/connect.php:470
1671
  msgid "License Agreement"
1672
  msgstr ""
1673
 
1674
- #: templates/connect.php:470
1675
  msgid "Terms of Service"
1676
  msgstr ""
1677
 
1678
- #: templates/connect.php:866
1679
  msgctxt "as in the process of sending an email"
1680
  msgid "Sending email"
1681
  msgstr ""
1682
 
1683
- #: templates/connect.php:867
1684
  msgctxt "as activating plugin"
1685
  msgid "Activating"
1686
  msgstr ""
@@ -1699,235 +1648,239 @@ msgctxt "as turned on"
1699
  msgid "On"
1700
  msgstr ""
1701
 
1702
- #: templates/debug.php:20
1703
  msgid "SDK"
1704
  msgstr ""
1705
 
1706
- #: templates/debug.php:24
1707
  msgctxt "as code debugging"
1708
  msgid "Debugging"
1709
  msgstr ""
1710
 
1711
- #: templates/debug.php:52, templates/debug.php:248, templates/debug.php:374, templates/debug.php:510
1712
  msgid "Actions"
1713
  msgstr ""
1714
 
1715
- #: templates/debug.php:62
1716
  msgid "Are you sure you want to delete all Freemius data?"
1717
  msgstr ""
1718
 
1719
- #: templates/debug.php:62
1720
  msgid "Delete All Accounts"
1721
  msgstr ""
1722
 
1723
- #: templates/debug.php:69
1724
  msgid "Clear API Cache"
1725
  msgstr ""
1726
 
1727
- #: templates/debug.php:77
1728
  msgid "Clear Updates Transients"
1729
  msgstr ""
1730
 
1731
- #: templates/debug.php:84
 
 
 
 
1732
  msgid "Sync Data From Server"
1733
  msgstr ""
1734
 
1735
- #: templates/debug.php:93
1736
  msgid "Migrate Options to Network"
1737
  msgstr ""
1738
 
1739
- #: templates/debug.php:98
1740
  msgid "Load DB Option"
1741
  msgstr ""
1742
 
1743
- #: templates/debug.php:101
1744
  msgid "Set DB Option"
1745
  msgstr ""
1746
 
1747
- #: templates/debug.php:180
1748
  msgid "Key"
1749
  msgstr ""
1750
 
1751
- #: templates/debug.php:181
1752
  msgid "Value"
1753
  msgstr ""
1754
 
1755
- #: templates/debug.php:197
1756
  msgctxt "as software development kit versions"
1757
  msgid "SDK Versions"
1758
  msgstr ""
1759
 
1760
- #: templates/debug.php:202
1761
  msgid "SDK Path"
1762
  msgstr ""
1763
 
1764
- #: templates/debug.php:203, templates/debug.php:242
1765
  msgid "Module Path"
1766
  msgstr ""
1767
 
1768
- #: templates/debug.php:204
1769
  msgid "Is Active"
1770
  msgstr ""
1771
 
1772
- #: templates/debug.php:232, templates/debug/plugins-themes-sync.php:35
1773
  msgid "Plugins"
1774
  msgstr ""
1775
 
1776
- #: templates/debug.php:232, templates/debug/plugins-themes-sync.php:56
1777
  msgid "Themes"
1778
  msgstr ""
1779
 
1780
- #: templates/debug.php:237, templates/debug.php:368, templates/debug.php:454, templates/debug/scheduled-crons.php:80
1781
  msgid "Slug"
1782
  msgstr ""
1783
 
1784
- #: templates/debug.php:239, templates/debug.php:453
1785
  msgid "Title"
1786
  msgstr ""
1787
 
1788
- #: templates/debug.php:240
1789
  msgctxt "as application program interface"
1790
  msgid "API"
1791
  msgstr ""
1792
 
1793
- #: templates/debug.php:241
1794
  msgid "Freemius State"
1795
  msgstr ""
1796
 
1797
- #: templates/debug.php:245
1798
  msgid "Network Blog"
1799
  msgstr ""
1800
 
1801
- #: templates/debug.php:246
1802
  msgid "Network User"
1803
  msgstr ""
1804
 
1805
- #: templates/debug.php:283
1806
  msgctxt "as connection was successful"
1807
  msgid "Connected"
1808
  msgstr ""
1809
 
1810
- #: templates/debug.php:284
1811
  msgctxt "as connection blocked"
1812
  msgid "Blocked"
1813
  msgstr ""
1814
 
1815
- #: templates/debug.php:320
1816
  msgid "Simulate Trial Promotion"
1817
  msgstr ""
1818
 
1819
- #: templates/debug.php:332
1820
  msgid "Simulate Network Upgrade"
1821
  msgstr ""
1822
 
1823
- #: templates/debug.php:357
1824
  msgid "%s Installs"
1825
  msgstr ""
1826
 
1827
- #: templates/debug.php:359
1828
  msgctxt "like websites"
1829
  msgid "Sites"
1830
  msgstr ""
1831
 
1832
- #: templates/debug.php:365, templates/account/partials/site.php:156
1833
  msgid "Blog ID"
1834
  msgstr ""
1835
 
1836
- #: templates/debug.php:370
1837
  msgid "License ID"
1838
  msgstr ""
1839
 
1840
- #: templates/debug.php:434, templates/debug.php:533, templates/account/partials/addon.php:435
1841
  msgctxt "verb"
1842
  msgid "Delete"
1843
  msgstr ""
1844
 
1845
- #: templates/debug.php:448
1846
  msgid "Add Ons of module %s"
1847
  msgstr ""
1848
 
1849
- #: templates/debug.php:500
1850
  msgid "Users"
1851
  msgstr ""
1852
 
1853
- #: templates/debug.php:507
1854
  msgid "Verified"
1855
  msgstr ""
1856
 
1857
- #: templates/debug.php:549
1858
  msgid "%s Licenses"
1859
  msgstr ""
1860
 
1861
- #: templates/debug.php:554
1862
  msgid "Plugin ID"
1863
  msgstr ""
1864
 
1865
- #: templates/debug.php:556
1866
  msgid "Plan ID"
1867
  msgstr ""
1868
 
1869
- #: templates/debug.php:557
1870
  msgid "Quota"
1871
  msgstr ""
1872
 
1873
- #: templates/debug.php:558
1874
  msgid "Activated"
1875
  msgstr ""
1876
 
1877
- #: templates/debug.php:559
1878
  msgid "Blocking"
1879
  msgstr ""
1880
 
1881
- #: templates/debug.php:560, templates/debug.php:631, templates/debug/logger.php:22
1882
  msgid "Type"
1883
  msgstr ""
1884
 
1885
- #: templates/debug.php:562
1886
  msgctxt "as expiration date"
1887
  msgid "Expiration"
1888
  msgstr ""
1889
 
1890
- #: templates/debug.php:590
1891
  msgid "Debug Log"
1892
  msgstr ""
1893
 
1894
- #: templates/debug.php:594
1895
  msgid "All Types"
1896
  msgstr ""
1897
 
1898
- #: templates/debug.php:601
1899
  msgid "All Requests"
1900
  msgstr ""
1901
 
1902
- #: templates/debug.php:606, templates/debug.php:635, templates/debug/logger.php:25
1903
  msgid "File"
1904
  msgstr ""
1905
 
1906
- #: templates/debug.php:607, templates/debug.php:633, templates/debug/logger.php:23
1907
  msgid "Function"
1908
  msgstr ""
1909
 
1910
- #: templates/debug.php:608
1911
  msgid "Process ID"
1912
  msgstr ""
1913
 
1914
- #: templates/debug.php:609
1915
  msgid "Logger"
1916
  msgstr ""
1917
 
1918
- #: templates/debug.php:610, templates/debug.php:634, templates/debug/logger.php:24
1919
  msgid "Message"
1920
  msgstr ""
1921
 
1922
- #: templates/debug.php:612
1923
  msgid "Filter"
1924
  msgstr ""
1925
 
1926
- #: templates/debug.php:620
1927
  msgid "Download"
1928
  msgstr ""
1929
 
1930
- #: templates/debug.php:636, templates/debug/logger.php:26
1931
  msgid "Timestamp"
1932
  msgstr ""
1933
 
@@ -1952,6 +1905,211 @@ msgstr ""
1952
  msgid "Requests"
1953
  msgstr ""
1954
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1955
  #: templates/account/billing.php:22
1956
  msgctxt "verb"
1957
  msgid "Update"
@@ -2017,6 +2175,16 @@ msgstr ""
2017
  msgid "Invoice"
2018
  msgstr ""
2019
 
 
 
 
 
 
 
 
 
 
 
2020
  #: templates/debug/api-calls.php:56
2021
  msgid "API"
2022
  msgstr ""
@@ -2105,143 +2273,143 @@ msgstr ""
2105
  msgid "Next"
2106
  msgstr ""
2107
 
2108
- #: templates/forms/affiliation.php:82
2109
  msgid "Non-expiring"
2110
  msgstr ""
2111
 
2112
- #: templates/forms/affiliation.php:85
2113
  msgid "Apply to become an affiliate"
2114
  msgstr ""
2115
 
2116
- #: templates/forms/affiliation.php:107
2117
  msgid "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s."
2118
  msgstr ""
2119
 
2120
- #: templates/forms/affiliation.php:122
2121
  msgid "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information."
2122
  msgstr ""
2123
 
2124
- #: templates/forms/affiliation.php:125
2125
  msgid "Your affiliation account was temporarily suspended."
2126
  msgstr ""
2127
 
2128
- #: templates/forms/affiliation.php:128
2129
  msgid "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days."
2130
  msgstr ""
2131
 
2132
- #: templates/forms/affiliation.php:131
2133
  msgid "Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support."
2134
  msgstr ""
2135
 
2136
- #: templates/forms/affiliation.php:144
2137
  msgid "Like the %s? Become our ambassador and earn cash ;-)"
2138
  msgstr ""
2139
 
2140
- #: templates/forms/affiliation.php:145
2141
  msgid "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
2142
  msgstr ""
2143
 
2144
- #: templates/forms/affiliation.php:148
2145
  msgid "Program Summary"
2146
  msgstr ""
2147
 
2148
- #: templates/forms/affiliation.php:150
2149
  msgid "%s commission when a customer purchases a new license."
2150
  msgstr ""
2151
 
2152
- #: templates/forms/affiliation.php:152
2153
  msgid "Get commission for automated subscription renewals."
2154
  msgstr ""
2155
 
2156
- #: templates/forms/affiliation.php:155
2157
  msgid "%s tracking cookie after the first visit to maximize earnings potential."
2158
  msgstr ""
2159
 
2160
- #: templates/forms/affiliation.php:158
2161
  msgid "Unlimited commissions."
2162
  msgstr ""
2163
 
2164
- #: templates/forms/affiliation.php:160
2165
  msgid "%s minimum payout amount."
2166
  msgstr ""
2167
 
2168
- #: templates/forms/affiliation.php:161
2169
  msgid "Payouts are in USD and processed monthly via PayPal."
2170
  msgstr ""
2171
 
2172
- #: templates/forms/affiliation.php:162
2173
  msgid "As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days."
2174
  msgstr ""
2175
 
2176
- #: templates/forms/affiliation.php:165
2177
  msgid "Affiliate"
2178
  msgstr ""
2179
 
2180
- #: templates/forms/affiliation.php:168, templates/forms/resend-key.php:23
2181
  msgid "Email address"
2182
  msgstr ""
2183
 
2184
- #: templates/forms/affiliation.php:172
2185
  msgid "Full name"
2186
  msgstr ""
2187
 
2188
- #: templates/forms/affiliation.php:176
2189
  msgid "PayPal account email address"
2190
  msgstr ""
2191
 
2192
- #: templates/forms/affiliation.php:180
2193
  msgid "Where are you going to promote the %s?"
2194
  msgstr ""
2195
 
2196
- #: templates/forms/affiliation.php:182
2197
  msgid "Enter the domain of your website or other websites from where you plan to promote the %s."
2198
  msgstr ""
2199
 
2200
- #: templates/forms/affiliation.php:184
2201
  msgid "Add another domain"
2202
  msgstr ""
2203
 
2204
- #: templates/forms/affiliation.php:188
2205
  msgid "Extra Domains"
2206
  msgstr ""
2207
 
2208
- #: templates/forms/affiliation.php:189
2209
  msgid "Extra domains where you will be marketing the product from."
2210
  msgstr ""
2211
 
2212
- #: templates/forms/affiliation.php:199
2213
  msgid "Promotion methods"
2214
  msgstr ""
2215
 
2216
- #: templates/forms/affiliation.php:202
2217
  msgid "Social media (Facebook, Twitter, etc.)"
2218
  msgstr ""
2219
 
2220
- #: templates/forms/affiliation.php:206
2221
  msgid "Mobile apps"
2222
  msgstr ""
2223
 
2224
- #: templates/forms/affiliation.php:210
2225
  msgid "Website, email, and social media statistics (optional)"
2226
  msgstr ""
2227
 
2228
- #: templates/forms/affiliation.php:213
2229
  msgid "Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential)."
2230
  msgstr ""
2231
 
2232
- #: templates/forms/affiliation.php:217
2233
  msgid "How will you promote us?"
2234
  msgstr ""
2235
 
2236
- #: templates/forms/affiliation.php:220
2237
  msgid "Please provide details on how you intend to promote %s (please be as specific as possible)."
2238
  msgstr ""
2239
 
2240
- #: templates/forms/affiliation.php:232, templates/forms/resend-key.php:22
2241
  msgid "Cancel"
2242
  msgstr ""
2243
 
2244
- #: templates/forms/affiliation.php:234
2245
  msgid "Become an affiliate"
2246
  msgstr ""
2247
 
@@ -2261,66 +2429,93 @@ msgstr ""
2261
  msgid "User key"
2262
  msgstr ""
2263
 
2264
- #: templates/forms/license-activation.php:23
2265
- msgid "Please enter the license key that you received in the email right after the purchase:"
2266
  msgstr ""
2267
 
2268
- #: templates/forms/license-activation.php:28
2269
- msgid "Update License"
 
2270
  msgstr ""
2271
 
2272
- #: templates/forms/license-activation.php:41
2273
- msgid "The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license."
2274
  msgstr ""
2275
 
2276
- #: templates/forms/license-activation.php:183
2277
- msgid "Associate with the license owner's account."
2278
  msgstr ""
2279
 
2280
- #: templates/forms/optout.php:30
2281
- msgctxt "verb"
2282
- msgid "Opt Out"
2283
  msgstr ""
2284
 
2285
- #: templates/forms/optout.php:31
2286
- msgctxt "verb"
2287
- msgid "Opt In"
2288
  msgstr ""
2289
 
2290
- #: templates/forms/optout.php:34
2291
- msgid "Connectivity to the licensing engine was successfully re-established. Automatic security & feature updates are now available through the WP Admin Dashboard."
2292
  msgstr ""
2293
 
2294
- #: templates/forms/optout.php:36
2295
- msgid "Warning: Opting out will block automatic updates"
2296
  msgstr ""
2297
 
2298
- #: templates/forms/optout.php:37
2299
- msgid "Ongoing connectivity with the licensing engine is essential for receiving automatic security & feature updates of the paid product. To receive these updates, data like your license key, %1$s version, and WordPress version, is periodically sent to the server to check for updates. By opting out, you understand that your site won't receive automatic updates for %2$s from within the WP Admin Dashboard. This can put your site at risk, and we highly recommend to keep this connection active. If you do choose to opt-out, you'll need to check for %1$s updates and install them manually."
2300
  msgstr ""
2301
 
2302
- #: templates/forms/optout.php:39
2303
- msgid "I'd like to keep automatic updates"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2304
  msgstr ""
2305
 
2306
  #: templates/forms/optout.php:44
2307
- msgid "Usage tracking is done in the name of making %s better. Making a better user experience, prioritizing new features, and more good things. We'd really appreciate if you'll reconsider letting us continue with the tracking."
2308
  msgstr ""
2309
 
2310
- #: templates/forms/optout.php:45
2311
- msgid "On second thought - I want to continue helping"
2312
  msgstr ""
2313
 
2314
- #: templates/forms/optout.php:49
2315
- msgid "By clicking \"Opt Out\", we will no longer be sending any data from %s to %s."
2316
  msgstr ""
2317
 
2318
- #: templates/forms/optout.php:74
2319
- msgid "Plugins & themes tracking"
2320
  msgstr ""
2321
 
2322
- #: templates/forms/optout.php:261
2323
- msgid "Saved"
 
 
 
 
2324
  msgstr ""
2325
 
2326
  #: templates/forms/premium-versions-upgrade-handler.php:40
@@ -2344,7 +2539,11 @@ msgstr ""
2344
  msgid "Send License Key"
2345
  msgstr ""
2346
 
2347
- #: templates/forms/resend-key.php:57
 
 
 
 
2348
  msgid "Enter the email address you've used for the upgrade below and we will resend you the license key."
2349
  msgstr ""
2350
 
@@ -2356,10 +2555,6 @@ msgstr ""
2356
  msgid "In case you are NOT planning on using this %s on this site (or any other site) - would you like to cancel the %s as well?"
2357
  msgstr ""
2358
 
2359
- #: templates/forms/subscription-cancellation.php:52
2360
- msgid "license"
2361
- msgstr ""
2362
-
2363
  #: templates/forms/subscription-cancellation.php:57
2364
  msgid "Cancel %s - I no longer need any security & feature updates, nor support for %s because I'm not planning to use the %s on this, or any other site."
2365
  msgstr ""
@@ -2380,7 +2575,7 @@ msgstr ""
2380
  msgid "Proceed"
2381
  msgstr ""
2382
 
2383
- #: templates/forms/subscription-cancellation.php:191, templates/forms/deactivation/form.php:171
2384
  msgid "Cancel %s & Proceed"
2385
  msgstr ""
2386
 
@@ -2404,9 +2599,8 @@ msgstr ""
2404
  msgid "Enter email address"
2405
  msgstr ""
2406
 
2407
- #: templates/forms/user-change.php:81
2408
- msgctxt "close window"
2409
- msgid "Dismiss"
2410
  msgstr ""
2411
 
2412
  #: templates/js/style-premium-theme.php:39
@@ -2417,31 +2611,31 @@ msgstr ""
2417
  msgid "Beta"
2418
  msgstr ""
2419
 
2420
- #: templates/partials/network-activation.php:27
2421
  msgid "Activate license on all sites in the network."
2422
  msgstr ""
2423
 
2424
- #: templates/partials/network-activation.php:28
2425
  msgid "Apply on all sites in the network."
2426
  msgstr ""
2427
 
2428
- #: templates/partials/network-activation.php:31
2429
  msgid "Activate license on all pending sites."
2430
  msgstr ""
2431
 
2432
- #: templates/partials/network-activation.php:32
2433
  msgid "Apply on all pending sites."
2434
  msgstr ""
2435
 
2436
- #: templates/partials/network-activation.php:40, templates/partials/network-activation.php:74
2437
  msgid "allow"
2438
  msgstr ""
2439
 
2440
- #: templates/partials/network-activation.php:43, templates/partials/network-activation.php:77
2441
  msgid "delegate"
2442
  msgstr ""
2443
 
2444
- #: templates/partials/network-activation.php:47, templates/partials/network-activation.php:81
2445
  msgid "skip"
2446
  msgstr ""
2447
 
@@ -2467,31 +2661,47 @@ msgid "Last license"
2467
  msgstr ""
2468
 
2469
  #. translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription'
2470
- #: templates/account/partials/addon.php:29
2471
  msgid "%1$s will immediately stop all future recurring payments and your %s plan license will expire in %s."
2472
  msgstr ""
2473
 
2474
- #: templates/account/partials/addon.php:185
2475
  msgid "Cancelled"
2476
  msgstr ""
2477
 
2478
- #: templates/account/partials/addon.php:195
2479
  msgid "No expiration"
2480
  msgstr ""
2481
 
2482
- #: templates/account/partials/site.php:189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2483
  msgid "Owner Name"
2484
  msgstr ""
2485
 
2486
- #: templates/account/partials/site.php:201
2487
  msgid "Owner Email"
2488
  msgstr ""
2489
 
2490
- #: templates/account/partials/site.php:213
2491
  msgid "Owner ID"
2492
  msgstr ""
2493
 
2494
- #: templates/account/partials/site.php:286
2495
  msgid "Subscription"
2496
  msgstr ""
2497
 
@@ -2503,47 +2713,63 @@ msgstr ""
2503
  msgid "Contact Support"
2504
  msgstr ""
2505
 
2506
- #: templates/forms/deactivation/form.php:64
2507
  msgid "Anonymous feedback"
2508
  msgstr ""
2509
 
2510
- #: templates/forms/deactivation/form.php:70
 
 
 
 
 
 
 
 
 
 
 
 
2511
  msgid "Deactivate"
2512
  msgstr ""
2513
 
2514
- #: templates/forms/deactivation/form.php:72
2515
  msgid "Activate %s"
2516
  msgstr ""
2517
 
2518
- #: templates/forms/deactivation/form.php:87
 
 
 
 
2519
  msgid "Quick Feedback"
2520
  msgstr ""
2521
 
2522
- #: templates/forms/deactivation/form.php:91
2523
  msgid "If you have a moment, please let us know why you are %s"
2524
  msgstr ""
2525
 
2526
- #: templates/forms/deactivation/form.php:91
2527
  msgid "deactivating"
2528
  msgstr ""
2529
 
2530
- #: templates/forms/deactivation/form.php:91
2531
  msgid "switching"
2532
  msgstr ""
2533
 
2534
- #: templates/forms/deactivation/form.php:369
2535
- msgid "Submit & %s"
2536
  msgstr ""
2537
 
2538
- #: templates/forms/deactivation/form.php:390
2539
- msgid "Kindly tell us the reason so we can improve."
2540
  msgstr ""
2541
 
2542
- #: templates/forms/deactivation/form.php:515
2543
  msgid "Yes - %s"
2544
  msgstr ""
2545
 
2546
- #: templates/forms/deactivation/form.php:522
2547
  msgid "Skip & %s"
2548
  msgstr ""
2549
 
1
+ # Copyright (C) 2022 freemius
2
  # This file is distributed under the same license as the freemius package.
3
  msgid ""
4
  msgstr ""
16
  "X-Poedit-SourceCharset: UTF-8\n"
17
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18
 
19
+ #: includes/class-freemius.php:1744, templates/account.php:947
20
  msgid "An update to a Beta version will replace your installed version of %s with the latest Beta release - use with caution, and not on production sites. You have been warned."
21
  msgstr ""
22
 
23
+ #: includes/class-freemius.php:1751
24
  msgid "Would you like to proceed with the update?"
25
  msgstr ""
26
 
27
+ #: includes/class-freemius.php:1976
28
  msgid "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
29
  msgstr ""
30
 
31
+ #: includes/class-freemius.php:1978
32
  msgid "Error"
33
  msgstr ""
34
 
35
+ #: includes/class-freemius.php:2424
36
  msgid "I found a better %s"
37
  msgstr ""
38
 
39
+ #: includes/class-freemius.php:2426
40
  msgid "What's the %s's name?"
41
  msgstr ""
42
 
43
+ #: includes/class-freemius.php:2432
44
+ msgid "It's a temporary %s - I'm troubleshooting an issue"
45
  msgstr ""
46
 
47
+ #: includes/class-freemius.php:2434
48
  msgid "Deactivation"
49
  msgstr ""
50
 
51
+ #: includes/class-freemius.php:2435
52
  msgid "Theme Switch"
53
  msgstr ""
54
 
55
+ #: includes/class-freemius.php:2444, templates/forms/resend-key.php:24, templates/forms/user-change.php:29
56
  msgid "Other"
57
  msgstr ""
58
 
59
+ #: includes/class-freemius.php:2452
60
  msgid "I no longer need the %s"
61
  msgstr ""
62
 
63
+ #: includes/class-freemius.php:2459
64
  msgid "I only needed the %s for a short period"
65
  msgstr ""
66
 
67
+ #: includes/class-freemius.php:2465
68
  msgid "The %s broke my site"
69
  msgstr ""
70
 
71
+ #: includes/class-freemius.php:2472
72
  msgid "The %s suddenly stopped working"
73
  msgstr ""
74
 
75
+ #: includes/class-freemius.php:2482
76
  msgid "I can't pay for it anymore"
77
  msgstr ""
78
 
79
+ #: includes/class-freemius.php:2484
80
  msgid "What price would you feel comfortable paying?"
81
  msgstr ""
82
 
83
+ #: includes/class-freemius.php:2490
84
  msgid "I don't like to share my information with you"
85
  msgstr ""
86
 
87
+ #: includes/class-freemius.php:2511
88
  msgid "The %s didn't work"
89
  msgstr ""
90
 
91
+ #: includes/class-freemius.php:2521
92
  msgid "I couldn't understand how to make it work"
93
  msgstr ""
94
 
95
+ #: includes/class-freemius.php:2529
96
  msgid "The %s is great, but I need specific feature that you don't support"
97
  msgstr ""
98
 
99
+ #: includes/class-freemius.php:2531
100
  msgid "What feature?"
101
  msgstr ""
102
 
103
+ #: includes/class-freemius.php:2535
104
  msgid "The %s is not working"
105
  msgstr ""
106
 
107
+ #: includes/class-freemius.php:2537
108
  msgid "Kindly share what didn't work so we can fix it for future users..."
109
  msgstr ""
110
 
111
+ #: includes/class-freemius.php:2541
112
  msgid "It's not what I was looking for"
113
  msgstr ""
114
 
115
+ #: includes/class-freemius.php:2543
116
  msgid "What you've been looking for?"
117
  msgstr ""
118
 
119
+ #: includes/class-freemius.php:2547
120
  msgid "The %s didn't work as expected"
121
  msgstr ""
122
 
123
+ #: includes/class-freemius.php:2549
124
  msgid "What did you expect?"
125
  msgstr ""
126
 
127
+ #: includes/class-freemius.php:3637, templates/debug.php:24
128
  msgid "Freemius Debug"
129
  msgstr ""
130
 
131
+ #: includes/class-freemius.php:4444
132
  msgid "I don't know what is cURL or how to install it, help me!"
133
  msgstr ""
134
 
135
+ #: includes/class-freemius.php:4446
136
  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."
137
  msgstr ""
138
 
139
+ #: includes/class-freemius.php:4453
140
  msgid "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
141
  msgstr ""
142
 
143
+ #: includes/class-freemius.php:4558
144
  msgid "Yes - do your thing"
145
  msgstr ""
146
 
147
+ #: includes/class-freemius.php:4563
148
  msgid "No - just deactivate"
149
  msgstr ""
150
 
151
+ #: includes/class-freemius.php:4608, includes/class-freemius.php:5139, includes/class-freemius.php:6334, includes/class-freemius.php:13998, includes/class-freemius.php:14747, includes/class-freemius.php:18513, includes/class-freemius.php:18618, includes/class-freemius.php:18795, includes/class-freemius.php:21078, includes/class-freemius.php:21456, includes/class-freemius.php:21470, includes/class-freemius.php:22158, includes/class-freemius.php:23174, includes/class-freemius.php:23304, includes/class-freemius.php:23434, templates/add-ons.php:57
152
  msgctxt "exclamation"
153
  msgid "Oops"
154
  msgstr ""
155
 
156
+ #: includes/class-freemius.php:4683
157
  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."
158
  msgstr ""
159
 
160
+ #: includes/class-freemius.php:5108
161
+ msgid "You have purchased a %s license."
162
+ msgstr ""
163
+
164
+ #: includes/class-freemius.php:5112
165
+ msgid " The %s's %sdownload link%s, license key, and installation instructions have been sent to %s. If you can't find the email after 5 min, please check your spam box."
166
+ msgstr ""
167
+
168
+ #: includes/class-freemius.php:5122, includes/class-freemius.php:6031, includes/class-freemius.php:17889, includes/class-freemius.php:17900, includes/class-freemius.php:21347, includes/class-freemius.php:21738, includes/class-freemius.php:21807, includes/class-freemius.php:21979
169
+ msgctxt "interjection expressing joy or exuberance"
170
+ msgid "Yee-haw"
171
+ msgstr ""
172
+
173
+ #: includes/class-freemius.php:5136
174
  msgctxt "addonX cannot run without pluginY"
175
  msgid "%s cannot run without %s."
176
  msgstr ""
177
 
178
+ #: includes/class-freemius.php:5137
179
  msgctxt "addonX cannot run..."
180
  msgid "%s cannot run without the plugin."
181
  msgstr ""
182
 
183
+ #: includes/class-freemius.php:5418
184
+ msgid "There was an unexpected API error while processing your request. Please try again in a few minutes and if it still doesn't work, contact the %s's author with the following:"
185
  msgstr ""
186
 
187
+ #: includes/class-freemius.php:6000
188
  msgid "Premium %s version was successfully activated."
189
  msgstr ""
190
 
191
+ #: includes/class-freemius.php:6012, includes/class-freemius.php:7992
192
  msgctxt "Used to express elation, enthusiasm, or triumph (especially in electronic communication)."
193
  msgid "W00t"
194
  msgstr ""
195
 
196
+ #: includes/class-freemius.php:6027
197
  msgid "You have a %s license."
198
  msgstr ""
199
 
200
+ #: includes/class-freemius.php:6317
 
 
 
 
 
201
  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."
202
  msgstr ""
203
 
204
+ #: includes/class-freemius.php:6321
205
  msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
206
  msgstr ""
207
 
208
+ #: includes/class-freemius.php:6330, templates/add-ons.php:186, templates/account/partials/addon.php:386
209
  msgid "More information about %s"
210
  msgstr ""
211
 
212
+ #: includes/class-freemius.php:6331
213
  msgid "Purchase License"
214
  msgstr ""
215
 
216
+ #: includes/class-freemius.php:7318, templates/connect.php:216
217
  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 %s."
218
  msgstr ""
219
 
220
+ #: includes/class-freemius.php:7322
221
  msgid "start the trial"
222
  msgstr ""
223
 
224
+ #: includes/class-freemius.php:7323, templates/connect.php:220
225
  msgid "complete the install"
226
  msgstr ""
227
 
228
+ #: includes/class-freemius.php:7456
229
  msgid "You are just one step away - %s"
230
  msgstr ""
231
 
232
+ #: includes/class-freemius.php:7459
233
  msgctxt "%s - plugin name. As complete \"PluginX\" activation now"
234
  msgid "Complete \"%s\" Activation Now"
235
  msgstr ""
236
 
237
+ #: includes/class-freemius.php:7541
238
  msgid "We made a few tweaks to the %s, %s"
239
  msgstr ""
240
 
241
+ #: includes/class-freemius.php:7545
242
  msgid "Opt in to make \"%s\" better!"
243
  msgstr ""
244
 
245
+ #: includes/class-freemius.php:7991
246
  msgid "The upgrade of %s was successfully completed."
247
  msgstr ""
248
 
249
+ #: includes/class-freemius.php:10709, includes/class-fs-plugin-updater.php:1089, includes/class-fs-plugin-updater.php:1284, includes/class-fs-plugin-updater.php:1291, templates/auto-installation.php:32
250
  msgid "Add-On"
251
  msgstr ""
252
 
253
+ #: includes/class-freemius.php:10711, templates/account.php:411, templates/account.php:419, templates/debug.php:395, templates/debug.php:615
254
  msgid "Plugin"
255
  msgstr ""
256
 
257
+ #: includes/class-freemius.php:10712, templates/account.php:412, templates/account.php:420, templates/debug.php:395, templates/debug.php:615, templates/forms/deactivation/form.php:107
258
  msgid "Theme"
259
  msgstr ""
260
 
261
+ #: includes/class-freemius.php:13817
262
  msgid "An unknown error has occurred while trying to toggle the license's white-label mode."
263
  msgstr ""
264
 
265
+ #: includes/class-freemius.php:13831
266
  msgid "Your %s license was flagged as white-labeled to hide sensitive information from the WP Admin (e.g. your email, license key, prices, billing address & invoices). If you ever wish to revert it back, you can easily do it through your %s. If this was a mistake you can also %s."
267
  msgstr ""
268
 
269
+ #: includes/class-freemius.php:13836, templates/account/partials/disconnect-button.php:84
270
  msgid "User Dashboard"
271
  msgstr ""
272
 
273
+ #: includes/class-freemius.php:13837
274
  msgid "revert it now"
275
  msgstr ""
276
 
277
+ #: includes/class-freemius.php:13895
278
  msgid "An unknown error has occurred while trying to set the user's beta mode."
279
  msgstr ""
280
 
281
+ #: includes/class-freemius.php:13969
282
  msgid "Invalid new user ID or email address."
283
  msgstr ""
284
 
285
+ #: includes/class-freemius.php:13999
286
  msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
287
  msgstr ""
288
 
289
+ #: includes/class-freemius.php:14000
290
  msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
291
  msgstr ""
292
 
293
+ #: includes/class-freemius.php:14007
294
  msgid "Change Ownership"
295
  msgstr ""
296
 
297
+ #: includes/class-freemius.php:14614
298
  msgid "Invalid site details collection."
299
  msgstr ""
300
 
301
+ #: includes/class-freemius.php:14734
302
  msgid "We couldn't find your email address in the system, are you sure it's the right address?"
303
  msgstr ""
304
 
305
+ #: includes/class-freemius.php:14736
306
  msgid "We can't see any active licenses associated with that email address, are you sure it's the right address?"
307
  msgstr ""
308
 
309
+ #: includes/class-freemius.php:15034
310
+ msgid "Account is pending activation. Please check your email and click the link to activate your account and then submit the affiliate form again."
311
  msgstr ""
312
 
313
+ #: includes/class-freemius.php:15148, templates/forms/premium-versions-upgrade-handler.php:47
314
  msgid "Buy a license now"
315
  msgstr ""
316
 
317
+ #: includes/class-freemius.php:15160, templates/forms/premium-versions-upgrade-handler.php:46
318
  msgid "Renew your license now"
319
  msgstr ""
320
 
321
+ #: includes/class-freemius.php:15164
322
  msgid "%s to access version %s security & feature updates, and support."
323
  msgstr ""
324
 
325
+ #: includes/class-freemius.php:17871
326
+ msgid "%s opt-in was successfully completed."
327
  msgstr ""
328
 
329
+ #: includes/class-freemius.php:17885
330
  msgid "Your account was successfully activated with the %s plan."
331
  msgstr ""
332
 
333
+ #: includes/class-freemius.php:17896, includes/class-freemius.php:21803
334
  msgid "Your trial has been successfully started."
335
  msgstr ""
336
 
337
+ #: includes/class-freemius.php:18511, includes/class-freemius.php:18616, includes/class-freemius.php:18793
338
  msgid "Couldn't activate %s."
339
  msgstr ""
340
 
341
+ #: includes/class-freemius.php:18512, includes/class-freemius.php:18617, includes/class-freemius.php:18794
342
  msgid "Please contact us with the following message:"
343
  msgstr ""
344
 
345
+ #: includes/class-freemius.php:18613, templates/forms/data-debug-mode.php:162
346
  msgid "An unknown error has occurred."
347
  msgstr ""
348
 
349
+ #: includes/class-freemius.php:19153, includes/class-freemius.php:24542
350
  msgid "Upgrade"
351
  msgstr ""
352
 
353
+ #: includes/class-freemius.php:19159
354
  msgid "Start Trial"
355
  msgstr ""
356
 
357
+ #: includes/class-freemius.php:19161
358
  msgid "Pricing"
359
  msgstr ""
360
 
361
+ #: includes/class-freemius.php:19241, includes/class-freemius.php:19243
362
  msgid "Affiliation"
363
  msgstr ""
364
 
365
+ #: includes/class-freemius.php:19271, includes/class-freemius.php:19273, templates/account.php:264, templates/debug.php:362
366
  msgid "Account"
367
  msgstr ""
368
 
369
+ #: includes/class-freemius.php:19287, includes/class-freemius.php:19289, includes/customizer/class-fs-customizer-support-section.php:60
370
  msgid "Contact Us"
371
  msgstr ""
372
 
373
+ #: includes/class-freemius.php:19300, includes/class-freemius.php:19302, includes/class-freemius.php:24556, templates/account.php:134, templates/account/partials/addon.php:49
374
  msgid "Add-Ons"
375
  msgstr ""
376
 
377
+ #: includes/class-freemius.php:19336
378
  msgctxt "ASCII arrow left icon"
379
  msgid "&#x2190;"
380
  msgstr ""
381
 
382
+ #: includes/class-freemius.php:19336
383
  msgctxt "ASCII arrow right icon"
384
  msgid "&#x27a4;"
385
  msgstr ""
386
 
387
+ #: includes/class-freemius.php:19338, templates/pricing.php:110
388
  msgctxt "noun"
389
  msgid "Pricing"
390
  msgstr ""
391
 
392
+ #: includes/class-freemius.php:19551, includes/customizer/class-fs-customizer-support-section.php:67
393
  msgid "Support Forum"
394
  msgstr ""
395
 
396
+ #: includes/class-freemius.php:20572
397
  msgid "Your email has been successfully verified - you are AWESOME!"
398
  msgstr ""
399
 
400
+ #: includes/class-freemius.php:20573
401
  msgctxt "a positive response"
402
  msgid "Right on"
403
  msgstr ""
404
 
405
+ #: includes/class-freemius.php:21079
406
  msgid "seems like the key you entered doesn't match our records."
407
  msgstr ""
408
 
409
+ #: includes/class-freemius.php:21103
410
  msgid "Debug mode was successfully enabled and will be automatically disabled in 60 min. You can also disable it earlier by clicking the \"Stop Debug\" link."
411
  msgstr ""
412
 
413
+ #: includes/class-freemius.php:21338
414
  msgid "Your %s Add-on plan was successfully upgraded."
415
  msgstr ""
416
 
417
+ #: includes/class-freemius.php:21340
418
  msgid "%s Add-on was successfully purchased."
419
  msgstr ""
420
 
421
+ #: includes/class-freemius.php:21343
422
  msgid "Download the latest version"
423
  msgstr ""
424
 
425
+ #: includes/class-freemius.php:21449
426
  msgid "Your server is blocking the access to Freemius' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s"
427
  msgstr ""
428
 
429
+ #: includes/class-freemius.php:21455, includes/class-freemius.php:21469, includes/class-freemius.php:21938, includes/class-freemius.php:22027
430
  msgid "Error received from the server:"
431
  msgstr ""
432
 
433
+ #: includes/class-freemius.php:21469
434
  msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
435
  msgstr ""
436
 
437
+ #: includes/class-freemius.php:21700, includes/class-freemius.php:21943, includes/class-freemius.php:21998, includes/class-freemius.php:22105
438
  msgctxt "something somebody says when they are thinking about what you have just said."
439
  msgid "Hmm"
440
  msgstr ""
441
 
442
+ #: includes/class-freemius.php:21713
443
  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."
444
  msgstr ""
445
 
446
+ #: includes/class-freemius.php:21714, templates/account.php:136, templates/add-ons.php:250, templates/account/partials/addon.php:51
447
  msgctxt "trial period"
448
  msgid "Trial"
449
  msgstr ""
450
 
451
+ #: includes/class-freemius.php:21719
452
  msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
453
  msgstr ""
454
 
455
+ #: includes/class-freemius.php:21723, includes/class-freemius.php:21782
456
  msgid "Please contact us here"
457
  msgstr ""
458
 
459
+ #: includes/class-freemius.php:21734
460
  msgid "Your plan was successfully activated."
461
  msgstr ""
462
 
463
+ #: includes/class-freemius.php:21735
464
  msgid "Your plan was successfully upgraded."
465
  msgstr ""
466
 
467
+ #: includes/class-freemius.php:21752
468
  msgid "Your plan was successfully changed to %s."
469
  msgstr ""
470
 
471
+ #: includes/class-freemius.php:21768
472
  msgid "Your license has expired. You can still continue using the free %s forever."
473
  msgstr ""
474
 
475
+ #: includes/class-freemius.php:21770
476
  msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
477
  msgstr ""
478
 
479
+ #: includes/class-freemius.php:21778
480
  msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
481
  msgstr ""
482
 
483
+ #: includes/class-freemius.php:21791
484
  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."
485
  msgstr ""
486
 
487
+ #: includes/class-freemius.php:21817
488
  msgid "Your free trial has expired. You can still continue using all our free features."
489
  msgstr ""
490
 
491
+ #: includes/class-freemius.php:21819
492
  msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
493
  msgstr ""
494
 
495
+ #: includes/class-freemius.php:21934
496
  msgid "It looks like the license could not be activated."
497
  msgstr ""
498
 
499
+ #: includes/class-freemius.php:21976
500
  msgid "Your license was successfully activated."
501
  msgstr ""
502
 
503
+ #: includes/class-freemius.php:22002
504
  msgid "It looks like your site currently doesn't have an active license."
505
  msgstr ""
506
 
507
+ #: includes/class-freemius.php:22026
508
  msgid "It looks like the license deactivation failed."
509
  msgstr ""
510
 
511
+ #: includes/class-freemius.php:22055
512
  msgid "Your %s license was successfully deactivated."
513
  msgstr ""
514
 
515
+ #: includes/class-freemius.php:22056
516
  msgid "Your license was successfully deactivated, you are back to the %s plan."
517
  msgstr ""
518
 
519
+ #: includes/class-freemius.php:22059
520
  msgid "O.K"
521
  msgstr ""
522
 
523
+ #: includes/class-freemius.php:22112
524
  msgid "Seems like we are having some temporary issue with your subscription cancellation. Please try again in few minutes."
525
  msgstr ""
526
 
527
+ #: includes/class-freemius.php:22121
528
  msgid "Your subscription was successfully cancelled. Your %s plan license will expire in %s."
529
  msgstr ""
530
 
531
+ #: includes/class-freemius.php:22163
532
  msgid "You are already running the %s in a trial mode."
533
  msgstr ""
534
 
535
+ #: includes/class-freemius.php:22174
536
  msgid "You already utilized a trial before."
537
  msgstr ""
538
 
539
+ #: includes/class-freemius.php:22188
540
  msgid "Plan %s do not exist, therefore, can't start a trial."
541
  msgstr ""
542
 
543
+ #: includes/class-freemius.php:22199
544
  msgid "Plan %s does not support a trial period."
545
  msgstr ""
546
 
547
+ #: includes/class-freemius.php:22210
548
  msgid "None of the %s's plans supports a trial period."
549
  msgstr ""
550
 
551
+ #: includes/class-freemius.php:22259
552
  msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
553
  msgstr ""
554
 
555
+ #: includes/class-freemius.php:22295
556
  msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
557
  msgstr ""
558
 
559
+ #: includes/class-freemius.php:22314
560
  msgid "Your %s free trial was successfully cancelled."
561
  msgstr ""
562
 
563
+ #: includes/class-freemius.php:22641
564
  msgid "Version %s was released."
565
  msgstr ""
566
 
567
+ #: includes/class-freemius.php:22641
568
  msgid "Please download %s."
569
  msgstr ""
570
 
571
+ #: includes/class-freemius.php:22648
572
  msgid "the latest %s version here"
573
  msgstr ""
574
 
575
+ #: includes/class-freemius.php:22653
576
  msgid "New"
577
  msgstr ""
578
 
579
+ #: includes/class-freemius.php:22658
580
  msgid "Seems like you got the latest release."
581
  msgstr ""
582
 
583
+ #: includes/class-freemius.php:22659
584
  msgid "You are all good!"
585
  msgstr ""
586
 
587
+ #: includes/class-freemius.php:23062
588
  msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
589
  msgstr ""
590
 
591
+ #: includes/class-freemius.php:23202
592
  msgid "Site successfully opted in."
593
  msgstr ""
594
 
595
+ #: includes/class-freemius.php:23203, includes/class-freemius.php:24252
596
  msgid "Awesome"
597
  msgstr ""
598
 
599
+ #: includes/class-freemius.php:23219
600
+ msgid "Sharing diagnostic data with %s helps to provide functionality that's more relevant to your website, avoid WordPress or PHP version incompatibilities that can break your website, and recognize which languages & regions the plugin should be translated and tailored to."
601
  msgstr ""
602
 
603
+ #: includes/class-freemius.php:23220
604
  msgid "Thank you!"
605
  msgstr ""
606
 
607
+ #: includes/class-freemius.php:23229
608
+ msgid "Diagnostic data will no longer be sent from %s to %s."
609
+ msgstr ""
610
+
611
+ #: includes/class-freemius.php:23384
612
+ msgid "A confirmation email was just sent to %s. The email owner must confirm the update within the next 4 hours."
613
  msgstr ""
614
 
615
+ #: includes/class-freemius.php:23386
616
+ msgid "A confirmation email was just sent to %s. You must confirm the update within the next 4 hours. If you cannot find the email, please check your spam folder."
617
  msgstr ""
618
 
619
+ #: includes/class-freemius.php:23393
620
  msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
621
  msgstr ""
622
 
623
+ #: includes/class-freemius.php:23398
624
  msgid "%s is the new owner of the account."
625
  msgstr ""
626
 
627
+ #: includes/class-freemius.php:23400
628
  msgctxt "as congratulations"
629
  msgid "Congrats"
630
  msgstr ""
631
 
632
+ #: includes/class-freemius.php:23417
 
 
 
 
633
  msgid "Please provide your full name."
634
  msgstr ""
635
 
636
+ #: includes/class-freemius.php:23422
637
  msgid "Your name was successfully updated."
638
  msgstr ""
639
 
640
+ #: includes/class-freemius.php:23483
641
  msgid "You have successfully updated your %s."
642
  msgstr ""
643
 
644
+ #: includes/class-freemius.php:23542
645
  msgid "Is this your client's site? %s if you wish to hide sensitive info like your email, license key, prices, billing address & invoices from the WP Admin."
646
  msgstr ""
647
 
648
+ #: includes/class-freemius.php:23545
649
  msgid "Click here"
650
  msgstr ""
651
 
652
+ #: includes/class-freemius.php:23582, includes/class-freemius.php:23579
653
+ msgid "Bundle"
654
+ msgstr ""
655
+
656
+ #: includes/class-freemius.php:23662
657
  msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
658
  msgstr ""
659
 
660
+ #: includes/class-freemius.php:23663
661
  msgctxt "advance notice of something that will need attention."
662
  msgid "Heads up"
663
  msgstr ""
664
 
665
+ #: includes/class-freemius.php:24292
666
  msgctxt "exclamation"
667
  msgid "Hey"
668
  msgstr ""
669
 
670
+ #: includes/class-freemius.php:24292
671
  msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
672
  msgstr ""
673
 
674
+ #: includes/class-freemius.php:24300
675
  msgid "No commitment for %s days - cancel anytime!"
676
  msgstr ""
677
 
678
+ #: includes/class-freemius.php:24301
679
  msgid "No credit card required"
680
  msgstr ""
681
 
682
+ #: includes/class-freemius.php:24308, templates/forms/trial-start.php:53
683
  msgctxt "call to action"
684
  msgid "Start free trial"
685
  msgstr ""
686
 
687
+ #: includes/class-freemius.php:24385
688
  msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
689
  msgstr ""
690
 
691
+ #: includes/class-freemius.php:24394
692
  msgid "Learn more"
693
  msgstr ""
694
 
695
+ #: includes/class-freemius.php:24580, templates/account.php:573, templates/account.php:725, templates/connect.php:223, templates/connect.php:449, includes/managers/class-fs-clone-manager.php:1295, templates/forms/license-activation.php:27, templates/account/partials/addon.php:326
696
  msgid "Activate License"
697
  msgstr ""
698
 
699
+ #: includes/class-freemius.php:24581, templates/account.php:667, templates/account.php:724, templates/account/partials/addon.php:327, templates/account/partials/site.php:273
700
  msgid "Change License"
701
  msgstr ""
702
 
703
+ #: includes/class-freemius.php:24688, templates/account/partials/site.php:170
704
  msgid "Opt Out"
705
  msgstr ""
706
 
707
+ #: includes/class-freemius.php:24690, includes/class-freemius.php:24696, templates/account/partials/site.php:49, templates/account/partials/site.php:170
708
  msgid "Opt In"
709
  msgstr ""
710
 
711
+ #: includes/class-freemius.php:24933
712
  msgid " The paid version of %1$s is already installed. Please activate it to start benefiting the %2$s features. %3$s"
713
  msgstr ""
714
 
715
+ #: includes/class-freemius.php:24943
716
  msgid "Activate %s features"
717
  msgstr ""
718
 
719
+ #: includes/class-freemius.php:24956
720
  msgid "Please follow these steps to complete the upgrade"
721
  msgstr ""
722
 
723
+ #: includes/class-freemius.php:24960
724
  msgid "Download the latest %s version"
725
  msgstr ""
726
 
727
+ #: includes/class-freemius.php:24964
728
  msgid "Upload and activate the downloaded version"
729
  msgstr ""
730
 
731
+ #: includes/class-freemius.php:24966
732
  msgid "How to upload and activate?"
733
  msgstr ""
734
 
735
+ #: includes/class-freemius.php:25100
736
  msgid "%sClick here%s to choose the sites where you'd like to activate the license on."
737
  msgstr ""
738
 
739
+ #: includes/class-freemius.php:25269
740
  msgid "Auto installation only works for opted-in users."
741
  msgstr ""
742
 
743
+ #: includes/class-freemius.php:25279, includes/class-freemius.php:25312, includes/class-fs-plugin-updater.php:1263, includes/class-fs-plugin-updater.php:1277
744
  msgid "Invalid module ID."
745
  msgstr ""
746
 
747
+ #: includes/class-freemius.php:25288, includes/class-fs-plugin-updater.php:1299
748
  msgid "Premium version already active."
749
  msgstr ""
750
 
751
+ #: includes/class-freemius.php:25295
752
  msgid "You do not have a valid license to access the premium version."
753
  msgstr ""
754
 
755
+ #: includes/class-freemius.php:25302
756
  msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
757
  msgstr ""
758
 
759
+ #: includes/class-freemius.php:25320, includes/class-fs-plugin-updater.php:1298
760
  msgid "Premium add-on version already installed."
761
  msgstr ""
762
 
763
+ #: includes/class-freemius.php:25674
764
  msgid "View paid features"
765
  msgstr ""
766
 
767
+ #: includes/class-freemius.php:25996
768
  msgid "Thank you so much for using %s and its add-ons!"
769
  msgstr ""
770
 
771
+ #: includes/class-freemius.php:25997
772
  msgid "Thank you so much for using %s!"
773
  msgstr ""
774
 
775
+ #: includes/class-freemius.php:26003
776
  msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
777
  msgstr ""
778
 
779
+ #: includes/class-freemius.php:26007
780
  msgid "Thank you so much for using our products!"
781
  msgstr ""
782
 
783
+ #: includes/class-freemius.php:26008
784
  msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
785
  msgstr ""
786
 
787
+ #: includes/class-freemius.php:26027
788
  msgid "%s and its add-ons"
789
  msgstr ""
790
 
791
+ #: includes/class-freemius.php:26036
792
  msgid "Products"
793
  msgstr ""
794
 
795
+ #: includes/class-freemius.php:26043, templates/connect.php:324
796
  msgid "Yes"
797
  msgstr ""
798
 
799
+ #: includes/class-freemius.php:26044, templates/connect.php:325
800
  msgid "send me security & feature updates, educational content and offers."
801
  msgstr ""
802
 
803
+ #: includes/class-freemius.php:26045, templates/connect.php:330
804
  msgid "No"
805
  msgstr ""
806
 
807
+ #: includes/class-freemius.php:26047, templates/connect.php:332
808
  msgid "do %sNOT%s send me security & feature updates, educational content and offers."
809
  msgstr ""
810
 
811
+ #: includes/class-freemius.php:26057
812
  msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard :-)"
813
  msgstr ""
814
 
815
+ #: includes/class-freemius.php:26059, templates/connect.php:339
816
  msgid "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
817
  msgstr ""
818
 
819
+ #: includes/class-freemius.php:26341
820
  msgid "License key is empty."
821
  msgstr ""
822
 
828
  msgid "Buy license"
829
  msgstr ""
830
 
831
+ #: includes/class-fs-plugin-updater.php:331, includes/class-fs-plugin-updater.php:364
832
  msgid "There is a %s of %s available."
833
  msgstr ""
834
 
835
+ #: includes/class-fs-plugin-updater.php:333, includes/class-fs-plugin-updater.php:369
836
  msgid "new Beta version"
837
  msgstr ""
838
 
839
+ #: includes/class-fs-plugin-updater.php:334, includes/class-fs-plugin-updater.php:370
840
  msgid "new version"
841
  msgstr ""
842
 
843
+ #: includes/class-fs-plugin-updater.php:393
844
  msgid "Important Upgrade Notice:"
845
  msgstr ""
846
 
847
+ #: includes/class-fs-plugin-updater.php:1328
848
  msgid "Installing plugin: %s"
849
  msgstr ""
850
 
851
+ #: includes/class-fs-plugin-updater.php:1369
852
  msgid "Unable to connect to the filesystem. Please confirm your credentials."
853
  msgstr ""
854
 
855
+ #: includes/class-fs-plugin-updater.php:1551
856
  msgid "The remote plugin package does not contain a folder with the desired slug and renaming did not work."
857
  msgstr ""
858
 
860
  msgid "Purchase More"
861
  msgstr ""
862
 
863
+ #: includes/fs-plugin-info-dialog.php:542, templates/account/partials/addon.php:390
864
  msgctxt "verb"
865
  msgid "Purchase"
866
  msgstr ""
873
  msgid "Install Free Version Update Now"
874
  msgstr ""
875
 
876
+ #: includes/fs-plugin-info-dialog.php:745, templates/account.php:656
877
  msgid "Install Update Now"
878
  msgstr ""
879
 
881
  msgid "Install Free Version Now"
882
  msgstr ""
883
 
884
+ #: includes/fs-plugin-info-dialog.php:755, templates/add-ons.php:323, templates/auto-installation.php:111, templates/account/partials/addon.php:370, templates/account/partials/addon.php:423
885
  msgid "Install Now"
886
  msgstr ""
887
 
890
  msgid "Download Latest Free Version"
891
  msgstr ""
892
 
893
+ #: includes/fs-plugin-info-dialog.php:772, templates/account.php:114, templates/add-ons.php:37, templates/account/partials/addon.php:30
894
  msgctxt "as download latest version"
895
  msgid "Download Latest"
896
  msgstr ""
897
 
898
+ #: includes/fs-plugin-info-dialog.php:787, templates/add-ons.php:329, templates/account/partials/addon.php:361, templates/account/partials/addon.php:417
899
  msgid "Activate this add-on"
900
  msgstr ""
901
 
902
+ #: includes/fs-plugin-info-dialog.php:789, templates/connect.php:446
903
  msgid "Activate Free Version"
904
  msgstr ""
905
 
906
+ #: includes/fs-plugin-info-dialog.php:790, templates/account.php:138, templates/add-ons.php:330, templates/account/partials/addon.php:53
907
  msgid "Activate"
908
  msgstr ""
909
 
1032
  msgid "Details"
1033
  msgstr ""
1034
 
1035
+ #: includes/fs-plugin-info-dialog.php:1318, templates/account.php:125, templates/debug.php:232, templates/debug.php:269, templates/debug.php:514, templates/account/partials/addon.php:41
1036
  msgctxt "product version"
1037
  msgid "Version"
1038
  msgstr ""
1046
  msgid "Last Updated"
1047
  msgstr ""
1048
 
1049
+ #: includes/fs-plugin-info-dialog.php:1337, templates/account.php:544
1050
  msgctxt "x-ago"
1051
  msgid "%s ago"
1052
  msgstr ""
1155
  msgid "Latest Free Version Installed"
1156
  msgstr ""
1157
 
1158
+ #: templates/account.php:115, templates/forms/subscription-cancellation.php:96, templates/account/partials/addon.php:31, templates/account/partials/site.php:313
1159
  msgid "Downgrading your plan"
1160
  msgstr ""
1161
 
1162
+ #: templates/account.php:116, templates/forms/subscription-cancellation.php:97, templates/account/partials/addon.php:32, templates/account/partials/site.php:314
1163
  msgid "Cancelling the subscription"
1164
  msgstr ""
1165
 
1166
  #. translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription'
1167
+ #: templates/account.php:118, templates/forms/subscription-cancellation.php:99, templates/account/partials/site.php:316
1168
  msgid "%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s."
1169
  msgstr ""
1170
 
1171
+ #: templates/account.php:119, templates/forms/subscription-cancellation.php:100, templates/account/partials/addon.php:35, templates/account/partials/site.php:317
1172
  msgid "Please note that we will not be able to grandfather outdated pricing for renewals/new subscriptions after a cancellation. If you choose to renew the subscription manually in the future, after a price increase, which typically occurs once a year, you will be charged the updated price."
1173
  msgstr ""
1174
 
1175
+ #: templates/account.php:120, templates/forms/subscription-cancellation.php:106, templates/account/partials/addon.php:36
1176
  msgid "Cancelling the trial will immediately block access to all premium features. Are you sure?"
1177
  msgstr ""
1178
 
1179
+ #: templates/account.php:121, templates/forms/subscription-cancellation.php:101, templates/account/partials/addon.php:37, templates/account/partials/site.php:318
1180
  msgid "You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support."
1181
  msgstr ""
1182
 
1183
+ #: templates/account.php:122, templates/forms/subscription-cancellation.php:102, templates/account/partials/addon.php:38, templates/account/partials/site.php:319
1184
  msgid "Once your license expires you can still use the Free version but you will NOT have access to the %s features."
1185
  msgstr ""
1186
 
1187
  #. translators: %s: Plan title (e.g. "Professional")
1188
+ #: templates/account.php:124, templates/account/partials/activate-license-button.php:31, templates/account/partials/addon.php:40
1189
  msgid "Activate %s Plan"
1190
  msgstr ""
1191
 
1192
  #. translators: %s: Time period (e.g. Auto renews in "2 months")
1193
+ #: templates/account.php:127, templates/account/partials/addon.php:43, templates/account/partials/site.php:293
1194
  msgid "Auto renews in %s"
1195
  msgstr ""
1196
 
1197
  #. translators: %s: Time period (e.g. Expires in "2 months")
1198
+ #: templates/account.php:129, templates/account/partials/addon.php:45, templates/account/partials/site.php:295
1199
  msgid "Expires in %s"
1200
  msgstr ""
1201
 
1202
+ #: templates/account.php:130
1203
  msgctxt "as synchronize license"
1204
  msgid "Sync License"
1205
  msgstr ""
1206
 
1207
+ #: templates/account.php:131, templates/account/partials/addon.php:46
1208
  msgid "Cancel Trial"
1209
  msgstr ""
1210
 
1211
+ #: templates/account.php:132, templates/account/partials/addon.php:47
1212
  msgid "Change Plan"
1213
  msgstr ""
1214
 
1215
+ #: templates/account.php:133, templates/account/partials/addon.php:48
1216
  msgctxt "verb"
1217
  msgid "Upgrade"
1218
  msgstr ""
1219
 
1220
+ #: templates/account.php:135, templates/account/partials/addon.php:50, templates/account/partials/site.php:320
1221
  msgctxt "verb"
1222
  msgid "Downgrade"
1223
  msgstr ""
1224
 
1225
+ #: templates/account.php:137, templates/add-ons.php:246, templates/plugin-info/features.php:72, templates/account/partials/addon.php:52, templates/account/partials/site.php:33
1226
  msgid "Free"
1227
  msgstr ""
1228
 
1229
+ #: templates/account.php:139, templates/debug.php:408, includes/customizer/class-fs-customizer-upsell-control.php:110, templates/account/partials/addon.php:54
1230
  msgctxt "as product pricing plan"
1231
  msgid "Plan"
1232
  msgstr ""
1233
 
1234
+ #: templates/account.php:140
1235
  msgid "Bundle Plan"
1236
  msgstr ""
1237
 
1238
+ #: templates/account.php:272
1239
  msgid "Free Trial"
1240
  msgstr ""
1241
 
1242
+ #: templates/account.php:283
1243
  msgid "Account Details"
1244
  msgstr ""
1245
 
1246
+ #: templates/account.php:290, templates/forms/data-debug-mode.php:33
1247
  msgid "Start Debug"
1248
  msgstr ""
1249
 
1250
+ #: templates/account.php:292
1251
  msgid "Stop Debug"
1252
  msgstr ""
1253
 
1254
+ #: templates/account.php:299
1255
  msgid "Billing & Invoices"
1256
  msgstr ""
1257
 
1258
+ #: templates/account.php:322, templates/account/partials/addon.php:236, templates/account/partials/deactivate-license-button.php:35
 
 
 
 
 
 
 
 
 
 
 
 
1259
  msgid "Deactivate License"
1260
  msgstr ""
1261
 
1262
+ #: templates/account.php:345, templates/forms/subscription-cancellation.php:125
1263
  msgid "Are you sure you want to proceed?"
1264
  msgstr ""
1265
 
1266
+ #: templates/account.php:345, templates/account/partials/addon.php:260
1267
  msgid "Cancel Subscription"
1268
  msgstr ""
1269
 
1270
+ #: templates/account.php:374, templates/account/partials/addon.php:345
1271
  msgctxt "as synchronize"
1272
  msgid "Sync"
1273
  msgstr ""
1274
 
1275
+ #: templates/account.php:389, templates/debug.php:571
1276
  msgid "Name"
1277
  msgstr ""
1278
 
1279
+ #: templates/account.php:395, templates/debug.php:572
1280
  msgid "Email"
1281
  msgstr ""
1282
 
1283
+ #: templates/account.php:402, templates/debug.php:406, templates/debug.php:621
1284
  msgid "User ID"
1285
  msgstr ""
1286
 
1287
+ #: templates/account.php:420, templates/account.php:738, templates/account.php:789, templates/debug.php:267, templates/debug.php:400, templates/debug.php:511, templates/debug.php:570, templates/debug.php:619, templates/debug.php:698, templates/account/payments.php:35, templates/debug/logger.php:21
1288
  msgid "ID"
1289
  msgstr ""
1290
 
1291
+ #: templates/account.php:427
1292
  msgid "Site ID"
1293
  msgstr ""
1294
 
1295
+ #: templates/account.php:430
1296
  msgid "No ID"
1297
  msgstr ""
1298
 
1299
+ #: templates/account.php:435, templates/debug.php:274, templates/debug.php:409, templates/debug.php:515, templates/debug.php:574, templates/account/partials/site.php:228
1300
  msgid "Public Key"
1301
  msgstr ""
1302
 
1303
+ #: templates/account.php:441, templates/debug.php:410, templates/debug.php:516, templates/debug.php:575, templates/account/partials/site.php:241
1304
  msgid "Secret Key"
1305
  msgstr ""
1306
 
1307
+ #: templates/account.php:444
1308
  msgctxt "as secret encryption key missing"
1309
  msgid "No Secret"
1310
  msgstr ""
1311
 
1312
+ #: templates/account.php:471, templates/account/partials/site.php:120, templates/account/partials/site.php:122
1313
  msgid "Trial"
1314
  msgstr ""
1315
 
1316
+ #: templates/account.php:498, templates/debug.php:627, templates/account/partials/site.php:262
1317
  msgid "License Key"
1318
  msgstr ""
1319
 
1320
+ #: templates/account.php:529
1321
  msgid "Join the Beta program"
1322
  msgstr ""
1323
 
1324
+ #: templates/account.php:535
1325
  msgid "not verified"
1326
  msgstr ""
1327
 
1328
+ #: templates/account.php:544, templates/account/partials/addon.php:195
1329
  msgid "Expired"
1330
  msgstr ""
1331
 
1332
+ #: templates/account.php:602
1333
  msgid "Premium version"
1334
  msgstr ""
1335
 
1336
+ #: templates/account.php:604
1337
  msgid "Free version"
1338
  msgstr ""
1339
 
1340
+ #: templates/account.php:616
1341
  msgid "Verify Email"
1342
  msgstr ""
1343
 
1344
+ #: templates/account.php:630
1345
  msgid "Download %s Version"
1346
  msgstr ""
1347
 
1348
+ #: templates/account.php:646
1349
  msgid "Download Paid Version"
1350
  msgstr ""
1351
 
1352
+ #: templates/account.php:664, templates/account.php:927, templates/account/partials/site.php:250, templates/account/partials/site.php:272
1353
  msgctxt "verb"
1354
  msgid "Show"
1355
  msgstr ""
1356
 
1357
+ #: templates/account.php:680
1358
  msgid "What is your %s?"
1359
  msgstr ""
1360
 
1361
+ #: templates/account.php:688, templates/account/billing.php:21
1362
  msgctxt "verb"
1363
  msgid "Edit"
1364
  msgstr ""
1365
 
1366
+ #: templates/account.php:693, templates/forms/user-change.php:27
1367
  msgid "Change User"
1368
  msgstr ""
1369
 
1370
+ #: templates/account.php:717
1371
  msgid "Sites"
1372
  msgstr ""
1373
 
1374
+ #: templates/account.php:730
1375
  msgid "Search by address"
1376
  msgstr ""
1377
 
1378
+ #: templates/account.php:739, templates/debug.php:403
1379
  msgid "Address"
1380
  msgstr ""
1381
 
1382
+ #: templates/account.php:740
1383
  msgid "License"
1384
  msgstr ""
1385
 
1386
+ #: templates/account.php:741
1387
  msgid "Plan"
1388
  msgstr ""
1389
 
1390
+ #: templates/account.php:792
1391
  msgctxt "as software license"
1392
  msgid "License"
1393
  msgstr ""
1394
 
1395
+ #: templates/account.php:921
1396
  msgctxt "verb"
1397
  msgid "Hide"
1398
  msgstr ""
1399
 
1400
+ #: templates/account.php:943, templates/forms/data-debug-mode.php:31, templates/forms/deactivation/form.php:358, templates/forms/deactivation/form.php:389
1401
  msgid "Processing"
1402
  msgstr ""
1403
 
1404
+ #: templates/account.php:946
1405
  msgid "Get updates for bleeding edge Beta versions of %s."
1406
  msgstr ""
1407
 
1408
+ #: templates/account.php:1004
1409
  msgid "Cancelling %s"
1410
  msgstr ""
1411
 
1412
+ #: templates/account.php:1004, templates/account.php:1021, templates/forms/subscription-cancellation.php:27, templates/forms/deactivation/form.php:178
1413
  msgid "trial"
1414
  msgstr ""
1415
 
1416
+ #: templates/account.php:1019, templates/forms/deactivation/form.php:195
1417
  msgid "Cancelling %s..."
1418
  msgstr ""
1419
 
1420
+ #: templates/account.php:1022, templates/forms/subscription-cancellation.php:28, templates/forms/deactivation/form.php:179
1421
  msgid "subscription"
1422
  msgstr ""
1423
 
1424
+ #: templates/account.php:1036
1425
  msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
1426
  msgstr ""
1427
 
1428
+ #: templates/account.php:1110
1429
  msgid "Disabling white-label mode"
1430
  msgstr ""
1431
 
1432
+ #: templates/account.php:1111
1433
  msgid "Enabling white-label mode"
1434
  msgstr ""
1435
 
1455
  msgid "Installed"
1456
  msgstr ""
1457
 
1458
+ #: templates/admin-notice.php:13, templates/forms/license-activation.php:243, templates/forms/resend-key.php:80
1459
  msgctxt "as close a window"
1460
  msgid "Dismiss"
1461
  msgstr ""
1489
  msgstr ""
1490
 
1491
  #. translators: %s: name (e.g. Hey John,)
1492
+ #: templates/connect.php:121
1493
  msgctxt "greeting"
1494
  msgid "Hey %s,"
1495
  msgstr ""
1496
 
1497
+ #: templates/connect.php:189
1498
+ msgid "Never miss an important update"
1499
+ msgstr ""
1500
+
1501
+ #: templates/connect.php:197
1502
+ msgid "Thank you for updating to %1$s v%2$s!"
1503
+ msgstr ""
1504
+
1505
+ #: templates/connect.php:207
1506
  msgid "Allow & Continue"
1507
  msgstr ""
1508
 
1509
+ #: templates/connect.php:211
1510
  msgid "Re-send activation email"
1511
  msgstr ""
1512
 
1513
+ #: templates/connect.php:215
1514
  msgid "Thanks %s!"
1515
  msgstr ""
1516
 
1517
+ #: templates/connect.php:227
1518
+ msgid "Welcome to %s! To get started, please enter your license key:"
1519
  msgstr ""
1520
 
1521
+ #: templates/connect.php:237
1522
+ msgid "Opt in to get email notifications for security & feature updates, educational content, and occasional offers, and to share some basic WordPress environment info. This will help us make the %s more compatible with your site and better at doing what you need it to."
1523
  msgstr ""
1524
 
1525
+ #: templates/connect.php:239
1526
+ msgid "Opt in to get email notifications for security & feature updates, and to share some basic WordPress environment info. This will help us make the %s more compatible with your site and better at doing what you need it to."
1527
  msgstr ""
1528
 
1529
+ #. translators: %s: module type (plugin, theme, or add-on)
1530
+ #: templates/connect.php:245
1531
+ msgid "We have introduced this opt-in so you never miss an important update and help us make the %s more compatible with your site and better at doing what you need it to."
1532
  msgstr ""
1533
 
1534
+ #: templates/connect.php:248
1535
+ msgid "Opt in to get email notifications for security & feature updates, educational content, and occasional offers, and to share some basic WordPress environment info."
1536
  msgstr ""
1537
 
1538
+ #: templates/connect.php:249
1539
+ msgid "Opt in to get email notifications for security & feature updates, and to share some basic WordPress environment info."
1540
  msgstr ""
1541
 
1542
+ #: templates/connect.php:252
1543
+ msgid "If you skip this, that's okay! %1$s will still work just fine."
1544
+ msgstr ""
1545
+
1546
+ #: templates/connect.php:282
1547
  msgid "We're excited to introduce the Freemius network-level integration."
1548
  msgstr ""
1549
 
1550
+ #: templates/connect.php:285
1551
  msgid "During the update process we detected %d site(s) that are still pending license activation."
1552
  msgstr ""
1553
 
1554
+ #: templates/connect.php:287
1555
  msgid "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
1556
  msgstr ""
1557
 
1558
+ #: templates/connect.php:289
1559
  msgid "%s's paid features"
1560
  msgstr ""
1561
 
1562
+ #: templates/connect.php:294
1563
  msgid "Alternatively, you can skip it for now and activate the license later, in your %s's network-level Account page."
1564
  msgstr ""
1565
 
1566
+ #: templates/connect.php:296
1567
  msgid "During the update process we detected %s site(s) in the network that are still pending your attention."
1568
  msgstr ""
1569
 
1570
+ #: templates/connect.php:305, templates/forms/data-debug-mode.php:35, templates/forms/license-activation.php:42
1571
  msgid "License key"
1572
  msgstr ""
1573
 
1574
+ #: templates/connect.php:308, templates/forms/license-activation.php:22
1575
  msgid "Can't find your license key?"
1576
  msgstr ""
1577
 
1578
+ #: templates/connect.php:371, templates/connect.php:695, templates/forms/deactivation/retry-skip.php:20
1579
  msgctxt "verb"
1580
  msgid "Skip"
1581
  msgstr ""
1582
 
1583
+ #: templates/connect.php:374
1584
  msgid "Delegate to Site Admins"
1585
  msgstr ""
1586
 
1587
+ #: templates/connect.php:374
1588
  msgid "If you click it, this decision will be delegated to the sites administrators."
1589
  msgstr ""
1590
 
1591
+ #: templates/connect.php:401
1592
  msgid "License issues?"
1593
  msgstr ""
1594
 
1595
+ #: templates/connect.php:425
1596
+ msgid "For delivery of security & feature updates, and license management, %s needs to"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1597
  msgstr ""
1598
 
1599
  #: templates/connect.php:430
1600
+ msgid "This will allow %s to"
1601
  msgstr ""
1602
 
1603
+ #: templates/connect.php:445
1604
  msgid "Don't have a license key?"
1605
  msgstr ""
1606
 
1607
+ #: templates/connect.php:448
1608
  msgid "Have a license key?"
1609
  msgstr ""
1610
 
1611
+ #: templates/connect.php:456
1612
+ msgid "Freemius is our licensing and software updates engine"
1613
+ msgstr ""
1614
+
1615
+ #: templates/connect.php:459
1616
  msgid "Privacy Policy"
1617
  msgstr ""
1618
 
1619
+ #: templates/connect.php:461
1620
  msgid "License Agreement"
1621
  msgstr ""
1622
 
1623
+ #: templates/connect.php:461
1624
  msgid "Terms of Service"
1625
  msgstr ""
1626
 
1627
+ #: templates/connect.php:881
1628
  msgctxt "as in the process of sending an email"
1629
  msgid "Sending email"
1630
  msgstr ""
1631
 
1632
+ #: templates/connect.php:882
1633
  msgctxt "as activating plugin"
1634
  msgid "Activating"
1635
  msgstr ""
1648
  msgid "On"
1649
  msgstr ""
1650
 
1651
+ #: templates/debug.php:24
1652
  msgid "SDK"
1653
  msgstr ""
1654
 
1655
+ #: templates/debug.php:28
1656
  msgctxt "as code debugging"
1657
  msgid "Debugging"
1658
  msgstr ""
1659
 
1660
+ #: templates/debug.php:58, templates/debug.php:279, templates/debug.php:411, templates/debug.php:576
1661
  msgid "Actions"
1662
  msgstr ""
1663
 
1664
+ #: templates/debug.php:68
1665
  msgid "Are you sure you want to delete all Freemius data?"
1666
  msgstr ""
1667
 
1668
+ #: templates/debug.php:68
1669
  msgid "Delete All Accounts"
1670
  msgstr ""
1671
 
1672
+ #: templates/debug.php:75
1673
  msgid "Clear API Cache"
1674
  msgstr ""
1675
 
1676
+ #: templates/debug.php:83
1677
  msgid "Clear Updates Transients"
1678
  msgstr ""
1679
 
1680
+ #: templates/debug.php:92
1681
+ msgid "Reset Deactivation Snoozing"
1682
+ msgstr ""
1683
+
1684
+ #: templates/debug.php:100
1685
  msgid "Sync Data From Server"
1686
  msgstr ""
1687
 
1688
+ #: templates/debug.php:109
1689
  msgid "Migrate Options to Network"
1690
  msgstr ""
1691
 
1692
+ #: templates/debug.php:114
1693
  msgid "Load DB Option"
1694
  msgstr ""
1695
 
1696
+ #: templates/debug.php:117
1697
  msgid "Set DB Option"
1698
  msgstr ""
1699
 
1700
+ #: templates/debug.php:211
1701
  msgid "Key"
1702
  msgstr ""
1703
 
1704
+ #: templates/debug.php:212
1705
  msgid "Value"
1706
  msgstr ""
1707
 
1708
+ #: templates/debug.php:228
1709
  msgctxt "as software development kit versions"
1710
  msgid "SDK Versions"
1711
  msgstr ""
1712
 
1713
+ #: templates/debug.php:233
1714
  msgid "SDK Path"
1715
  msgstr ""
1716
 
1717
+ #: templates/debug.php:234, templates/debug.php:273
1718
  msgid "Module Path"
1719
  msgstr ""
1720
 
1721
+ #: templates/debug.php:235
1722
  msgid "Is Active"
1723
  msgstr ""
1724
 
1725
+ #: templates/debug.php:263, templates/debug/plugins-themes-sync.php:35
1726
  msgid "Plugins"
1727
  msgstr ""
1728
 
1729
+ #: templates/debug.php:263, templates/debug/plugins-themes-sync.php:56
1730
  msgid "Themes"
1731
  msgstr ""
1732
 
1733
+ #: templates/debug.php:268, templates/debug.php:405, templates/debug.php:513, templates/debug/scheduled-crons.php:80
1734
  msgid "Slug"
1735
  msgstr ""
1736
 
1737
+ #: templates/debug.php:270, templates/debug.php:512
1738
  msgid "Title"
1739
  msgstr ""
1740
 
1741
+ #: templates/debug.php:271
1742
  msgctxt "as application program interface"
1743
  msgid "API"
1744
  msgstr ""
1745
 
1746
+ #: templates/debug.php:272
1747
  msgid "Freemius State"
1748
  msgstr ""
1749
 
1750
+ #: templates/debug.php:276
1751
  msgid "Network Blog"
1752
  msgstr ""
1753
 
1754
+ #: templates/debug.php:277
1755
  msgid "Network User"
1756
  msgstr ""
1757
 
1758
+ #: templates/debug.php:321
1759
  msgctxt "as connection was successful"
1760
  msgid "Connected"
1761
  msgstr ""
1762
 
1763
+ #: templates/debug.php:322
1764
  msgctxt "as connection blocked"
1765
  msgid "Blocked"
1766
  msgstr ""
1767
 
1768
+ #: templates/debug.php:358
1769
  msgid "Simulate Trial Promotion"
1770
  msgstr ""
1771
 
1772
+ #: templates/debug.php:370
1773
  msgid "Simulate Network Upgrade"
1774
  msgstr ""
1775
 
1776
+ #: templates/debug.php:394
1777
  msgid "%s Installs"
1778
  msgstr ""
1779
 
1780
+ #: templates/debug.php:396
1781
  msgctxt "like websites"
1782
  msgid "Sites"
1783
  msgstr ""
1784
 
1785
+ #: templates/debug.php:402, templates/account/partials/site.php:156
1786
  msgid "Blog ID"
1787
  msgstr ""
1788
 
1789
+ #: templates/debug.php:407
1790
  msgid "License ID"
1791
  msgstr ""
1792
 
1793
+ #: templates/debug.php:493, templates/debug.php:599, templates/account/partials/addon.php:440
1794
  msgctxt "verb"
1795
  msgid "Delete"
1796
  msgstr ""
1797
 
1798
+ #: templates/debug.php:507
1799
  msgid "Add Ons of module %s"
1800
  msgstr ""
1801
 
1802
+ #: templates/debug.php:566
1803
  msgid "Users"
1804
  msgstr ""
1805
 
1806
+ #: templates/debug.php:573
1807
  msgid "Verified"
1808
  msgstr ""
1809
 
1810
+ #: templates/debug.php:615
1811
  msgid "%s Licenses"
1812
  msgstr ""
1813
 
1814
+ #: templates/debug.php:620
1815
  msgid "Plugin ID"
1816
  msgstr ""
1817
 
1818
+ #: templates/debug.php:622
1819
  msgid "Plan ID"
1820
  msgstr ""
1821
 
1822
+ #: templates/debug.php:623
1823
  msgid "Quota"
1824
  msgstr ""
1825
 
1826
+ #: templates/debug.php:624
1827
  msgid "Activated"
1828
  msgstr ""
1829
 
1830
+ #: templates/debug.php:625
1831
  msgid "Blocking"
1832
  msgstr ""
1833
 
1834
+ #: templates/debug.php:626, templates/debug.php:697, templates/debug/logger.php:22
1835
  msgid "Type"
1836
  msgstr ""
1837
 
1838
+ #: templates/debug.php:628
1839
  msgctxt "as expiration date"
1840
  msgid "Expiration"
1841
  msgstr ""
1842
 
1843
+ #: templates/debug.php:656
1844
  msgid "Debug Log"
1845
  msgstr ""
1846
 
1847
+ #: templates/debug.php:660
1848
  msgid "All Types"
1849
  msgstr ""
1850
 
1851
+ #: templates/debug.php:667
1852
  msgid "All Requests"
1853
  msgstr ""
1854
 
1855
+ #: templates/debug.php:672, templates/debug.php:701, templates/debug/logger.php:25
1856
  msgid "File"
1857
  msgstr ""
1858
 
1859
+ #: templates/debug.php:673, templates/debug.php:699, templates/debug/logger.php:23
1860
  msgid "Function"
1861
  msgstr ""
1862
 
1863
+ #: templates/debug.php:674
1864
  msgid "Process ID"
1865
  msgstr ""
1866
 
1867
+ #: templates/debug.php:675
1868
  msgid "Logger"
1869
  msgstr ""
1870
 
1871
+ #: templates/debug.php:676, templates/debug.php:700, templates/debug/logger.php:24
1872
  msgid "Message"
1873
  msgstr ""
1874
 
1875
+ #: templates/debug.php:678
1876
  msgid "Filter"
1877
  msgstr ""
1878
 
1879
+ #: templates/debug.php:686
1880
  msgid "Download"
1881
  msgstr ""
1882
 
1883
+ #: templates/debug.php:702, templates/debug/logger.php:26
1884
  msgid "Timestamp"
1885
  msgstr ""
1886
 
1905
  msgid "Requests"
1906
  msgstr ""
1907
 
1908
+ #: includes/managers/class-fs-clone-manager.php:839
1909
+ msgid "Invalid clone resolution action."
1910
+ msgstr ""
1911
+
1912
+ #: includes/managers/class-fs-clone-manager.php:1024
1913
+ msgid "products"
1914
+ msgstr ""
1915
+
1916
+ #: includes/managers/class-fs-clone-manager.php:1205
1917
+ msgid "%1$s has been placed into safe mode because we noticed that %2$s is an exact copy of %3$s."
1918
+ msgstr ""
1919
+
1920
+ #: includes/managers/class-fs-clone-manager.php:1211
1921
+ msgid "The products below have been placed into safe mode because we noticed that %2$s is an exact copy of %3$s:%1$s"
1922
+ msgstr ""
1923
+
1924
+ #: includes/managers/class-fs-clone-manager.php:1212
1925
+ msgid "The products below have been placed into safe mode because we noticed that %2$s is an exact copy of these sites:%3$s%1$s"
1926
+ msgstr ""
1927
+
1928
+ #: includes/managers/class-fs-clone-manager.php:1238
1929
+ msgid "the above-mentioned sites"
1930
+ msgstr ""
1931
+
1932
+ #: includes/managers/class-fs-clone-manager.php:1251
1933
+ msgid "Is %2$s a duplicate of %4$s?"
1934
+ msgstr ""
1935
+
1936
+ #: includes/managers/class-fs-clone-manager.php:1252
1937
+ msgid "Yes, %2$s is a duplicate of %4$s for the purpose of testing, staging, or development."
1938
+ msgstr ""
1939
+
1940
+ #: includes/managers/class-fs-clone-manager.php:1257
1941
+ msgid "Long-Term Duplicate"
1942
+ msgstr ""
1943
+
1944
+ #: includes/managers/class-fs-clone-manager.php:1262
1945
+ msgid "Duplicate Website"
1946
+ msgstr ""
1947
+
1948
+ #: includes/managers/class-fs-clone-manager.php:1268
1949
+ msgid "Is %2$s the new home of %4$s?"
1950
+ msgstr ""
1951
+
1952
+ #: includes/managers/class-fs-clone-manager.php:1270
1953
+ msgid "Yes, %%2$s is replacing %%4$s. I would like to migrate my %s from %%4$s to %%2$s."
1954
+ msgstr ""
1955
+
1956
+ #: includes/managers/class-fs-clone-manager.php:1271, templates/forms/subscription-cancellation.php:52
1957
+ msgid "license"
1958
+ msgstr ""
1959
+
1960
+ #: includes/managers/class-fs-clone-manager.php:1271
1961
+ msgid "data"
1962
+ msgstr ""
1963
+
1964
+ #: includes/managers/class-fs-clone-manager.php:1277
1965
+ msgid "Migrate License"
1966
+ msgstr ""
1967
+
1968
+ #: includes/managers/class-fs-clone-manager.php:1278
1969
+ msgid "Migrate"
1970
+ msgstr ""
1971
+
1972
+ #: includes/managers/class-fs-clone-manager.php:1284
1973
+ msgid "Is %2$s a new website?"
1974
+ msgstr ""
1975
+
1976
+ #: includes/managers/class-fs-clone-manager.php:1285
1977
+ msgid "Yes, %2$s is a new and different website that is separate from %4$s."
1978
+ msgstr ""
1979
+
1980
+ #: includes/managers/class-fs-clone-manager.php:1287
1981
+ msgid "It requires license activation."
1982
+ msgstr ""
1983
+
1984
+ #: includes/managers/class-fs-clone-manager.php:1294
1985
+ msgid "New Website"
1986
+ msgstr ""
1987
+
1988
+ #: includes/managers/class-fs-clone-manager.php:1319
1989
+ msgctxt "Clone resolution admin notice products list label"
1990
+ msgid "Products"
1991
+ msgstr ""
1992
+
1993
+ #: includes/managers/class-fs-clone-manager.php:1408
1994
+ msgid "You marked this website, %s, as a temporary duplicate of %s."
1995
+ msgstr ""
1996
+
1997
+ #: includes/managers/class-fs-clone-manager.php:1409
1998
+ msgid "You marked this website, %s, as a temporary duplicate of these sites"
1999
+ msgstr ""
2000
+
2001
+ #: includes/managers/class-fs-clone-manager.php:1423
2002
+ msgid "%s automatic security & feature updates and paid functionality will keep working without interruptions until %s (or when your license expires, whatever comes first)."
2003
+ msgstr ""
2004
+
2005
+ #: includes/managers/class-fs-clone-manager.php:1426
2006
+ msgctxt "\"The <product_label>\", e.g.: \"The plugin\""
2007
+ msgid "The %s's"
2008
+ msgstr ""
2009
+
2010
+ #: includes/managers/class-fs-clone-manager.php:1429
2011
+ msgid "The following products'"
2012
+ msgstr ""
2013
+
2014
+ #: includes/managers/class-fs-clone-manager.php:1437
2015
+ msgid "If this is a long term duplicate, to keep automatic updates and paid functionality after %s, please %s."
2016
+ msgstr ""
2017
+
2018
+ #: includes/managers/class-fs-clone-manager.php:1439
2019
+ msgid "activate a license here"
2020
+ msgstr ""
2021
+
2022
+ #: includes/managers/class-fs-permission-manager.php:182
2023
+ msgid "View Basic Website Info"
2024
+ msgstr ""
2025
+
2026
+ #: includes/managers/class-fs-permission-manager.php:183
2027
+ msgid "Homepage URL & title, WP & PHP versions, and site language"
2028
+ msgstr ""
2029
+
2030
+ #: includes/managers/class-fs-permission-manager.php:186
2031
+ msgid "To provide additional functionality that's relevant to your website, avoid WordPress or PHP version incompatibilities that can break your website, and recognize which languages & regions the %s should be translated and tailored to."
2032
+ msgstr ""
2033
+
2034
+ #: includes/managers/class-fs-permission-manager.php:198
2035
+ msgid "View Basic %s Info"
2036
+ msgstr ""
2037
+
2038
+ #: includes/managers/class-fs-permission-manager.php:201
2039
+ msgid "Current %s & SDK versions, and if active or uninstalled"
2040
+ msgstr ""
2041
+
2042
+ #: includes/managers/class-fs-permission-manager.php:252
2043
+ msgid "View License Essentials"
2044
+ msgstr ""
2045
+
2046
+ #: includes/managers/class-fs-permission-manager.php:253
2047
+ msgstr ""
2048
+
2049
+ #: includes/managers/class-fs-permission-manager.php:263
2050
+ msgid "To let you manage & control where the license is activated and ensure %s security & feature updates are only delivered to websites you authorize."
2051
+ msgstr ""
2052
+
2053
+ #: includes/managers/class-fs-permission-manager.php:275
2054
+ msgid "View %s State"
2055
+ msgstr ""
2056
+
2057
+ #: includes/managers/class-fs-permission-manager.php:278
2058
+ msgid "Is active, deactivated, or uninstalled"
2059
+ msgstr ""
2060
+
2061
+ #: includes/managers/class-fs-permission-manager.php:281
2062
+ msgid "So you can reuse the license when the %s is no longer active."
2063
+ msgstr ""
2064
+
2065
+ #: includes/managers/class-fs-permission-manager.php:317
2066
+ msgid "View Diagnostic Info"
2067
+ msgstr ""
2068
+
2069
+ #: includes/managers/class-fs-permission-manager.php:317, includes/managers/class-fs-permission-manager.php:354
2070
+ msgid "optional"
2071
+ msgstr ""
2072
+
2073
+ #: includes/managers/class-fs-permission-manager.php:318
2074
+ msgid "WordPress & PHP versions, site language & title"
2075
+ msgstr ""
2076
+
2077
+ #: includes/managers/class-fs-permission-manager.php:321
2078
+ msgid "To avoid breaking your website due to WordPress or PHP version incompatibilities, and recognize which languages & regions the %s should be translated and tailored to."
2079
+ msgstr ""
2080
+
2081
+ #: includes/managers/class-fs-permission-manager.php:354
2082
+ msgid "View Plugins & Themes List"
2083
+ msgstr ""
2084
+
2085
+ #: includes/managers/class-fs-permission-manager.php:355
2086
+ msgid "Names, slugs, versions, and if active or not"
2087
+ msgstr ""
2088
+
2089
+ #: includes/managers/class-fs-permission-manager.php:356
2090
+ msgid "To ensure compatibility and avoid conflicts with your installed plugins and themes."
2091
+ msgstr ""
2092
+
2093
+ #: includes/managers/class-fs-permission-manager.php:373
2094
+ msgid "View Basic Profile Info"
2095
+ msgstr ""
2096
+
2097
+ #: includes/managers/class-fs-permission-manager.php:374
2098
+ msgid "Your WordPress user's: first & last name, and email address"
2099
+ msgstr ""
2100
+
2101
+ #: includes/managers/class-fs-permission-manager.php:375
2102
+ msgid "Never miss important updates, get security warnings before they become public knowledge, and receive notifications about special offers and awesome new features."
2103
+ msgstr ""
2104
+
2105
+ #: includes/managers/class-fs-permission-manager.php:396
2106
+ msgid "Newsletter"
2107
+ msgstr ""
2108
+
2109
+ #: includes/managers/class-fs-permission-manager.php:397
2110
+ msgid "Updates, announcements, marketing, no spam"
2111
+ msgstr ""
2112
+
2113
  #: templates/account/billing.php:22
2114
  msgctxt "verb"
2115
  msgid "Update"
2175
  msgid "Invoice"
2176
  msgstr ""
2177
 
2178
+ #: templates/connect/permissions-group.php:31, templates/forms/optout.php:26, templates/js/permissions.php:78
2179
+ msgctxt "verb"
2180
+ msgid "Opt Out"
2181
+ msgstr ""
2182
+
2183
+ #: templates/connect/permissions-group.php:32, templates/js/permissions.php:77
2184
+ msgctxt "verb"
2185
+ msgid "Opt In"
2186
+ msgstr ""
2187
+
2188
  #: templates/debug/api-calls.php:56
2189
  msgid "API"
2190
  msgstr ""
2273
  msgid "Next"
2274
  msgstr ""
2275
 
2276
+ #: templates/forms/affiliation.php:83
2277
  msgid "Non-expiring"
2278
  msgstr ""
2279
 
2280
+ #: templates/forms/affiliation.php:86
2281
  msgid "Apply to become an affiliate"
2282
  msgstr ""
2283
 
2284
+ #: templates/forms/affiliation.php:108
2285
  msgid "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s."
2286
  msgstr ""
2287
 
2288
+ #: templates/forms/affiliation.php:123
2289
  msgid "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information."
2290
  msgstr ""
2291
 
2292
+ #: templates/forms/affiliation.php:126
2293
  msgid "Your affiliation account was temporarily suspended."
2294
  msgstr ""
2295
 
2296
+ #: templates/forms/affiliation.php:129
2297
  msgid "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days."
2298
  msgstr ""
2299
 
2300
+ #: templates/forms/affiliation.php:132
2301
  msgid "Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support."
2302
  msgstr ""
2303
 
2304
+ #: templates/forms/affiliation.php:145
2305
  msgid "Like the %s? Become our ambassador and earn cash ;-)"
2306
  msgstr ""
2307
 
2308
+ #: templates/forms/affiliation.php:146
2309
  msgid "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
2310
  msgstr ""
2311
 
2312
+ #: templates/forms/affiliation.php:149
2313
  msgid "Program Summary"
2314
  msgstr ""
2315
 
2316
+ #: templates/forms/affiliation.php:151
2317
  msgid "%s commission when a customer purchases a new license."
2318
  msgstr ""
2319
 
2320
+ #: templates/forms/affiliation.php:153
2321
  msgid "Get commission for automated subscription renewals."
2322
  msgstr ""
2323
 
2324
+ #: templates/forms/affiliation.php:156
2325
  msgid "%s tracking cookie after the first visit to maximize earnings potential."
2326
  msgstr ""
2327
 
2328
+ #: templates/forms/affiliation.php:159
2329
  msgid "Unlimited commissions."
2330
  msgstr ""
2331
 
2332
+ #: templates/forms/affiliation.php:161
2333
  msgid "%s minimum payout amount."
2334
  msgstr ""
2335
 
2336
+ #: templates/forms/affiliation.php:162
2337
  msgid "Payouts are in USD and processed monthly via PayPal."
2338
  msgstr ""
2339
 
2340
+ #: templates/forms/affiliation.php:163
2341
  msgid "As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days."
2342
  msgstr ""
2343
 
2344
+ #: templates/forms/affiliation.php:166
2345
  msgid "Affiliate"
2346
  msgstr ""
2347
 
2348
+ #: templates/forms/affiliation.php:169, templates/forms/resend-key.php:23
2349
  msgid "Email address"
2350
  msgstr ""
2351
 
2352
+ #: templates/forms/affiliation.php:173
2353
  msgid "Full name"
2354
  msgstr ""
2355
 
2356
+ #: templates/forms/affiliation.php:177
2357
  msgid "PayPal account email address"
2358
  msgstr ""
2359
 
2360
+ #: templates/forms/affiliation.php:181
2361
  msgid "Where are you going to promote the %s?"
2362
  msgstr ""
2363
 
2364
+ #: templates/forms/affiliation.php:183
2365
  msgid "Enter the domain of your website or other websites from where you plan to promote the %s."
2366
  msgstr ""
2367
 
2368
+ #: templates/forms/affiliation.php:185
2369
  msgid "Add another domain"
2370
  msgstr ""
2371
 
2372
+ #: templates/forms/affiliation.php:189
2373
  msgid "Extra Domains"
2374
  msgstr ""
2375
 
2376
+ #: templates/forms/affiliation.php:190
2377
  msgid "Extra domains where you will be marketing the product from."
2378
  msgstr ""
2379
 
2380
+ #: templates/forms/affiliation.php:200
2381
  msgid "Promotion methods"
2382
  msgstr ""
2383
 
2384
+ #: templates/forms/affiliation.php:203
2385
  msgid "Social media (Facebook, Twitter, etc.)"
2386
  msgstr ""
2387
 
2388
+ #: templates/forms/affiliation.php:207
2389
  msgid "Mobile apps"
2390
  msgstr ""
2391
 
2392
+ #: templates/forms/affiliation.php:211
2393
  msgid "Website, email, and social media statistics (optional)"
2394
  msgstr ""
2395
 
2396
+ #: templates/forms/affiliation.php:214
2397
  msgid "Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential)."
2398
  msgstr ""
2399
 
2400
+ #: templates/forms/affiliation.php:218
2401
  msgid "How will you promote us?"
2402
  msgstr ""
2403
 
2404
+ #: templates/forms/affiliation.php:221
2405
  msgid "Please provide details on how you intend to promote %s (please be as specific as possible)."
2406
  msgstr ""
2407
 
2408
+ #: templates/forms/affiliation.php:233, templates/forms/resend-key.php:22, templates/account/partials/disconnect-button.php:92
2409
  msgid "Cancel"
2410
  msgstr ""
2411
 
2412
+ #: templates/forms/affiliation.php:235
2413
  msgid "Become an affiliate"
2414
  msgstr ""
2415
 
2429
  msgid "User key"
2430
  msgstr ""
2431
 
2432
+ #: templates/forms/email-address-update.php:32
2433
+ msgid "Email address update"
2434
  msgstr ""
2435
 
2436
+ #: templates/forms/email-address-update.php:33, templates/forms/user-change.php:81
2437
+ msgctxt "close window"
2438
+ msgid "Dismiss"
2439
  msgstr ""
2440
 
2441
+ #: templates/forms/email-address-update.php:38
2442
+ msgid "Enter the new email address"
2443
  msgstr ""
2444
 
2445
+ #: templates/forms/email-address-update.php:42
2446
+ msgid "Are both %s and %s your email addresses?"
2447
  msgstr ""
2448
 
2449
+ #: templates/forms/email-address-update.php:50
2450
+ msgid "Yes - both addresses are mine"
 
2451
  msgstr ""
2452
 
2453
+ #: templates/forms/email-address-update.php:57
2454
+ msgid "%s is my client's email address"
 
2455
  msgstr ""
2456
 
2457
+ #: templates/forms/email-address-update.php:66
2458
+ msgid "%s is my email address"
2459
  msgstr ""
2460
 
2461
+ #: templates/forms/email-address-update.php:75
2462
+ msgid "Would you like to merge %s into %s?"
2463
  msgstr ""
2464
 
2465
+ #: templates/forms/email-address-update.php:84
2466
+ msgid "Yes - move all my data and assets from %s to %s"
2467
  msgstr ""
2468
 
2469
+ #: templates/forms/email-address-update.php:94
2470
+ msgid "No - only move this site's data to %s"
2471
+ msgstr ""
2472
+
2473
+ #: templates/forms/email-address-update.php:292, templates/forms/email-address-update.php:298
2474
+ msgid "Update"
2475
+ msgstr ""
2476
+
2477
+ #: templates/forms/license-activation.php:23
2478
+ msgid "Please enter the license key that you received in the email right after the purchase:"
2479
+ msgstr ""
2480
+
2481
+ #: templates/forms/license-activation.php:28
2482
+ msgid "Update License"
2483
+ msgstr ""
2484
+
2485
+ #: templates/forms/license-activation.php:34
2486
+ msgid "The %1$s will be periodically sending essential license data to %2$s to check for security and feature updates, and verify the validity of your license."
2487
+ msgstr ""
2488
+
2489
+ #: templates/forms/license-activation.php:39
2490
+ msgid "Agree & Activate License"
2491
+ msgstr ""
2492
+
2493
+ #: templates/forms/license-activation.php:204
2494
+ msgid "Associate with the license owner's account."
2495
  msgstr ""
2496
 
2497
  #: templates/forms/optout.php:44
2498
+ msgid "Communication"
2499
  msgstr ""
2500
 
2501
+ #: templates/forms/optout.php:56
2502
+ msgid "Stay Connected"
2503
  msgstr ""
2504
 
2505
+ #: templates/forms/optout.php:61
2506
+ msgid "Diagnostic Info"
2507
  msgstr ""
2508
 
2509
+ #: templates/forms/optout.php:77
2510
+ msgid "Keep Sharing"
2511
  msgstr ""
2512
 
2513
+ #: templates/forms/optout.php:82
2514
+ msgid "Extensions"
2515
+ msgstr ""
2516
+
2517
+ #: templates/forms/optout.php:104
2518
+ msgid "Keep automatic updates"
2519
  msgstr ""
2520
 
2521
  #: templates/forms/premium-versions-upgrade-handler.php:40
2539
  msgid "Send License Key"
2540
  msgstr ""
2541
 
2542
+ #: templates/forms/resend-key.php:58
2543
+ msgid "Enter the email address you've used during the purchase and we will resend you the license key."
2544
+ msgstr ""
2545
+
2546
+ #: templates/forms/resend-key.php:59
2547
  msgid "Enter the email address you've used for the upgrade below and we will resend you the license key."
2548
  msgstr ""
2549
 
2555
  msgid "In case you are NOT planning on using this %s on this site (or any other site) - would you like to cancel the %s as well?"
2556
  msgstr ""
2557
 
 
 
 
 
2558
  #: templates/forms/subscription-cancellation.php:57
2559
  msgid "Cancel %s - I no longer need any security & feature updates, nor support for %s because I'm not planning to use the %s on this, or any other site."
2560
  msgstr ""
2575
  msgid "Proceed"
2576
  msgstr ""
2577
 
2578
+ #: templates/forms/subscription-cancellation.php:191, templates/forms/deactivation/form.php:216
2579
  msgid "Cancel %s & Proceed"
2580
  msgstr ""
2581
 
2599
  msgid "Enter email address"
2600
  msgstr ""
2601
 
2602
+ #: templates/js/permissions.php:337, templates/js/permissions.php:485
2603
+ msgid "Saved"
 
2604
  msgstr ""
2605
 
2606
  #: templates/js/style-premium-theme.php:39
2611
  msgid "Beta"
2612
  msgstr ""
2613
 
2614
+ #: templates/partials/network-activation.php:32
2615
  msgid "Activate license on all sites in the network."
2616
  msgstr ""
2617
 
2618
+ #: templates/partials/network-activation.php:33
2619
  msgid "Apply on all sites in the network."
2620
  msgstr ""
2621
 
2622
+ #: templates/partials/network-activation.php:36
2623
  msgid "Activate license on all pending sites."
2624
  msgstr ""
2625
 
2626
+ #: templates/partials/network-activation.php:37
2627
  msgid "Apply on all pending sites."
2628
  msgstr ""
2629
 
2630
+ #: templates/partials/network-activation.php:45, templates/partials/network-activation.php:79
2631
  msgid "allow"
2632
  msgstr ""
2633
 
2634
+ #: templates/partials/network-activation.php:48, templates/partials/network-activation.php:82
2635
  msgid "delegate"
2636
  msgstr ""
2637
 
2638
+ #: templates/partials/network-activation.php:52, templates/partials/network-activation.php:86
2639
  msgid "skip"
2640
  msgstr ""
2641
 
2661
  msgstr ""
2662
 
2663
  #. translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription'
2664
+ #: templates/account/partials/addon.php:34
2665
  msgid "%1$s will immediately stop all future recurring payments and your %s plan license will expire in %s."
2666
  msgstr ""
2667
 
2668
+ #: templates/account/partials/addon.php:190
2669
  msgid "Cancelled"
2670
  msgstr ""
2671
 
2672
+ #: templates/account/partials/addon.php:200
2673
  msgid "No expiration"
2674
  msgstr ""
2675
 
2676
+ #: templates/account/partials/disconnect-button.php:74
2677
+ msgid "By disconnecting the website, previously shared diagnostic data about %1$s will be deleted and no longer visible to %2$s."
2678
+ msgstr ""
2679
+
2680
+ #: templates/account/partials/disconnect-button.php:78
2681
+ msgid "Disconnecting the website will permanently remove %s from your User Dashboard's account."
2682
+ msgstr ""
2683
+
2684
+ #: templates/account/partials/disconnect-button.php:84
2685
+ msgid "If you wish to cancel your %1$s plan's subscription instead, please navigate to the %2$s and cancel it there."
2686
+ msgstr ""
2687
+
2688
+ #: templates/account/partials/disconnect-button.php:88
2689
+ msgid "Are you sure you would like to proceed with the disconnection?"
2690
+ msgstr ""
2691
+
2692
+ #: templates/account/partials/site.php:190
2693
  msgid "Owner Name"
2694
  msgstr ""
2695
 
2696
+ #: templates/account/partials/site.php:202
2697
  msgid "Owner Email"
2698
  msgstr ""
2699
 
2700
+ #: templates/account/partials/site.php:214
2701
  msgid "Owner ID"
2702
  msgstr ""
2703
 
2704
+ #: templates/account/partials/site.php:288
2705
  msgid "Subscription"
2706
  msgstr ""
2707
 
2713
  msgid "Contact Support"
2714
  msgstr ""
2715
 
2716
+ #: templates/forms/deactivation/form.php:65
2717
  msgid "Anonymous feedback"
2718
  msgstr ""
2719
 
2720
+ #: templates/forms/deactivation/form.php:71
2721
+ msgid "hour"
2722
+ msgstr ""
2723
+
2724
+ #: templates/forms/deactivation/form.php:76
2725
+ msgid "hours"
2726
+ msgstr ""
2727
+
2728
+ #: templates/forms/deactivation/form.php:81, templates/forms/deactivation/form.php:86
2729
+ msgid "days"
2730
+ msgstr ""
2731
+
2732
+ #: templates/forms/deactivation/form.php:106
2733
  msgid "Deactivate"
2734
  msgstr ""
2735
 
2736
+ #: templates/forms/deactivation/form.php:108
2737
  msgid "Activate %s"
2738
  msgstr ""
2739
 
2740
+ #: templates/forms/deactivation/form.php:111
2741
+ msgid "Submit & %s"
2742
+ msgstr ""
2743
+
2744
+ #: templates/forms/deactivation/form.php:130
2745
  msgid "Quick Feedback"
2746
  msgstr ""
2747
 
2748
+ #: templates/forms/deactivation/form.php:134
2749
  msgid "If you have a moment, please let us know why you are %s"
2750
  msgstr ""
2751
 
2752
+ #: templates/forms/deactivation/form.php:134
2753
  msgid "deactivating"
2754
  msgstr ""
2755
 
2756
+ #: templates/forms/deactivation/form.php:134
2757
  msgid "switching"
2758
  msgstr ""
2759
 
2760
+ #: templates/forms/deactivation/form.php:448
2761
+ msgid "Kindly tell us the reason so we can improve."
2762
  msgstr ""
2763
 
2764
+ #: templates/forms/deactivation/form.php:478
2765
+ msgid "Snooze & %s"
2766
  msgstr ""
2767
 
2768
+ #: templates/forms/deactivation/form.php:638
2769
  msgid "Yes - %s"
2770
  msgstr ""
2771
 
2772
+ #: templates/forms/deactivation/form.php:645
2773
  msgid "Skip & %s"
2774
  msgstr ""
2775
 
freemius/require.php CHANGED
@@ -21,6 +21,8 @@
21
  // require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';
22
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';
23
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-gdpr-manager.php';
 
 
24
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php';
25
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';
26
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';
21
  // require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';
22
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';
23
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-gdpr-manager.php';
24
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-clone-manager.php';
25
+ require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-permission-manager.php';
26
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php';
27
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';
28
  require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';
freemius/start.php CHANGED
@@ -15,7 +15,7 @@
15
  *
16
  * @var string
17
  */
18
- $this_sdk_version = '2.4.3';
19
 
20
  #region SDK Selection Logic --------------------------------------------------------------------
21
 
@@ -68,7 +68,11 @@
68
 
69
  if ( ! isset( $fs_active_plugins ) ) {
70
  // Load all Freemius powered active plugins.
71
- $fs_active_plugins = get_option( 'fs_active_plugins', new stdClass() );
 
 
 
 
72
 
73
  if ( ! isset( $fs_active_plugins->plugins ) ) {
74
  $fs_active_plugins->plugins = array();
15
  *
16
  * @var string
17
  */
18
+ $this_sdk_version = '2.5.2';
19
 
20
  #region SDK Selection Logic --------------------------------------------------------------------
21
 
68
 
69
  if ( ! isset( $fs_active_plugins ) ) {
70
  // Load all Freemius powered active plugins.
71
+ $fs_active_plugins = get_option( 'fs_active_plugins' );
72
+
73
+ if ( ! is_object( $fs_active_plugins ) ) {
74
+ $fs_active_plugins = new stdClass();
75
+ }
76
 
77
  if ( ! isset( $fs_active_plugins->plugins ) ) {
78
  $fs_active_plugins->plugins = array();
freemius/templates/account.php CHANGED
@@ -46,6 +46,7 @@
46
  $site = $fs->get_site();
47
  $name = $user->get_name();
48
  $license = $fs->_get_license();
 
49
  $is_data_debug_mode = $fs->is_data_debug_mode();
50
  $is_whitelabeled = $fs->is_whitelabeled();
51
  $subscription = ( is_object( $license ) ?
@@ -58,10 +59,19 @@
58
  $show_upgrade = ( ! $is_whitelabeled && $has_paid_plan && ! $is_paying && ! $is_paid_trial );
59
  $trial_plan = $fs->get_trial_plan();
60
 
 
 
 
 
 
61
  if ( $has_paid_plan ) {
62
  $fs->_add_license_activation_dialog_box();
63
  }
64
 
 
 
 
 
65
  $ids_of_installs_activated_with_foreign_licenses = $fs->should_handle_user_change() ?
66
  $fs->get_installs_ids_with_foreign_licenses() :
67
  array();
@@ -86,12 +96,15 @@
86
  ) );
87
  }
88
 
89
- $payments = $fs->_fetch_payments();
 
 
90
 
91
- $show_billing = ( ! $is_whitelabeled && is_array( $payments ) && 0 < count( $payments ) );
 
92
 
93
 
94
- $has_tabs = $fs->_add_tabs_before_content();
95
 
96
  if ( $has_tabs ) {
97
  $query_params['tabs'] = 'true';
@@ -140,6 +153,7 @@
140
  $install = $fs->get_install_by_blog_id( $site_info['blog_id'] );
141
  $view_params = array(
142
  'freemius' => $fs,
 
143
  'license' => $license,
144
  'site' => $site_info,
145
  'install' => $install,
@@ -234,6 +248,14 @@
234
  $addons_to_show = array_unique( array_merge( $installed_addons_ids, $account_addons ) );
235
 
236
  $is_active_bundle_subscription = ( is_object( $bundle_subscription ) && $bundle_subscription->is_active() );
 
 
 
 
 
 
 
 
237
  ?>
238
  <div class="wrap fs-section">
239
  <?php if ( ! $has_tabs && ! $fs->apply_filters( 'hide_account_tabs', false ) ) : ?>
@@ -274,24 +296,19 @@
274
  <li>&nbsp;&bull;&nbsp;</li>
275
  <?php endif ?>
276
  <?php if ( $show_billing ) : ?>
277
- <li><a href="#fs_billing"><i class="dashicons dashicons-portfolio"></i> <?php fs_esc_html_echo_inline( 'Billing & Invoices', 'billing-invoices', $slug ) ?></li>
278
  <li>&nbsp;&bull;&nbsp;</li>
279
  <?php endif ?>
280
  <?php if ( ! $is_whitelabeled ) : ?>
281
  <?php if ( ! $is_paying ) : ?>
282
  <li>
283
- <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
284
- <input type="hidden" name="fs_action" value="delete_account">
285
- <?php wp_nonce_field( 'delete_account' ) ?>
286
- <a class="fs-delete-account" href="#" onclick="if (confirm('<?php
287
- if ( $is_active_subscription ) {
288
- echo esc_attr( sprintf( fs_text_inline( '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?', 'delete-account-x-confirm', $slug ), $plan->title ) );
289
- } else {
290
- echo esc_attr( sprintf( fs_text_inline( 'Deletion is not temporary. Only delete if you no longer want to use this %s anymore. Are you sure you would like to continue with the deletion?', 'delete-account-confirm', $slug ), $fs->get_module_label( true ) ) );
291
- }
292
- ?>')) this.parentNode.submit(); return false;"><i
293
- class="dashicons dashicons-no"></i> <?php fs_esc_html_echo_inline( 'Delete Account', 'delete-account', $slug ) ?></a>
294
- </form>
295
  </li>
296
  <li>&nbsp;&bull;&nbsp;</li>
297
  <?php endif ?>
@@ -330,7 +347,7 @@
330
  </li>
331
  <li>&nbsp;&bull;&nbsp;</li>
332
  <?php endif ?>
333
- <?php if ( ! $fs->is_single_plan() ) : ?>
334
  <li>
335
  <a href="<?php echo $fs->get_upgrade_url() ?>"><i
336
  class="dashicons dashicons-grid-view"></i> <?php echo esc_html( $change_plan_text ) ?></a>
@@ -366,7 +383,7 @@
366
 
367
  $profile = array();
368
 
369
- if ( ! $is_whitelabeled ) {
370
  $profile[] = array(
371
  'id' => 'user_name',
372
  'title' => fs_text_inline( 'Name', 'name', $slug ),
@@ -435,7 +452,7 @@
435
  'value' => $fs->get_plugin_version()
436
  );
437
 
438
- if ( ! fs_is_network_admin() && $is_premium && ! $is_whitelabeled ) {
439
  $profile[] = array(
440
  'id' => 'beta_program',
441
  'title' => '',
@@ -537,15 +554,13 @@
537
  <?php endif ?>
538
  <?php if ( ! $is_whitelabeled ) : ?>
539
  <div class="button-group">
540
- <?php $available_license = $fs->is_free_plan() && ! fs_is_network_admin() ? $fs->_get_available_premium_license( $site->is_localhost() ) : false ?>
541
  <?php if ( is_object( $available_license ) ) : ?>
542
- <?php $premium_plan = $fs->_get_plan_by_id( $available_license->plan_id ) ?>
543
  <?php
544
  $view_params = array(
545
  'freemius' => $fs,
546
  'slug' => $slug,
547
  'license' => $available_license,
548
- 'plan' => $premium_plan,
549
  'is_localhost' => $site->is_localhost(),
550
  'install_id' => $site->id,
551
  'class' => 'button-primary',
@@ -562,7 +577,7 @@
562
  <input type="hidden" name="fs_action"
563
  value="<?php echo $fs->get_unique_affix() ?>_sync_license">
564
  <?php wp_nonce_field( $fs->get_unique_affix() . '_sync_license' ) ?>
565
- <?php if ( $show_upgrade || ! $fs->is_single_plan() ) : ?>
566
  <a href="<?php echo $fs->get_upgrade_url() ?>"
567
  class="button<?php
568
  echo $show_upgrade ?
@@ -645,7 +660,7 @@
645
  <?php endif ?>
646
  <?php
647
  elseif ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
648
- <?php if ( ! $is_whitelabeled ) : ?>
649
  <button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button>
650
  <?php endif ?>
651
  <?php if ('license_key' === $p['id']) : ?>
@@ -658,6 +673,7 @@
658
  'user_name'
659
  ) ) )
660
  ) : ?>
 
661
  <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"
662
  onsubmit="var val = prompt('<?php echo esc_attr( sprintf(
663
  /* translators: %s: User's account property (e.g. name, email) */
@@ -668,9 +684,10 @@
668
  <input type="hidden" name="fs_<?php echo $p['id'] ?>_<?php echo $fs->get_unique_affix() ?>"
669
  value="">
670
  <?php wp_nonce_field( 'update_' . $p['id'] ) ?>
671
- <input type="submit" class="button button-small"
672
  value="<?php echo fs_esc_attr_x_inline( 'Edit', 'verb', 'edit', $slug ) ?>">
673
  </form>
 
674
  <?php elseif ( 'user_id' === $p['id'] && ! empty( $ids_of_installs_activated_with_foreign_licenses ) ) : ?>
675
  <input id="fs_change_user" type="submit" class="button button-small"
676
  value="<?php echo fs_esc_attr_inline( 'Change User', 'change-user', $slug ) ?>">
@@ -730,12 +747,30 @@
730
  <div class="fs-table-body">
731
  <table class="widefat">
732
  <?php
 
 
733
  foreach ( $site_view_params as $view_params ) {
734
  fs_require_template(
735
  'account/partials/site.php',
736
  $view_params
737
  );
738
- } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
  </table>
740
  </div>
741
  </div>
@@ -839,7 +874,7 @@
839
 
840
  <?php
841
  if ( $show_billing ) {
842
- $view_params = array( 'id' => $VARS['id'] );
843
  fs_require_once_template( 'account/billing.php', $view_params );
844
  fs_require_once_template( 'account/payments.php', $view_params );
845
  }
@@ -919,7 +954,7 @@
919
 
920
  if ( ! isChecked || confirm( '<?php echo $confirmation_message ?>' ) ) {
921
  $.ajax( {
922
- url : ajaxurl,
923
  method: 'POST',
924
  data : {
925
  action : '<?php echo $fs->get_ajax_action( 'set_beta_mode' ) ?>',
@@ -1062,7 +1097,7 @@
1062
  var $toggleLink = $( this );
1063
 
1064
  $.ajax( {
1065
- url : ajaxurl,
1066
  method: 'POST',
1067
  data : {
1068
  action : '<?php echo $fs->get_ajax_action( 'toggle_whitelabel_mode' ) ?>',
@@ -1095,4 +1130,4 @@
1095
  'module_slug' => $slug,
1096
  'module_version' => $fs->get_plugin_version(),
1097
  );
1098
- fs_require_template( 'powered-by.php', $params );
46
  $site = $fs->get_site();
47
  $name = $user->get_name();
48
  $license = $fs->_get_license();
49
+ $is_license_foreign = ( is_object( $license ) && $user->id != $license->user_id );
50
  $is_data_debug_mode = $fs->is_data_debug_mode();
51
  $is_whitelabeled = $fs->is_whitelabeled();
52
  $subscription = ( is_object( $license ) ?
59
  $show_upgrade = ( ! $is_whitelabeled && $has_paid_plan && ! $is_paying && ! $is_paid_trial );
60
  $trial_plan = $fs->get_trial_plan();
61
 
62
+ $is_plan_change_supported = (
63
+ ! $fs->is_single_plan() &&
64
+ ! $fs->apply_filters( 'hide_plan_change', false )
65
+ );
66
+
67
  if ( $has_paid_plan ) {
68
  $fs->_add_license_activation_dialog_box();
69
  }
70
 
71
+ if ( $fs->should_handle_user_change() ) {
72
+ $fs->_add_email_address_update_dialog_box();
73
+ }
74
+
75
  $ids_of_installs_activated_with_foreign_licenses = $fs->should_handle_user_change() ?
76
  $fs->get_installs_ids_with_foreign_licenses() :
77
  array();
96
  ) );
97
  }
98
 
99
+ $show_billing = ( ! $is_whitelabeled && ! $fs->apply_filters( 'hide_billing_and_payments_info', false ) );
100
+ if ( $show_billing ) {
101
+ $payments = $fs->_fetch_payments();
102
 
103
+ $show_billing = ( is_array( $payments ) && 0 < count( $payments ) );
104
+ }
105
 
106
 
107
+ $has_tabs = $fs->_add_tabs_before_content();
108
 
109
  if ( $has_tabs ) {
110
  $query_params['tabs'] = 'true';
153
  $install = $fs->get_install_by_blog_id( $site_info['blog_id'] );
154
  $view_params = array(
155
  'freemius' => $fs,
156
+ 'user' => $fs->get_user(),
157
  'license' => $license,
158
  'site' => $site_info,
159
  'install' => $install,
248
  $addons_to_show = array_unique( array_merge( $installed_addons_ids, $account_addons ) );
249
 
250
  $is_active_bundle_subscription = ( is_object( $bundle_subscription ) && $bundle_subscription->is_active() );
251
+
252
+ $available_license = ( $fs->is_free_plan() && ! fs_is_network_admin() ) ?
253
+ $fs->_get_available_premium_license( $site->is_localhost() ) :
254
+ null;
255
+
256
+ $available_license_paid_plan = is_object( $available_license ) ?
257
+ $fs->_get_plan_by_id( $available_license->plan_id ) :
258
+ null;
259
  ?>
260
  <div class="wrap fs-section">
261
  <?php if ( ! $has_tabs && ! $fs->apply_filters( 'hide_account_tabs', false ) ) : ?>
296
  <li>&nbsp;&bull;&nbsp;</li>
297
  <?php endif ?>
298
  <?php if ( $show_billing ) : ?>
299
+ <li><a href="#fs_billing"><i class="dashicons dashicons-portfolio"></i> <?php fs_esc_html_echo_inline( 'Billing & Invoices', 'billing-invoices', $slug ) ?></a></li>
300
  <li>&nbsp;&bull;&nbsp;</li>
301
  <?php endif ?>
302
  <?php if ( ! $is_whitelabeled ) : ?>
303
  <?php if ( ! $is_paying ) : ?>
304
  <li>
305
+ <?php
306
+ $view_params = array(
307
+ 'freemius' => $fs,
308
+ 'license' => $available_license,
309
+ 'license_paid_plan' => $available_license_paid_plan,
310
+ );
311
+ fs_require_template( 'account/partials/disconnect-button.php', $view_params ); ?>
 
 
 
 
 
312
  </li>
313
  <li>&nbsp;&bull;&nbsp;</li>
314
  <?php endif ?>
347
  </li>
348
  <li>&nbsp;&bull;&nbsp;</li>
349
  <?php endif ?>
350
+ <?php if ( $is_plan_change_supported ) : ?>
351
  <li>
352
  <a href="<?php echo $fs->get_upgrade_url() ?>"><i
353
  class="dashicons dashicons-grid-view"></i> <?php echo esc_html( $change_plan_text ) ?></a>
383
 
384
  $profile = array();
385
 
386
+ if ( ! $is_whitelabeled ) {
387
  $profile[] = array(
388
  'id' => 'user_name',
389
  'title' => fs_text_inline( 'Name', 'name', $slug ),
452
  'value' => $fs->get_plugin_version()
453
  );
454
 
455
+ if ( ! fs_is_network_admin() && $is_premium ) {
456
  $profile[] = array(
457
  'id' => 'beta_program',
458
  'title' => '',
554
  <?php endif ?>
555
  <?php if ( ! $is_whitelabeled ) : ?>
556
  <div class="button-group">
 
557
  <?php if ( is_object( $available_license ) ) : ?>
 
558
  <?php
559
  $view_params = array(
560
  'freemius' => $fs,
561
  'slug' => $slug,
562
  'license' => $available_license,
563
+ 'plan' => $available_license_paid_plan,
564
  'is_localhost' => $site->is_localhost(),
565
  'install_id' => $site->id,
566
  'class' => 'button-primary',
577
  <input type="hidden" name="fs_action"
578
  value="<?php echo $fs->get_unique_affix() ?>_sync_license">
579
  <?php wp_nonce_field( $fs->get_unique_affix() . '_sync_license' ) ?>
580
+ <?php if ( $show_upgrade || $is_plan_change_supported ) : ?>
581
  <a href="<?php echo $fs->get_upgrade_url() ?>"
582
  class="button<?php
583
  echo $show_upgrade ?
660
  <?php endif ?>
661
  <?php
662
  elseif ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
663
+ <?php if ( ! $is_whitelabeled && ( 'site_secret_key' === $p['id'] || ! $is_license_foreign ) ) : ?>
664
  <button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button>
665
  <?php endif ?>
666
  <?php if ('license_key' === $p['id']) : ?>
673
  'user_name'
674
  ) ) )
675
  ) : ?>
676
+ <?php if ( 'email' !== $p['id'] || ! fs_is_network_admin() ) : ?>
677
  <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"
678
  onsubmit="var val = prompt('<?php echo esc_attr( sprintf(
679
  /* translators: %s: User's account property (e.g. name, email) */
684
  <input type="hidden" name="fs_<?php echo $p['id'] ?>_<?php echo $fs->get_unique_affix() ?>"
685
  value="">
686
  <?php wp_nonce_field( 'update_' . $p['id'] ) ?>
687
+ <input type="submit" class="button button-small <?php if ( 'email' === $p['id'] ) echo 'button-edit-email-address' ?>"
688
  value="<?php echo fs_esc_attr_x_inline( 'Edit', 'verb', 'edit', $slug ) ?>">
689
  </form>
690
+ <?php endif ?>
691
  <?php elseif ( 'user_id' === $p['id'] && ! empty( $ids_of_installs_activated_with_foreign_licenses ) ) : ?>
692
  <input id="fs_change_user" type="submit" class="button button-small"
693
  value="<?php echo fs_esc_attr_inline( 'Change User', 'change-user', $slug ) ?>">
747
  <div class="fs-table-body">
748
  <table class="widefat">
749
  <?php
750
+ $current_blog_id = get_current_blog_id();
751
+
752
  foreach ( $site_view_params as $view_params ) {
753
  fs_require_template(
754
  'account/partials/site.php',
755
  $view_params
756
  );
757
+ }
758
+
759
+ /**
760
+ * It's possible for the `Freemius::switch_to_blog()` method to be called within the `site.php` template and this changes the Freemius instance's context, so this check is for restoring the previous context based on the previously retrieved site.
761
+ *
762
+ * @author Leo Fajardo (@leorw)
763
+ * @since 2.5.0
764
+ */
765
+ $current_install = $fs->get_site();
766
+
767
+ if (
768
+ is_object( $site ) &&
769
+ ( ! is_object( $current_install ) || $current_install->id != $site->id )
770
+ ) {
771
+ $fs->switch_to_blog( $current_blog_id, $site, true );
772
+ }
773
+ ?>
774
  </table>
775
  </div>
776
  </div>
874
 
875
  <?php
876
  if ( $show_billing ) {
877
+ $view_params = array( 'id' => $VARS['id'], 'payments' => $payments );
878
  fs_require_once_template( 'account/billing.php', $view_params );
879
  fs_require_once_template( 'account/payments.php', $view_params );
880
  }
954
 
955
  if ( ! isChecked || confirm( '<?php echo $confirmation_message ?>' ) ) {
956
  $.ajax( {
957
+ url : <?php echo Freemius::ajax_url() ?>,
958
  method: 'POST',
959
  data : {
960
  action : '<?php echo $fs->get_ajax_action( 'set_beta_mode' ) ?>',
1097
  var $toggleLink = $( this );
1098
 
1099
  $.ajax( {
1100
+ url : <?php echo Freemius::ajax_url() ?>,
1101
  method: 'POST',
1102
  data : {
1103
  action : '<?php echo $fs->get_ajax_action( 'toggle_whitelabel_mode' ) ?>',
1130
  'module_slug' => $slug,
1131
  'module_version' => $fs->get_plugin_version(),
1132
  );
1133
+ fs_require_template( 'powered-by.php', $params );
freemius/templates/account/billing.php CHANGED
@@ -377,7 +377,7 @@
377
  });
378
 
379
  $.ajax({
380
- url : ajaxurl,
381
  method : 'POST',
382
  data : {
383
  action : '<?php echo $fs->get_ajax_action( 'update_billing' ) ?>',
377
  });
378
 
379
  $.ajax({
380
+ url : <?php echo Freemius::ajax_url() ?>,
381
  method : 'POST',
382
  data : {
383
  action : '<?php echo $fs->get_ajax_action( 'update_billing' ) ?>',
freemius/templates/account/partials/disconnect-button.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2016, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ * @var Freemius $fs
16
+ */
17
+ $fs = $VARS['freemius'];
18
+
19
+ /**
20
+ * @var FS_Plugin_License $license
21
+ */
22
+ $license = $VARS['license'];
23
+ /**
24
+ * @var FS_Plugin_Plan $license_paid_plan
25
+ */
26
+ $license_paid_plan = $VARS['license_paid_plan'];
27
+
28
+ $license_subscription = ( is_object( $license ) && is_object( $license_paid_plan ) ) ?
29
+ $fs->_get_subscription( $license->id ) :
30
+ null;
31
+
32
+ $has_active_subscription = (
33
+ is_object( $license_subscription ) &&
34
+ $license_subscription->is_active()
35
+ );
36
+
37
+ $button_id = "fs_disconnect_button_{$fs->get_id()}";
38
+
39
+ $website_link = sprintf( '<a href="#" tabindex="-1">%s</a>', fs_strip_url_protocol( untrailingslashit( Freemius::get_unfiltered_site_url() ) ) );
40
+ ?>
41
+ <script type="text/javascript">
42
+ // Wrap in a IFFE to prevent leaking global variables.
43
+ ( function( $ ) {
44
+ $( document ).ready( function() {
45
+ var $modal = $( '#fs_modal_delete_site' );
46
+
47
+ $( '#<?php echo $button_id ?>' ).on( 'click', function( e ) {
48
+ // Prevent the form being submitted.
49
+ e.preventDefault();
50
+
51
+ $( document.body ).append( $modal );
52
+ $modal.show();
53
+ } );
54
+
55
+ $modal.on( 'click', '.button-close', function ( evt ) {
56
+ $modal.hide();
57
+ } );
58
+
59
+ $modal.on( 'click', '.button-primary', function ( evt ) {
60
+ $( '#<?php echo $button_id ?>' ).closest( 'form' )[0].submit();
61
+ } );
62
+ } );
63
+ } )( jQuery );
64
+ </script>
65
+ <div id="fs_modal_delete_site" class="fs-modal active" style="display: none">
66
+ <div class="fs-modal-dialog">
67
+ <div class="fs-modal-header">
68
+ <h4><?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></h4>
69
+ </div>
70
+ <div class="fs-modal-body">
71
+ <?php if ( ! is_object( $license ) ) : ?>
72
+ <p><?php echo
73
+ // translators: %1$s is replaced with the website's homepage address, %2$s is replaced with the plugin name.
74
+ sprintf( esc_html( $fs->get_text_inline( 'By disconnecting the website, previously shared diagnostic data about %1$s will be deleted and no longer visible to %2$s.', 'disconnect-intro-paid' ) ), $website_link, '<b>' . $fs->get_plugin_title() . '</b>' ) ?></p>
75
+ <?php else : ?>
76
+ <p><?php echo
77
+ // translators: %s is replaced with the website's homepage address.
78
+ sprintf( esc_html( $fs->get_text_inline( 'Disconnecting the website will permanently remove %s from your User Dashboard\'s account.', 'disconnect-intro-paid' ) ), $website_link ) ?></p>
79
+ <?php endif ?>
80
+
81
+ <?php if ( $has_active_subscription ) : ?>
82
+ <p><?php echo
83
+ // translators: %1$s is replaced by the paid plan name, %2$s is replaced with an anchor link with the text "User Dashboard".
84
+ sprintf( esc_html( $fs->get_text_inline( 'If you wish to cancel your %1$s plan\'s subscription instead, please navigate to the %2$s and cancel it there.', 'disconnect-subscription-disclaimer' ) ), $license_paid_plan->title, sprintf( '<a href="https://users.freemius.com" target="_blank" rel="noreferrer noopener nofollow">%s</a>', $fs->get_text_inline( 'User Dashboard', 'user-dashboard' ) )
85
+ ) ?></p>
86
+ <?php endif ?>
87
+
88
+ <p><?php echo esc_html( $fs->get_text_inline( 'Are you sure you would like to proceed with the disconnection?', 'disconnect-confirm' ) ) ?></p>
89
+ </div>
90
+ <div class="fs-modal-footer">
91
+ <button class="button button-primary<?php if ( is_object( $license ) ) : ?> warn<?php endif ?>" tabindex="2"><?php echo $fs->esc_html_inline( 'Yes', 'yes' ) . ' - ' . $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></button>
92
+ <button class="button button-secondary button-close" tabindex="1"><?php echo esc_html( $fs->get_text_inline( 'Cancel', 'cancel' ) ) ?></button>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ <form action="<?php echo esc_attr( $fs->_get_admin_page_url( 'account' ) ); ?>" method="POST">
97
+ <input type="hidden" name="fs_action" value="delete_account">
98
+ <?php wp_nonce_field( 'delete_account' ) ?>
99
+
100
+ <a id="<?php echo $button_id ?>" href="#" class="fs-button-inline">
101
+ <i class="dashicons dashicons-no"></i>
102
+ <?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?>
103
+ </a>
104
+ </form>
freemius/templates/account/partials/site.php CHANGED
@@ -23,7 +23,7 @@
23
  $is_whitelabeled = $fs->is_whitelabeled();
24
  $has_paid_plan = $fs->has_paid_plan();
25
  $is_premium = $fs->is_premium();
26
- $main_user = $fs->get_user();
27
  $blog_id = $site['blog_id'];
28
 
29
  $install = $VARS['install'];
@@ -32,7 +32,7 @@
32
  $trial_plan = $fs->get_trial_plan();
33
  $free_text = fs_text_inline( 'Free', 'free', $slug );
34
 
35
- if ( $is_whitelabeled && $fs->is_delegated_connection( $blog_id ) ) {
36
  $is_whitelabeled = $fs->is_whitelabeled( true, $blog_id );
37
  }
38
  ?>
@@ -159,14 +159,15 @@
159
  <td><?php if ( ! FS_Plugin_License::is_valid_id( $install->license_id ) ) : ?>
160
  <!-- Toggle Usage Tracking -->
161
  <?php $action = 'toggle_tracking' ?>
 
162
  <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
163
  <input type="hidden" name="fs_action" value="<?php echo $action ?>">
164
  <?php wp_nonce_field( trim( "{$action}:{$blog_id}:{$install->id}", ':' ) ) ?>
165
  <input type="hidden" name="install_id" value="<?php echo $install->id ?>">
166
  <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
167
- <button class="fs-toggle-tracking button button-small<?php if ( $install->is_disconnected ) {
168
  echo ' button-primary';
169
- } ?>" data-is-disconnected="<?php echo $install->is_disconnected ? 'true' : 'false' ?>"><?php $install->is_disconnected ? fs_esc_html_echo_inline( 'Opt In', 'opt-in', $slug ) : fs_esc_html_echo_inline( 'Opt Out', 'opt-out', $slug ) ?></button>
170
  </form>
171
  <!--/ Toggle Usage Tracking -->
172
  <?php endif ?></td>
@@ -174,7 +175,7 @@
174
  <?php $row_index ++ ?>
175
  <!--/ Blog ID -->
176
 
177
- <?php if ( $is_registered && $install->user_id != $main_user->id ) : ?>
178
  <?php
179
  /**
180
  * @var FS_User $user
@@ -226,7 +227,8 @@
226
  <td>
227
  <nobr><?php fs_esc_html_echo_inline( 'Public Key', 'public-key', $slug ) ?>:</nobr>
228
  </td>
229
- <td colspan="2"><code><?php echo htmlspecialchars( $install->public_key ) ?></code></td>
 
230
  </tr>
231
  <?php $row_index ++ ?>
232
  <!--/ Public Key -->
23
  $is_whitelabeled = $fs->is_whitelabeled();
24
  $has_paid_plan = $fs->has_paid_plan();
25
  $is_premium = $fs->is_premium();
26
+ $main_user = $VARS['user'];
27
  $blog_id = $site['blog_id'];
28
 
29
  $install = $VARS['install'];
32
  $trial_plan = $fs->get_trial_plan();
33
  $free_text = fs_text_inline( 'Free', 'free', $slug );
34
 
35
+ if ( $is_whitelabeled && is_object( $install ) && $fs->is_delegated_connection( $blog_id ) ) {
36
  $is_whitelabeled = $fs->is_whitelabeled( true, $blog_id );
37
  }
38
  ?>
159
  <td><?php if ( ! FS_Plugin_License::is_valid_id( $install->license_id ) ) : ?>
160
  <!-- Toggle Usage Tracking -->
161
  <?php $action = 'toggle_tracking' ?>
162
+ <?php $is_disconnected = ! FS_Permission_Manager::instance( $fs )->is_homepage_url_tracking_allowed( $blog_id ) ?>
163
  <form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
164
  <input type="hidden" name="fs_action" value="<?php echo $action ?>">
165
  <?php wp_nonce_field( trim( "{$action}:{$blog_id}:{$install->id}", ':' ) ) ?>
166
  <input type="hidden" name="install_id" value="<?php echo $install->id ?>">
167
  <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
168
+ <button class="fs-toggle-tracking button button-small<?php if ( $is_disconnected ) {
169
  echo ' button-primary';
170
+ } ?>" data-is-disconnected="<?php echo $is_disconnected ? 'true' : 'false' ?>"><?php $is_disconnected ? fs_esc_html_echo_inline( 'Opt In', 'opt-in', $slug ) : fs_esc_html_echo_inline( 'Opt Out', 'opt-out', $slug ) ?></button>
171
  </form>
172
  <!--/ Toggle Usage Tracking -->
173
  <?php endif ?></td>
175
  <?php $row_index ++ ?>
176
  <!--/ Blog ID -->
177
 
178
+ <?php if ( $install->user_id != $main_user->id ) : ?>
179
  <?php
180
  /**
181
  * @var FS_User $user
227
  <td>
228
  <nobr><?php fs_esc_html_echo_inline( 'Public Key', 'public-key', $slug ) ?>:</nobr>
229
  </td>
230
+ <td><code><?php echo htmlspecialchars( $install->public_key ) ?></code></td>
231
+ <td></td>
232
  </tr>
233
  <?php $row_index ++ ?>
234
  <!--/ Public Key -->
freemius/templates/account/payments.php CHANGED
@@ -10,19 +10,19 @@
10
  exit;
11
  }
12
 
13
- /**
14
- * @var array $VARS
15
- * @var Freemius $fs
16
- */
17
- $fs = freemius( $VARS['id'] );
18
 
19
- $slug = $fs->get_slug();
 
 
 
20
 
21
- $payments = $fs->_fetch_payments();
22
-
23
- $show_payments = ( is_array( $payments ) && 0 < count( $payments ) );
24
 
25
- if ( $show_payments ) :
26
  ?>
27
  <div class="postbox">
28
  <div id="fs_payments">
@@ -56,4 +56,3 @@
56
  </div>
57
  </div>
58
  <?php
59
- endif;
10
  exit;
11
  }
12
 
13
+ /**
14
+ * @var array $VARS
15
+ * @var Freemius $fs
16
+ */
17
+ $fs = freemius( $VARS['id'] );
18
 
19
+ /**
20
+ * @var FS_Payment[] $payments
21
+ */
22
+ $payments = $VARS['payments'];
23
 
24
+ $slug = $fs->get_slug();
 
 
25
 
 
26
  ?>
27
  <div class="postbox">
28
  <div id="fs_payments">
56
  </div>
57
  </div>
58
  <?php
 
freemius/templates/admin-notice.php CHANGED
@@ -45,6 +45,9 @@
45
  case 'promotion':
46
  echo 'updated promotion';
47
  break;
 
 
 
48
  case 'update':
49
  // echo 'update-nag update';
50
  // break;
@@ -64,7 +67,7 @@
64
  } ?>"><?php if ( ! empty( $VARS['plugin'] ) ) : ?>
65
  <label class="fs-plugin-title"><?php echo $VARS['plugin'] ?></label>
66
  <?php endif ?>
67
- <?php if ( ! empty( $VARS['sticky'] ) ) : ?>
68
  <div class="fs-close"><i class="dashicons dashicons-no"
69
  title="<?php echo esc_attr( $dismiss_text ) ?>"></i> <span><?php echo esc_html( $dismiss_text ) ?></span>
70
  </div>
45
  case 'promotion':
46
  echo 'updated promotion';
47
  break;
48
+ case 'warn':
49
+ echo 'notice notice-warning';
50
+ break;
51
  case 'update':
52
  // echo 'update-nag update';
53
  // break;
67
  } ?>"><?php if ( ! empty( $VARS['plugin'] ) ) : ?>
68
  <label class="fs-plugin-title"><?php echo $VARS['plugin'] ?></label>
69
  <?php endif ?>
70
+ <?php if ( ! empty( $VARS['sticky'] ) && ( ! isset( $VARS['dismissible'] ) || false !== $VARS['dismissible'] ) ) : ?>
71
  <div class="fs-close"><i class="dashicons dashicons-no"
72
  title="<?php echo esc_attr( $dismiss_text ) ?>"></i> <span><?php echo esc_html( $dismiss_text ) ?></span>
73
  </div>
freemius/templates/auto-installation.php CHANGED
@@ -164,7 +164,7 @@
164
  }
165
 
166
  $.ajax({
167
- url : ajaxurl,
168
  method : 'POST',
169
  data : data,
170
  success: function (resultObj) {
164
  }
165
 
166
  $.ajax({
167
+ url : <?php echo Freemius::ajax_url() ?>,
168
  method : 'POST',
169
  data : data,
170
  success: function (resultObj) {
freemius/templates/clone-resolution-js.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.0
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+ ?>
13
+ <script type="text/javascript">
14
+ ( function( $ ) {
15
+ var $errorMessage = null;
16
+
17
+ $( document ).ready( function() {
18
+ var $cloneResolutionNotice = $( 'div[data-id="clone_resolution_options_notice"], div[data-id="temporary_duplicate_notice"]' );
19
+
20
+ if ( 0 === $cloneResolutionNotice.length ) {
21
+ return;
22
+ }
23
+
24
+ $errorMessage = $cloneResolutionNotice.find( '#fs_clone_resolution_error_message' );
25
+
26
+ /**
27
+ * Triggers an AJAX request when the license activation link or any of the buttons on the clone resolution options notice is clicked. The AJAX request will then handle the action the user has chosen.
28
+ */
29
+ $cloneResolutionNotice.on( 'click', '.button, #fs_temporary_duplicate_license_activation_link', function( evt ) {
30
+ evt.preventDefault();
31
+
32
+ var $this = $( this );
33
+
34
+ if ( $this.hasClass( 'disabled' ) ) {
35
+ return;
36
+ }
37
+
38
+ var $body = $( 'body' ),
39
+ $optionsContainer = $this.parents( '.fs-clone-resolution-options-container' ),
40
+ cursor = $body.css( 'cursor' ),
41
+ beforeUnload = function() {
42
+ return '<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait' ) ?>';
43
+ };
44
+
45
+ $.ajax( {
46
+ // Get the parent options container from the child as `$cloneResolutionNotice` can have different AJAX URLs if both the manual clone resolution options and temporary duplicate notices are shown (for different subsites in a multisite network).
47
+ url : $optionsContainer.data( 'ajax-url' ),
48
+ method : 'POST',
49
+ data : {
50
+ action : '<?php echo $VARS['ajax_action'] ?>',
51
+ security : '<?php echo wp_create_nonce( $VARS['ajax_action'] ) ?>',
52
+ clone_action: $this.data( 'clone-action' ),
53
+ blog_id : $optionsContainer.data( 'blog-id' )
54
+ },
55
+ beforeSend: function() {
56
+ $body.css( { cursor: 'wait' } );
57
+
58
+ $cloneResolutionNotice.find( '.button' ).addClass( 'disabled' );
59
+
60
+ $( window ).on( 'beforeunload', beforeUnload );
61
+ },
62
+ success : function( resultObj ) {
63
+ $( window ).off( 'beforeunload', beforeUnload );
64
+
65
+ if ( resultObj.data.redirect_url && '' !== resultObj.data.redirect_url ) {
66
+ window.location = resultObj.data.redirect_url;
67
+ } else {
68
+ window.location.reload();
69
+ }
70
+ },
71
+ error : function() {
72
+ $body.css( { cursor: cursor } );
73
+ $cloneResolutionNotice.find( '.button' ).removeClass( 'disabled' );
74
+ }
75
+ } );
76
+ } );
77
+ } );
78
+ } )( jQuery );
79
+ </script>
freemius/templates/connect.php CHANGED
@@ -25,6 +25,15 @@
25
 
26
  $fs->_enqueue_connect_essentials();
27
 
 
 
 
 
 
 
 
 
 
28
  $current_user = Freemius::_get_current_wp_user();
29
 
30
  $first_name = $current_user->user_firstname;
@@ -32,7 +41,7 @@
32
  $first_name = $current_user->nickname;
33
  }
34
 
35
- $site_url = get_site_url();
36
  $protocol_pos = strpos( $site_url, '://' );
37
  if ( false !== $protocol_pos ) {
38
  $site_url = substr( $site_url, $protocol_pos + 3 );
@@ -118,6 +127,14 @@
118
  if ( is_null( $is_gdpr_required ) ) {
119
  $is_gdpr_required = $fs->fetch_and_store_current_user_gdpr_anonymously();
120
  }
 
 
 
 
 
 
 
 
121
  ?>
122
  <?php
123
  if ( $is_optin_dialog ) { ?>
@@ -138,26 +155,54 @@
138
  * @author Vova Feldman
139
  * @since 2.3.2
140
  */
141
- $fs->do_action( 'connect/before' );
142
  ?>
143
  <div id="fs_connect"
144
  class="wrap<?php if ( ! fs_is_network_admin() && ( ! $fs->is_enable_anonymous() || $is_pending_activation || $require_license_key ) ) {
145
  echo ' fs-anonymous-disabled';
146
  } ?><?php echo $require_license_key ? ' require-license-key' : '' ?>">
147
- <div class="fs-visual">
148
- <b class="fs-site-icon"><i class="dashicons dashicons-wordpress"></i></b>
149
- <i class="dashicons dashicons-plus fs-first"></i>
150
- <?php
151
- $vars = array( 'id' => $fs->get_id() );
152
- fs_require_once_template( 'plugin-icon.php', $vars );
153
- ?>
154
- <i class="dashicons dashicons-plus fs-second"></i>
155
- <img class="fs-connect-logo" width="80" height="80" src="//img.freemius.com/connect-logo.png"/>
156
- </div>
 
 
 
 
157
  <div class="fs-content">
 
 
158
  <?php if ( ! empty( $error ) ) : ?>
159
- <p class="fs-error"><?php echo esc_html( $error ) ?></p>
160
  <?php endif ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  <p><?php
162
  $button_label = fs_text_inline( 'Allow & Continue', 'opt-in-connect', $slug );
163
  $message = '';
@@ -175,9 +220,7 @@
175
  fs_text_inline( 'complete the install', 'complete-the-install', $slug )
176
  ) );
177
  } else if ( $require_license_key ) {
178
- $button_label = $is_network_upgrade_mode ?
179
- fs_text_inline( 'Activate License', 'agree-activate-license', $slug ) :
180
- fs_text_inline( 'Agree & Activate License', 'agree-activate-license', $slug );
181
 
182
  $message = $fs->apply_filters(
183
  'connect-message_on-premium',
@@ -186,21 +229,32 @@
186
  $fs->get_plugin_name()
187
  );
188
  } else {
189
- $filter = 'connect_message';
190
- $default_optin_message = $is_gdpr_required ?
191
- fs_text_inline( 'Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s.', 'connect-message', $slug) :
192
- fs_text_inline( 'Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s.', 'connect-message', $slug);
193
 
194
- if ( $fs->is_plugin_update() ) {
 
 
 
 
 
 
195
  // If Freemius was added on a plugin update, set different
196
  // opt-in message.
197
- $default_optin_message = $is_gdpr_required ?
198
- fs_text_inline( 'Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s. If you skip this, that\'s okay! %1$s will still work just fine.', 'connect-message_on-update', $slug ) :
199
- fs_text_inline( 'Never miss an important update - opt in to our security & feature updates notifications, and non-sensitive diagnostic tracking with %4$s. If you skip this, that\'s okay! %1$s will still work just fine.', 'connect-message_on-update', $slug );
200
 
201
- // If user customized the opt-in message on update, use
 
 
 
 
 
 
 
 
 
 
 
202
  // that message. Otherwise, fallback to regular opt-in
203
- // custom message if exist.
204
  if ( $fs->has_filter( 'connect_message_on_update' ) ) {
205
  $filter = 'connect_message_on_update';
206
  }
@@ -208,17 +262,12 @@
208
 
209
  $message = $fs->apply_filters(
210
  $filter,
211
- ($is_network_upgrade_mode ?
212
- '' :
213
- /* translators: %s: name (e.g. Hey John,) */
214
- $hey_x_text . '<br>'
215
- ) .
216
  sprintf(
217
- esc_html( $default_optin_message ),
218
  '<b>' . esc_html( $fs->get_plugin_name() ) . '</b>',
219
  '<b>' . $current_user->user_login . '</b>',
220
  '<a href="' . $site_url . '" target="_blank" rel="noopener noreferrer">' . $site_url . '</a>',
221
- $freemius_link
222
  ),
223
  $first_name,
224
  $fs->get_plugin_name(),
@@ -266,7 +315,7 @@
266
  * @author Vova Feldman
267
  * @since 2.1.2
268
  */
269
- $fs->do_action( 'connect/after_license_input' );
270
  ?>
271
 
272
  <?php
@@ -311,8 +360,12 @@
311
  echo fs_get_template( 'partials/network-activation.php', $vars );
312
  ?>
313
  <?php endif ?>
 
 
314
  </div>
315
  <div class="fs-actions">
 
 
316
  <?php if ( $fs->is_enable_anonymous() && ! $is_pending_activation && ( ! $require_license_key || $is_network_upgrade_mode ) ) : ?>
317
  <a id="skip_activation" href="<?php echo fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ), $is_network_level_activation ), $fs->get_unique_affix() . '_skip_activation' ) ?>"
318
  class="button button-secondary" tabindex="2"><?php fs_esc_html_echo_x_inline( 'Skip', 'verb', 'skip', $slug ) ?></a>
@@ -326,6 +379,7 @@
326
  value="<?php echo $fs->get_unique_affix() ?>_activate_existing">
327
  <?php wp_nonce_field( 'activate_existing_' . $fs->get_public_key() ) ?>
328
  <input type="hidden" name="is_extensions_tracking_allowed" value="1">
 
329
  <button class="button button-primary" tabindex="1"
330
  type="submit"><?php echo esc_html( $button_label ) ?></button>
331
  </form>
@@ -336,6 +390,7 @@
336
  <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
337
  <?php endforeach ?>
338
  <input type="hidden" name="is_extensions_tracking_allowed" value="1">
 
339
  <button class="button button-primary" tabindex="1"
340
  type="submit"<?php if ( $require_license_key ) {
341
  echo ' disabled="disabled"';
@@ -345,109 +400,42 @@
345
  <?php if ( $require_license_key ) : ?>
346
  <a id="license_issues_link" href="<?php echo $fs->apply_filters( 'known_license_issues_url', 'https://freemius.com/help/documentation/wordpress-sdk/license-activation-issues/' ) ?>" target="_blank"><?php fs_esc_html_echo_inline( 'License issues?', 'license-issues', $slug ) ?></a>
347
  <?php endif ?>
 
 
348
  </div><?php
 
349
 
350
  // Set core permission list items.
351
  $permissions = array();
352
 
353
- /**
354
- * When activating a license key the information of the admin is not collected, we gather the user info from the license.
355
- *
356
- * @since 2.3.2
357
- * @author Vova Feldman
358
- */
359
- if ( ! $require_license_key ) {
360
- $permissions['profile'] = array(
361
- 'icon-class' => 'dashicons dashicons-admin-users',
362
- 'label' => $fs->get_text_inline( 'Your Profile Overview', 'permissions-profile' ),
363
- 'desc' => $fs->get_text_inline( 'Name and email address', 'permissions-profile_desc' ),
364
- 'priority' => 5,
365
- );
366
- }
367
-
368
- $permissions['site'] = array(
369
- 'icon-class' => 'dashicons dashicons-admin-settings',
370
- 'tooltip' => ( $require_license_key ? sprintf( $fs->get_text_inline( 'So you can manage and control your license remotely from the User Dashboard.', 'permissions-site_tooltip' ), $fs->get_module_type() ) : '' ),
371
- 'label' => $fs->get_text_inline( 'Your Site Overview', 'permissions-site' ),
372
- 'desc' => $fs->get_text_inline( 'Site URL, WP version, PHP info', 'permissions-site_desc' ),
373
- 'priority' => 10,
374
- );
375
-
376
- if ( ! $require_license_key ) {
377
- $permissions['notices'] = array(
378
- 'icon-class' => 'dashicons dashicons-testimonial',
379
- 'label' => $fs->get_text_inline( 'Admin Notices', 'permissions-admin-notices' ),
380
- 'desc' => $fs->get_text_inline( 'Updates, announcements, marketing, no spam', 'permissions-newsletter_desc' ),
381
- 'priority' => 13,
382
- );
383
- }
384
-
385
- $permissions['events'] = array(
386
- 'icon-class' => 'dashicons dashicons-admin-' . ( $fs->is_plugin() ? 'plugins' : 'appearance' ),
387
- 'tooltip' => ( $require_license_key ? sprintf( $fs->get_text_inline( 'So you can reuse the license when the %s is no longer active.', 'permissions-events_tooltip' ), $fs->get_module_type() ) : '' ),
388
- 'label' => sprintf( $fs->get_text_inline( 'Current %s Status', 'permissions-events' ), ucfirst( $fs->get_module_type() ) ),
389
- 'desc' => $fs->get_text_inline( 'Active, deactivated, or uninstalled', 'permissions-events_desc' ),
390
- 'priority' => 20,
391
- );
392
-
393
  // Add newsletter permissions if enabled.
394
  if ( $is_gdpr_required || $fs->is_permission_requested( 'newsletter' ) ) {
395
- $permissions['newsletter'] = array(
396
- 'icon-class' => 'dashicons dashicons-email-alt',
397
- 'label' => $fs->get_text_inline( 'Newsletter', 'permissions-newsletter' ),
398
- 'desc' => $fs->get_text_inline( 'Updates, announcements, marketing, no spam', 'permissions-newsletter_desc' ),
399
- 'priority' => 15,
400
- );
401
  }
402
 
403
- $permissions['extensions'] = array(
404
- 'icon-class' => 'dashicons dashicons-menu',
405
- 'label' => $fs->get_text_inline( 'Plugins & Themes', 'permissions-extensions' ) . ( $require_license_key ? ' (' . $fs->get_text_inline( 'optional' ) . ')' : '' ),
406
- 'tooltip' => $fs->get_text_inline( 'To help us troubleshoot any potential issues that may arise from other plugin or theme conflicts.', 'permissions-events_tooltip' ),
407
- 'desc' => $fs->get_text_inline( 'Title, slug, version, and is active', 'permissions-extensions_desc' ),
408
- 'priority' => 25,
409
- 'optional' => true,
410
- 'default' => $fs->apply_filters( 'permission_extensions_default', ! $require_license_key )
411
  );
412
 
413
- // Allow filtering of the permissions list.
414
- $permissions = $fs->apply_filters( 'permission_list', $permissions );
415
-
416
- // Sort by priority.
417
- uasort( $permissions, 'fs_sort_by_priority' );
418
-
419
  if ( ! empty( $permissions ) ) : ?>
420
  <div class="fs-permissions">
421
- <?php if ( $require_license_key ) : ?>
422
- <p class="fs-license-sync-disclaimer"><?php
423
- echo sprintf(
424
- fs_esc_html_inline( 'The %1$s will periodically send %2$s to %3$s for security & feature updates delivery, and license management.', 'license-sync-disclaimer', $slug ),
425
- $fs->get_module_label( true ),
426
- sprintf('<a class="fs-trigger" href="#" tabindex="1">%s</a>', fs_esc_html_inline('diagnostic data', 'send-data')),
427
- '<a class="fs-tooltip-trigger' . (is_rtl() ? ' rtl' : '') . '" href="' . $freemius_site_url . '" target="_blank" rel="noopener" tabindex="1">freemius.com <i class="dashicons dashicons-editor-help" style="text-decoration: none;"><span class="fs-tooltip" style="width: 170px">' . $fs->get_text_inline( 'Freemius is our licensing and software updates engine', 'permissions-extensions_desc' ) . '</span></i></a>'
428
- ) ?></p>
429
- <?php else : ?>
430
- <a class="fs-trigger" href="#" tabindex="1"><?php fs_esc_html_echo_inline( 'What permissions are being granted?', 'what-permissions', $slug ) ?></a>
431
  <?php endif ?>
432
  <ul><?php
433
- foreach ( $permissions as $id => $permission ) : ?>
434
- <li id="fs-permission-<?php echo esc_attr( $id ); ?>"
435
- class="fs-permission fs-<?php echo esc_attr( $id ); ?>">
436
- <i class="<?php echo esc_attr( $permission['icon-class'] ); ?>"></i>
437
- <?php if ( isset( $permission['optional'] ) && true === $permission['optional'] ) : ?>
438
- <div class="fs-switch fs-small fs-round fs-<?php echo (! isset( $permission['default'] ) || true === $permission['default'] ) ? 'on' : 'off' ?>">
439
- <div class="fs-toggle"></div>
440
- </div>
441
- <?php endif ?>
442
-
443
- <div class="fs-permission-description">
444
- <span<?php if ( ! empty($permission['tooltip']) ) : ?> class="fs-tooltip-trigger"<?php endif ?>><?php echo esc_html( $permission['label'] ); ?><?php if ( ! empty($permission['tooltip']) ) : ?><i class="dashicons dashicons-editor-help"><span class="fs-tooltip" style="width: 200px"><?php echo $permission['tooltip'] ?></span></i><?php endif ?></span>
445
-
446
- <p><?php echo esc_html( $permission['desc'] ); ?></p>
447
- </div>
448
- </li>
449
- <?php endforeach; ?>
450
- </ul>
451
  </div>
452
  <?php endif ?>
453
  <?php if ( $is_premium_code && $is_freemium ) : ?>
@@ -463,7 +451,10 @@
463
  </p>
464
  </div>
465
  <?php endif ?>
 
466
  <div class="fs-terms">
 
 
467
  <a href="https://freemius.com/privacy/" target="_blank" rel="noopener"
468
  tabindex="1"><?php fs_esc_html_echo_inline( 'Privacy Policy', 'privacy-policy', $slug ) ?></a>
469
  &nbsp;&nbsp;-&nbsp;&nbsp;
@@ -477,7 +468,7 @@
477
  * @author Vova Feldman
478
  * @since 2.3.2
479
  */
480
- $fs->do_action( 'connect/after' );
481
 
482
  if ( $is_optin_dialog ) { ?>
483
  </div>
@@ -531,13 +522,12 @@
531
  // Reset loading mode.
532
  $primaryCta.html(primaryCtaLabel);
533
  $primaryCta.prop('disabled', false);
534
- $(document.body).css({'cursor': 'auto'});
535
- $('.fs-loading').removeClass('fs-loading');
536
 
537
  console.log('resetLoadingMode - Primary button was enabled');
538
  },
539
  setLoadingMode = function () {
540
- $(document.body).css({'cursor': 'wait'});
541
  };
542
 
543
  $('.fs-actions .button').on('click', function () {
@@ -601,6 +591,11 @@
601
  updatePrimaryCtaText( actionType );
602
  });
603
 
 
 
 
 
 
604
  $sitesListContainer.delegate( '.action', 'click', function( evt ) {
605
  var $this = $( evt.target );
606
  if ( $this.hasClass( 'selected' ) ) {
@@ -707,15 +702,25 @@
707
  var ajaxOptin = ( requireLicenseKey || isNetworkActive );
708
 
709
  $form.on('submit', function () {
710
- var $extensionsPermission = $('#fs-permission-extensions .fs-switch'),
711
- isExtensionsTrackingAllowed = ($extensionsPermission.length > 0) ?
712
- $extensionsPermission.hasClass('fs-on') :
713
  null;
714
 
715
- if (null === isExtensionsTrackingAllowed) {
716
- $('input[name=is_extensions_tracking_allowed]').remove();
 
 
 
 
 
717
  } else {
718
- $('input[name=is_extensions_tracking_allowed]').val(isExtensionsTrackingAllowed ? 1 : 0);
 
 
 
 
 
719
  }
720
 
721
  /**
@@ -772,6 +777,8 @@
772
  data.is_marketing_allowed = isMarketingAllowed;
773
 
774
  data.is_extensions_tracking_allowed = isExtensionsTrackingAllowed;
 
 
775
  }
776
 
777
  $marketingOptin.removeClass( 'error' );
@@ -794,7 +801,6 @@
794
  url : $this.find( '.url' ).val(),
795
  title : $this.find( '.title' ).val(),
796
  language: $this.find( '.language' ).val(),
797
- charset : $this.find( '.charset' ).val(),
798
  blog_id : $this.find( '.blog-id' ).find( 'span' ).text()
799
  };
800
 
@@ -822,7 +828,7 @@
822
  * @since 1.2.1.5
823
  */
824
  $.ajax({
825
- url : ajaxurl,
826
  method : 'POST',
827
  data : data,
828
  success: function (result) {
@@ -858,6 +864,15 @@
858
  return true;
859
  });
860
 
 
 
 
 
 
 
 
 
 
861
  $primaryCta.on('click', function () {
862
  console.log('Primary button was clicked');
863
 
@@ -874,12 +889,6 @@
874
  return false;
875
  });
876
 
877
- $( '.fs-switch' ).click( function () {
878
- $(this)
879
- .toggleClass( 'fs-on' )
880
- .toggleClass( 'fs-off' );
881
- });
882
-
883
  if (requireLicenseKey) {
884
  /**
885
  * Submit license key on enter.
@@ -1005,7 +1014,7 @@
1005
  $primaryCta.html('<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait', $slug ) ?>...');
1006
 
1007
  $.ajax({
1008
- url : ajaxurl,
1009
  method : 'POST',
1010
  data : {
1011
  action : '<?php echo $fs->get_ajax_action( 'fetch_is_marketing_required_flag_value' ) ?>',
@@ -1035,4 +1044,4 @@
1035
 
1036
  //endregion
1037
  })(jQuery);
1038
- </script>
25
 
26
  $fs->_enqueue_connect_essentials();
27
 
28
+ /**
29
+ * Enqueueing the styles in `_enqueue_connect_essentials()` is too late, as we need them in the HEADER. Therefore, inject the styles inline to avoid FOUC.
30
+ *
31
+ * @author Vova Feldman (@svovaf)
32
+ */
33
+ echo "<style>\n";
34
+ include WP_FS__DIR_CSS . '/admin/connect.css';
35
+ echo "</style>\n";
36
+
37
  $current_user = Freemius::_get_current_wp_user();
38
 
39
  $first_name = $current_user->user_firstname;
41
  $first_name = $current_user->nickname;
42
  }
43
 
44
+ $site_url = Freemius::get_unfiltered_site_url();
45
  $protocol_pos = strpos( $site_url, '://' );
46
  if ( false !== $protocol_pos ) {
47
  $site_url = substr( $site_url, $protocol_pos + 3 );
127
  if ( is_null( $is_gdpr_required ) ) {
128
  $is_gdpr_required = $fs->fetch_and_store_current_user_gdpr_anonymously();
129
  }
130
+
131
+ $activation_state = array(
132
+ 'is_license_activation' => $require_license_key,
133
+ 'is_pending_activation' => $is_pending_activation,
134
+ 'is_gdpr_required' => $is_gdpr_required,
135
+ 'is_network_level_activation' => $is_network_level_activation,
136
+ 'is_dialog' => $is_optin_dialog,
137
+ );
138
  ?>
139
  <?php
140
  if ( $is_optin_dialog ) { ?>
155
  * @author Vova Feldman
156
  * @since 2.3.2
157
  */
158
+ $fs->do_action( 'connect/before', $activation_state );
159
  ?>
160
  <div id="fs_connect"
161
  class="wrap<?php if ( ! fs_is_network_admin() && ( ! $fs->is_enable_anonymous() || $is_pending_activation || $require_license_key ) ) {
162
  echo ' fs-anonymous-disabled';
163
  } ?><?php echo $require_license_key ? ' require-license-key' : '' ?>">
164
+ <div class="fs-header">
165
+ <!-- <b class="fs-site-icon"><i class="dashicons dashicons-wordpress-alt"></i></b>-->
166
+ <?php
167
+ $size = 50;
168
+ $vars = array(
169
+ 'id' => $fs->get_id(),
170
+ 'size' => $size,
171
+ );
172
+
173
+ fs_require_once_template( 'plugin-icon.php', $vars );
174
+ ?>
175
+ <!-- <img class="fs-connect-logo" width="--><?php //echo $size ?><!--" height="--><?php //echo $size ?><!--" src="//img.freemius.com/logo/connect.svg"/>-->
176
+ </div>
177
+ <div class="fs-box-container">
178
  <div class="fs-content">
179
+ <?php $fs->do_action( 'connect/before_message', $activation_state ) ?>
180
+
181
  <?php if ( ! empty( $error ) ) : ?>
182
+ <p class="fs-error"><?php echo $fs->apply_filters( 'connect_error_esc_html', esc_html( $error ) ) ?></p>
183
  <?php endif ?>
184
+ <?php
185
+ if ( ! $is_pending_activation && ! $require_license_key ) {
186
+ if ( ! $fs->is_plugin_update() ) {
187
+ echo $fs->apply_filters( 'connect-header', sprintf(
188
+ '<h2 style="text-align: center">%s</h2>',
189
+ esc_html( fs_text_inline( 'Never miss an important update', 'connect-header' ) )
190
+ ) );
191
+ } else {
192
+ echo $fs->apply_filters( 'connect-header_on-update', sprintf(
193
+ '<h2>%s</h2>',
194
+ sprintf(
195
+ esc_html(
196
+ /* translators: %1$s: plugin name (e.g., "Awesome Plugin"); %2$s: version (e.g., "1.2.3") */
197
+ fs_text_inline('Thank you for updating to %1$s v%2$s!', 'connect-header_on-update' )
198
+ ),
199
+ esc_html( $fs->get_plugin_name() ),
200
+ $fs->get_plugin_version()
201
+ )
202
+ ) );
203
+ }
204
+ }
205
+ ?>
206
  <p><?php
207
  $button_label = fs_text_inline( 'Allow & Continue', 'opt-in-connect', $slug );
208
  $message = '';
220
  fs_text_inline( 'complete the install', 'complete-the-install', $slug )
221
  ) );
222
  } else if ( $require_license_key ) {
223
+ $button_label = fs_text_inline( 'Activate License', 'activate-license', $slug );
 
 
224
 
225
  $message = $fs->apply_filters(
226
  'connect-message_on-premium',
229
  $fs->get_plugin_name()
230
  );
231
  } else {
232
+ $filter = 'connect_message';
 
 
 
233
 
234
+ if ( ! $fs->is_plugin_update() ) {
235
+ $default_optin_message = esc_html( sprintf( ( $is_gdpr_required ?
236
+ /* translators: %s: module type (plugin, theme, or add-on) */
237
+ fs_text_inline( 'Opt in to get email notifications for security & feature updates, educational content, and occasional offers, and to share some basic WordPress environment info. This will help us make the %s more compatible with your site and better at doing what you need it to.', 'connect-message', $slug ) :
238
+ /* translators: %s: module type (plugin, theme, or add-on) */
239
+ fs_text_inline( 'Opt in to get email notifications for security & feature updates, and to share some basic WordPress environment info. This will help us make the %s more compatible with your site and better at doing what you need it to.', 'connect-message', $slug ) ), $fs->get_module_label( true ) ) );
240
+ } else {
241
  // If Freemius was added on a plugin update, set different
242
  // opt-in message.
 
 
 
243
 
244
+ /* translators: %s: module type (plugin, theme, or add-on) */
245
+ $default_optin_message = esc_html( sprintf( fs_text_inline( 'We have introduced this opt-in so you never miss an important update and help us make the %s more compatible with your site and better at doing what you need it to.', 'connect-message_on-update_why' ), $fs->get_module_label( true ) ) );
246
+
247
+ $default_optin_message .= '<br><br>' . esc_html( $is_gdpr_required ?
248
+ fs_text_inline( 'Opt in to get email notifications for security & feature updates, educational content, and occasional offers, and to share some basic WordPress environment info.', 'connect-message_on-update', $slug ) :
249
+ fs_text_inline( 'Opt in to get email notifications for security & feature updates, and to share some basic WordPress environment info.', 'connect-message_on-update', $slug ) );
250
+
251
+ if ( $fs->is_enable_anonymous() ) {
252
+ $default_optin_message .= ' ' . esc_html( fs_text_inline( 'If you skip this, that\'s okay! %1$s will still work just fine.', 'connect-message_on-update_skip', $slug ) );
253
+ }
254
+
255
+ // If user customized the opt-in message on update, use
256
  // that message. Otherwise, fallback to regular opt-in
257
+ // custom message if exists.
258
  if ( $fs->has_filter( 'connect_message_on_update' ) ) {
259
  $filter = 'connect_message_on_update';
260
  }
262
 
263
  $message = $fs->apply_filters(
264
  $filter,
 
 
 
 
 
265
  sprintf(
266
+ $default_optin_message,
267
  '<b>' . esc_html( $fs->get_plugin_name() ) . '</b>',
268
  '<b>' . $current_user->user_login . '</b>',
269
  '<a href="' . $site_url . '" target="_blank" rel="noopener noreferrer">' . $site_url . '</a>',
270
+ $freemius_link
271
  ),
272
  $first_name,
273
  $fs->get_plugin_name(),
315
  * @author Vova Feldman
316
  * @since 2.1.2
317
  */
318
+ $fs->do_action( 'connect/after_license_input', $activation_state );
319
  ?>
320
 
321
  <?php
360
  echo fs_get_template( 'partials/network-activation.php', $vars );
361
  ?>
362
  <?php endif ?>
363
+
364
+ <?php $fs->do_action( 'connect/after_message', $activation_state ) ?>
365
  </div>
366
  <div class="fs-actions">
367
+ <?php $fs->do_action( 'connect/before_actions', $activation_state ) ?>
368
+
369
  <?php if ( $fs->is_enable_anonymous() && ! $is_pending_activation && ( ! $require_license_key || $is_network_upgrade_mode ) ) : ?>
370
  <a id="skip_activation" href="<?php echo fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ), $is_network_level_activation ), $fs->get_unique_affix() . '_skip_activation' ) ?>"
371
  class="button button-secondary" tabindex="2"><?php fs_esc_html_echo_x_inline( 'Skip', 'verb', 'skip', $slug ) ?></a>
379
  value="<?php echo $fs->get_unique_affix() ?>_activate_existing">
380
  <?php wp_nonce_field( 'activate_existing_' . $fs->get_public_key() ) ?>
381
  <input type="hidden" name="is_extensions_tracking_allowed" value="1">
382
+ <input type="hidden" name="is_diagnostic_tracking_allowed" value="1">
383
  <button class="button button-primary" tabindex="1"
384
  type="submit"><?php echo esc_html( $button_label ) ?></button>
385
  </form>
390
  <input type="hidden" name="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>">
391
  <?php endforeach ?>
392
  <input type="hidden" name="is_extensions_tracking_allowed" value="1">
393
+ <input type="hidden" name="is_diagnostic_tracking_allowed" value="1">
394
  <button class="button button-primary" tabindex="1"
395
  type="submit"<?php if ( $require_license_key ) {
396
  echo ' disabled="disabled"';
400
  <?php if ( $require_license_key ) : ?>
401
  <a id="license_issues_link" href="<?php echo $fs->apply_filters( 'known_license_issues_url', 'https://freemius.com/help/documentation/wordpress-sdk/license-activation-issues/' ) ?>" target="_blank"><?php fs_esc_html_echo_inline( 'License issues?', 'license-issues', $slug ) ?></a>
402
  <?php endif ?>
403
+
404
+ <?php $fs->do_action( 'connect/after_actions', $activation_state ) ?>
405
  </div><?php
406
+ $permission_manager = FS_Permission_Manager::instance( $fs );
407
 
408
  // Set core permission list items.
409
  $permissions = array();
410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  // Add newsletter permissions if enabled.
412
  if ( $is_gdpr_required || $fs->is_permission_requested( 'newsletter' ) ) {
413
+ $permissions[] = $permission_manager->get_newsletter_permission();
 
 
 
 
 
414
  }
415
 
416
+ $permissions = $permission_manager->get_permissions(
417
+ $require_license_key,
418
+ $permissions
 
 
 
 
 
419
  );
420
 
 
 
 
 
 
 
421
  if ( ! empty( $permissions ) ) : ?>
422
  <div class="fs-permissions">
423
+ <?php if ( $require_license_key ) : ?>
424
+ <a class="fs-trigger wp-core-ui" href="#" tabindex="1" style="color: inherit;"><?php echo sprintf(
425
+ fs_esc_html_inline( 'For delivery of security & feature updates, and license management, %s needs to', 'license-sync-disclaimer', $slug ) . '<b class="fs-arrow"></b>',
426
+ sprintf( '<nobr class="button-link" style="color: inherit;">%s</nobr>', $fs->get_plugin_title() )
427
+ ) ?></a>
428
+ <?php else : ?>
429
+ <a class="fs-trigger wp-core-ui" href="#" tabindex="1" style="color: inherit;"><?php printf(
430
+ fs_esc_html_inline( 'This will allow %s to', 'this-will-allow-x', $slug ) . '<b class="fs-arrow"></b>',
431
+ sprintf( '<nobr class="button-link" style="color: inherit;">%s</nobr>', $fs->get_plugin_title() )
432
+ ) ?></a>
433
  <?php endif ?>
434
  <ul><?php
435
+ foreach ( $permissions as $permission ) {
436
+ $permission_manager->render_permission( $permission );
437
+ }
438
+ ?></ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  </div>
440
  <?php endif ?>
441
  <?php if ( $is_premium_code && $is_freemium ) : ?>
451
  </p>
452
  </div>
453
  <?php endif ?>
454
+ </div>
455
  <div class="fs-terms">
456
+ <a class="fs-tooltip-trigger<?php echo is_rtl() ? ' rtl' : '' ?>" href="<?php echo $freemius_site_url ?>" target="_blank" rel="noopener" tabindex="1">Powered by Freemius<?php if ( $require_license_key ) : ?> <span class="fs-tooltip" style="width: 170px"><?php echo $fs->get_text_inline( 'Freemius is our licensing and software updates engine', 'permissions-extensions_desc' ) ?></span><?php endif ?></a>
457
+ &nbsp;&nbsp;-&nbsp;&nbsp;
458
  <a href="https://freemius.com/privacy/" target="_blank" rel="noopener"
459
  tabindex="1"><?php fs_esc_html_echo_inline( 'Privacy Policy', 'privacy-policy', $slug ) ?></a>
460
  &nbsp;&nbsp;-&nbsp;&nbsp;
468
  * @author Vova Feldman
469
  * @since 2.3.2
470
  */
471
+ $fs->do_action( 'connect/after', $activation_state );
472
 
473
  if ( $is_optin_dialog ) { ?>
474
  </div>
522
  // Reset loading mode.
523
  $primaryCta.html(primaryCtaLabel);
524
  $primaryCta.prop('disabled', false);
525
+ $( '.fs-loading' ).removeClass( 'fs-loading' );
 
526
 
527
  console.log('resetLoadingMode - Primary button was enabled');
528
  },
529
  setLoadingMode = function () {
530
+ $( document.body ).addClass( 'fs-loading' );
531
  };
532
 
533
  $('.fs-actions .button').on('click', function () {
591
  updatePrimaryCtaText( actionType );
592
  });
593
 
594
+ $sitesListContainer.delegate( 'td:not(:first-child)', 'click', function() {
595
+ // If a site row is clicked, trigger a click on the checkbox.
596
+ $( this ).parent().find( 'td:first-child input' ).click();
597
+ } );
598
+
599
  $sitesListContainer.delegate( '.action', 'click', function( evt ) {
600
  var $this = $( evt.target );
601
  if ( $this.hasClass( 'selected' ) ) {
702
  var ajaxOptin = ( requireLicenseKey || isNetworkActive );
703
 
704
  $form.on('submit', function () {
705
+ var $extensionsPermission = $( '#fs_permission_extensions .fs-switch' ),
706
+ isExtensionsTrackingAllowed = ( $extensionsPermission.length > 0 ) ?
707
+ $extensionsPermission.hasClass( 'fs-on' ) :
708
  null;
709
 
710
+ var $diagnosticPermission = $( '#fs_permission_diagnostic .fs-switch' ),
711
+ isDiagnosticTrackingAllowed = ( $diagnosticPermission.length > 0 ) ?
712
+ $diagnosticPermission.hasClass( 'fs-on' ) :
713
+ null;
714
+
715
+ if ( null === isExtensionsTrackingAllowed ) {
716
+ $( 'input[name=is_extensions_tracking_allowed]' ).remove();
717
  } else {
718
+ $( 'input[name=is_extensions_tracking_allowed]' ).val( isExtensionsTrackingAllowed ? 1 : 0 );
719
+ }
720
+
721
+ // We are not showing switch to enable/disable diagnostic tracking while activating free version. So, don't remove hidden `is_diagnostic_tracking_allowed` element from DOM and change the value only if switch is available.
722
+ if ( null !== isDiagnosticTrackingAllowed ) {
723
+ $( 'input[name=is_diagnostic_tracking_allowed]' ).val( isDiagnosticTrackingAllowed ? 1 : 0 );
724
  }
725
 
726
  /**
777
  data.is_marketing_allowed = isMarketingAllowed;
778
 
779
  data.is_extensions_tracking_allowed = isExtensionsTrackingAllowed;
780
+
781
+ data.is_diagnostic_tracking_allowed = isDiagnosticTrackingAllowed;
782
  }
783
 
784
  $marketingOptin.removeClass( 'error' );
801
  url : $this.find( '.url' ).val(),
802
  title : $this.find( '.title' ).val(),
803
  language: $this.find( '.language' ).val(),
 
804
  blog_id : $this.find( '.blog-id' ).find( 'span' ).text()
805
  };
806
 
828
  * @since 1.2.1.5
829
  */
830
  $.ajax({
831
+ url : <?php echo Freemius::ajax_url() ?>,
832
  method : 'POST',
833
  data : data,
834
  success: function (result) {
864
  return true;
865
  });
866
 
867
+ $( '#fs_connect .fs-permissions .fs-switch' ).on( 'click', function () {
868
+ $( this )
869
+ .toggleClass( 'fs-on' )
870
+ .toggleClass( 'fs-off' );
871
+
872
+ $( this ).closest( '.fs-permission' )
873
+ .toggleClass( 'fs-disabled' );
874
+ });
875
+
876
  $primaryCta.on('click', function () {
877
  console.log('Primary button was clicked');
878
 
889
  return false;
890
  });
891
 
 
 
 
 
 
 
892
  if (requireLicenseKey) {
893
  /**
894
  * Submit license key on enter.
1014
  $primaryCta.html('<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait', $slug ) ?>...');
1015
 
1016
  $.ajax({
1017
+ url : <?php echo Freemius::ajax_url() ?>,
1018
  method : 'POST',
1019
  data : {
1020
  action : '<?php echo $fs->get_ajax_action( 'fetch_is_marketing_required_flag_value' ) ?>',
1044
 
1045
  //endregion
1046
  })(jQuery);
1047
+ </script>
freemius/templates/connect/index.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+ // Silence is golden.
3
+ // Hide file structure from users on unprotected servers.
freemius/templates/connect/permission.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2022, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ * @var array $permission {
16
+ * @type string $id
17
+ * @type bool $default
18
+ * @type string $icon-class
19
+ * @type bool $optional
20
+ * @type string $label
21
+ * @type string $tooltip
22
+ * @type string $desc
23
+ * }
24
+ */
25
+ $permission = $VARS;
26
+
27
+ $is_permission_on = ( ! isset( $permission['default'] ) || true === $permission['default'] );
28
+ ?>
29
+ <li id="fs_permission_<?php echo esc_attr( $permission['id'] ) ?>" data-permission-id="<?php echo esc_attr( $permission['id'] ) ?>"
30
+ class="fs-permission fs-<?php echo esc_attr( $permission['id'] ); ?><?php echo ( ! $is_permission_on ) ? ' fs-disabled' : ''; ?>">
31
+ <i class="<?php echo esc_attr( $permission['icon-class'] ); ?>"></i>
32
+ <?php if ( isset( $permission['optional'] ) && true === $permission['optional'] ) : ?>
33
+ <div class="fs-switch fs-small fs-round fs-<?php echo $is_permission_on ? 'on' : 'off' ?>">
34
+ <div class="fs-toggle"></div>
35
+ </div>
36
+ <?php endif ?>
37
+
38
+ <div class="fs-permission-description">
39
+ <span<?php if ( ! empty( $permission['tooltip'] ) ) : ?> class="fs-tooltip-trigger"<?php endif ?>><?php echo esc_html( $permission['label'] ); ?><?php if ( ! empty( $permission['tooltip'] ) ) : ?><i class="dashicons dashicons-editor-help"><span class="fs-tooltip" style="width: 200px"><?php echo esc_html( $permission['tooltip'] ) ?></span></i><?php endif ?></span>
40
+
41
+ <p><?php echo esc_html( $permission['desc'] ); ?></p>
42
+ </div>
43
+ </li>
freemius/templates/connect/permissions-group.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2022, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @var array $VARS
15
+ *
16
+ * @var array $permission_group {
17
+ * @type Freemius $fs
18
+ * @type string $id
19
+ * @type string $desc
20
+ * @type array $prompt
21
+ * @type array $permissions
22
+ * @type bool $is_enabled
23
+ * }
24
+ */
25
+ $permission_group = $VARS;
26
+
27
+ $fs = $permission_group[ 'fs' ];
28
+
29
+ $permission_manager = FS_Permission_Manager::instance( $fs );
30
+
31
+ $opt_out_text = $fs->get_text_x_inline( 'Opt Out', 'verb', 'opt-out' );
32
+ $opt_in_text = $fs->get_text_x_inline( 'Opt In', 'verb', 'opt-in' );
33
+
34
+ if ( empty( $permission_group[ 'prompt' ] ) ) {
35
+ $is_enabled = false;
36
+
37
+ foreach ( $permission_group[ 'permissions' ] as $permission ) {
38
+ if ( true === $permission[ 'default' ] ) {
39
+ // Even if one of the permissions is on, treat as if the entire group is on.
40
+ $is_enabled = true;
41
+ break;
42
+ }
43
+ }
44
+ } else {
45
+ $is_enabled = ( isset( $permission_group['is_enabled'] ) && true === $permission_group['is_enabled'] );
46
+ }
47
+ ?>
48
+ <div class="fs-permissions-section fs-<?php echo esc_attr( $permission_group[ 'id' ] ) ?>-permissions">
49
+ <div>
50
+ <div class="fs-permissions-section--header">
51
+ <a class="fs-group-opt-out-button"
52
+ data-type="<?php echo esc_attr( $permission_group['type'] ) ?>"
53
+ data-group-id="<?php echo esc_attr( $permission_group[ 'id' ] ) ?>"
54
+ data-is-enabled="<?php echo $is_enabled ? 'true' : 'false' ?>"
55
+ href="#"><?php echo esc_html( $is_enabled ? $opt_out_text : $opt_in_text ) ?></a>
56
+ <span class="fs-permissions-section--header-title"><?php
57
+ // The title is already HTML-escaped.
58
+ echo $permission_group[ 'title' ]
59
+ ?></span>
60
+ </div>
61
+ <p class="fs-permissions-section--desc"><?php
62
+ // The description is already HTML-escaped.
63
+ echo $permission_group['desc']
64
+ ?></p></div>
65
+ <ul>
66
+ <?php
67
+ foreach ( $permission_group['permissions'] as $permission ) {
68
+ $permission_manager->render_permission( $permission );
69
+ }
70
+ ?>
71
+ </ul>
72
+ </div>
freemius/templates/contact.php CHANGED
@@ -69,7 +69,7 @@
69
  $query_params = array_merge( $_GET, array_merge( $context_params, array(
70
  'plugin_version' => $fs->get_plugin_version(),
71
  'wp_login_url' => wp_login_url(),
72
- 'site_url' => get_site_url(),
73
  // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
74
  ) ) );
75
 
69
  $query_params = array_merge( $_GET, array_merge( $context_params, array(
70
  'plugin_version' => $fs->get_plugin_version(),
71
  'wp_login_url' => wp_login_url(),
72
+ 'site_url' => Freemius::get_unfiltered_site_url(),
73
  // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
74
  ) ) );
75
 
freemius/templates/debug.php CHANGED
@@ -16,6 +16,10 @@
16
 
17
  $off_text = fs_text_x_inline( 'Off', 'as turned off' );
18
  $on_text = fs_text_x_inline( 'On', 'as turned on' );
 
 
 
 
19
  ?>
20
  <h1><?php echo fs_text_inline( 'Freemius Debug' ) . ' - ' . fs_text_inline( 'SDK' ) . ' v.' . $fs_active_plugins->newest->version ?></h1>
21
  <div>
@@ -35,7 +39,7 @@
35
  .toggleClass( 'fs-on' )
36
  .toggleClass( 'fs-off' );
37
 
38
- $.post( ajaxurl, {
39
  action: 'fs_toggle_debug_mode',
40
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
41
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_toggle_debug_mode' ) ); ?>,
@@ -79,6 +83,16 @@
79
  <button class="button"><?php fs_esc_html_echo_inline( 'Clear Updates Transients' ) ?></button>
80
  </form>
81
  </td>
 
 
 
 
 
 
 
 
 
 
82
  <td>
83
  <!-- Sync Data with Server -->
84
  <form action="" method="POST">
@@ -102,6 +116,15 @@
102
  <td>
103
  <button id="fs_set_db_option" class="button"><?php fs_esc_html_echo_inline( 'Set DB Option' ) ?></button>
104
  </td>
 
 
 
 
 
 
 
 
 
105
  </tr>
106
  </tbody>
107
  </table>
@@ -111,7 +134,7 @@
111
  var optionName = prompt('Please enter the option name:');
112
 
113
  if (optionName) {
114
- $.post(ajaxurl, {
115
  action : 'fs_get_db_option',
116
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
117
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_get_db_option' ) ); ?>,
@@ -132,7 +155,7 @@
132
  var optionValue = prompt('Please enter the option value:');
133
 
134
  if (optionValue) {
135
- $.post(ajaxurl, {
136
  action : 'fs_set_db_option',
137
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
138
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_set_db_option' ) ); ?>,
@@ -175,6 +198,10 @@
175
  'key' => 'WP_FS__DIR',
176
  'val' => WP_FS__DIR,
177
  ),
 
 
 
 
178
  )
179
  ?>
180
  <br>
@@ -229,7 +256,7 @@
229
  WP_FS__MODULE_TYPE_THEME
230
  );
231
  ?>
232
-
233
  <?php foreach ( $module_types as $module_type ) : ?>
234
  <?php $modules = fs_get_entities( $fs_options->get_option( $module_type . 's' ), FS_Plugin::get_class_name() ) ?>
235
  <?php if ( is_array( $modules ) && count( $modules ) > 0 ) : ?>
@@ -245,7 +272,7 @@
245
  <th><?php fs_esc_html_echo_inline( 'Freemius State' ) ?></th>
246
  <th><?php fs_esc_html_echo_inline( 'Module Path' ) ?></th>
247
  <th><?php fs_esc_html_echo_inline( 'Public Key' ) ?></th>
248
- <?php if ( is_multisite() ) : ?>
249
  <th><?php fs_esc_html_echo_inline( 'Network Blog' ) ?></th>
250
  <th><?php fs_esc_html_echo_inline( 'Network User' ) ?></th>
251
  <?php endif ?>
@@ -268,7 +295,14 @@
268
  }
269
  }
270
  ?>
271
- <?php $fs = $is_active ? freemius( $data->id ) : null ?>
 
 
 
 
 
 
 
272
  <tr<?php if ( $is_active ) {
273
  if ( $fs->has_api_connectivity() && $fs->is_on() ) {
274
  echo ' style="background: #E6FFE6; font-weight: bold"';
@@ -298,7 +332,7 @@
298
  } ?></td>
299
  <td><?php echo $data->file ?></td>
300
  <td><?php echo $data->public_key ?></td>
301
- <?php if ( is_multisite() ) : ?>
302
  <?php
303
  $network_blog_id = null;
304
  $network_user = null;
@@ -352,8 +386,7 @@
352
  */
353
  $sites_map = $VARS[ $module_type . '_sites' ];
354
 
355
- $is_multisite = is_multisite();
356
- $all_plans = false;
357
  ?>
358
  <?php if ( is_array( $sites_map ) && count( $sites_map ) > 0 ) : ?>
359
  <h2><?php echo esc_html( sprintf(
@@ -379,15 +412,37 @@
379
  </tr>
380
  </thead>
381
  <tbody>
 
382
  <?php foreach ( $sites_map as $slug => $sites ) : ?>
383
- <?php if ( ! is_array( $sites ) ) {
384
- $sites = array( $sites );
385
- } ?>
386
  <?php foreach ( $sites as $site ) : ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  <tr>
388
- <td><?php echo $site->id ?></td>
 
 
 
 
 
389
  <?php if ( $is_multisite ) : ?>
390
- <td><?php echo $site->blog_id ?></td>
391
  <td><?php echo fs_strip_url_protocol( $site->url ) ?></td>
392
  <?php endif ?>
393
  <td><?php echo $slug ?></td>
@@ -484,8 +539,15 @@
484
  * @var FS_User[] $users
485
  */
486
  $users = $VARS['users'];
 
487
  $users_with_developer_license_by_id = array();
488
 
 
 
 
 
 
 
489
  foreach ( $module_types as $module_type ) {
490
  /**
491
  * @var FS_Plugin_License[] $licenses
@@ -578,7 +640,7 @@
578
  <td><?php echo $license->is_block_features ? 'Blocking' : 'Flexible' ?></td>
579
  <td><?php echo $license->is_whitelabeled ? 'Whitelabeled' : 'Normal' ?></td>
580
  <td><?php
581
- echo $license->is_whitelabeled ?
582
  $license->get_html_escaped_masked_secret_key() :
583
  esc_html( $license->secret_key );
584
  ?></td>
@@ -726,7 +788,7 @@
726
  offset = 0;
727
  }
728
 
729
- $.post(ajaxurl, {
730
  action : 'fs_get_debug_log',
731
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
732
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_get_debug_log' ) ); ?>,
16
 
17
  $off_text = fs_text_x_inline( 'Off', 'as turned off' );
18
  $on_text = fs_text_x_inline( 'On', 'as turned on' );
19
+
20
+ $has_any_active_clone = false;
21
+
22
+ $is_multisite = is_multisite();
23
  ?>
24
  <h1><?php echo fs_text_inline( 'Freemius Debug' ) . ' - ' . fs_text_inline( 'SDK' ) . ' v.' . $fs_active_plugins->newest->version ?></h1>
25
  <div>
39
  .toggleClass( 'fs-on' )
40
  .toggleClass( 'fs-off' );
41
 
42
+ $.post( <?php echo Freemius::ajax_url() ?>, {
43
  action: 'fs_toggle_debug_mode',
44
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
45
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_toggle_debug_mode' ) ); ?>,
83
  <button class="button"><?php fs_esc_html_echo_inline( 'Clear Updates Transients' ) ?></button>
84
  </form>
85
  </td>
86
+ <?php if ( Freemius::is_deactivation_snoozed() ) : ?>
87
+ <td>
88
+ <!-- Reset Deactivation Snoozing -->
89
+ <form action="" method="POST">
90
+ <input type="hidden" name="fs_action" value="reset_deactivation_snoozing">
91
+ <?php wp_nonce_field( 'reset_deactivation_snoozing' ) ?>
92
+ <button class="button"><?php fs_esc_html_echo_inline( 'Reset Deactivation Snoozing' ) ?> (Expires in <?php echo ( Freemius::deactivation_snooze_expires_at() - time() ) ?> sec)</button>
93
+ </form>
94
+ </td>
95
+ <?php endif ?>
96
  <td>
97
  <!-- Sync Data with Server -->
98
  <form action="" method="POST">
116
  <td>
117
  <button id="fs_set_db_option" class="button"><?php fs_esc_html_echo_inline( 'Set DB Option' ) ?></button>
118
  </td>
119
+ <td>
120
+ <?php
121
+ $fs_debug_page_url = 'admin.php?page=freemius&fs_action=allow_clone_resolution_notice';
122
+ $fs_debug_page_url = fs_is_network_admin() ?
123
+ network_admin_url( $fs_debug_page_url ) :
124
+ admin_url( $fs_debug_page_url );
125
+ ?>
126
+ <a href="<?php echo wp_nonce_url( $fs_debug_page_url, 'fs_allow_clone_resolution_notice' ) ?>" class="button button-primary">Resolve Clone(s)</a>
127
+ </td>
128
  </tr>
129
  </tbody>
130
  </table>
134
  var optionName = prompt('Please enter the option name:');
135
 
136
  if (optionName) {
137
+ $.post(<?php echo Freemius::ajax_url() ?>, {
138
  action : 'fs_get_db_option',
139
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
140
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_get_db_option' ) ); ?>,
155
  var optionValue = prompt('Please enter the option value:');
156
 
157
  if (optionValue) {
158
+ $.post(<?php echo Freemius::ajax_url() ?>, {
159
  action : 'fs_set_db_option',
160
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
161
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_set_db_option' ) ); ?>,
198
  'key' => 'WP_FS__DIR',
199
  'val' => WP_FS__DIR,
200
  ),
201
+ array(
202
+ 'key' => 'wp_using_ext_object_cache()',
203
+ 'val' => wp_using_ext_object_cache() ? 'true' : 'false',
204
+ ),
205
  )
206
  ?>
207
  <br>
256
  WP_FS__MODULE_TYPE_THEME
257
  );
258
  ?>
259
+ <?php $active_modules_by_id = array() ?>
260
  <?php foreach ( $module_types as $module_type ) : ?>
261
  <?php $modules = fs_get_entities( $fs_options->get_option( $module_type . 's' ), FS_Plugin::get_class_name() ) ?>
262
  <?php if ( is_array( $modules ) && count( $modules ) > 0 ) : ?>
272
  <th><?php fs_esc_html_echo_inline( 'Freemius State' ) ?></th>
273
  <th><?php fs_esc_html_echo_inline( 'Module Path' ) ?></th>
274
  <th><?php fs_esc_html_echo_inline( 'Public Key' ) ?></th>
275
+ <?php if ( $is_multisite ) : ?>
276
  <th><?php fs_esc_html_echo_inline( 'Network Blog' ) ?></th>
277
  <th><?php fs_esc_html_echo_inline( 'Network User' ) ?></th>
278
  <?php endif ?>
295
  }
296
  }
297
  ?>
298
+ <?php
299
+ $fs = null;
300
+ if ( $is_active ) {
301
+ $fs = freemius( $data->id );
302
+
303
+ $active_modules_by_id[ $data->id ] = true;
304
+ }
305
+ ?>
306
  <tr<?php if ( $is_active ) {
307
  if ( $fs->has_api_connectivity() && $fs->is_on() ) {
308
  echo ' style="background: #E6FFE6; font-weight: bold"';
332
  } ?></td>
333
  <td><?php echo $data->file ?></td>
334
  <td><?php echo $data->public_key ?></td>
335
+ <?php if ( $is_multisite ) : ?>
336
  <?php
337
  $network_blog_id = null;
338
  $network_user = null;
386
  */
387
  $sites_map = $VARS[ $module_type . '_sites' ];
388
 
389
+ $all_plans = false;
 
390
  ?>
391
  <?php if ( is_array( $sites_map ) && count( $sites_map ) > 0 ) : ?>
392
  <h2><?php echo esc_html( sprintf(
412
  </tr>
413
  </thead>
414
  <tbody>
415
+ <?php $site_url = null ?>
416
  <?php foreach ( $sites_map as $slug => $sites ) : ?>
 
 
 
417
  <?php foreach ( $sites as $site ) : ?>
418
+ <?php
419
+ $blog_id = $is_multisite ?
420
+ $site->blog_id :
421
+ null;
422
+
423
+ if ( is_null( $site_url ) || $is_multisite ) {
424
+ $site_url = Freemius::get_unfiltered_site_url(
425
+ $blog_id,
426
+ true,
427
+ true
428
+ );
429
+ }
430
+
431
+ $is_active_clone = ( $site->is_clone( $site_url ) && isset( $active_modules_by_id[ $site->plugin_id ] ) );
432
+
433
+ if ( $is_active_clone ) {
434
+ $has_any_active_clone = true;
435
+ }
436
+ ?>
437
  <tr>
438
+ <td>
439
+ <?php echo $site->id ?>
440
+ <?php if ( $is_active_clone ) : ?>
441
+ <label class="fs-tag fs-warn">Clone</label>
442
+ <?php endif ?>
443
+ </td>
444
  <?php if ( $is_multisite ) : ?>
445
+ <td><?php echo $blog_id ?></td>
446
  <td><?php echo fs_strip_url_protocol( $site->url ) ?></td>
447
  <?php endif ?>
448
  <td><?php echo $slug ?></td>
539
  * @var FS_User[] $users
540
  */
541
  $users = $VARS['users'];
542
+ $user_ids_map = array();
543
  $users_with_developer_license_by_id = array();
544
 
545
+ if ( is_array( $users ) && ! empty( $users ) ) {
546
+ foreach ( $users as $user ) {
547
+ $user_ids_map[ $user->id ] = true;
548
+ }
549
+ }
550
+
551
  foreach ( $module_types as $module_type ) {
552
  /**
553
  * @var FS_Plugin_License[] $licenses
640
  <td><?php echo $license->is_block_features ? 'Blocking' : 'Flexible' ?></td>
641
  <td><?php echo $license->is_whitelabeled ? 'Whitelabeled' : 'Normal' ?></td>
642
  <td><?php
643
+ echo ( $license->is_whitelabeled || ! isset( $user_ids_map[ $license->user_id ] ) ) ?
644
  $license->get_html_escaped_masked_secret_key() :
645
  esc_html( $license->secret_key );
646
  ?></td>
788
  offset = 0;
789
  }
790
 
791
+ $.post(<?php echo Freemius::ajax_url() ?>, {
792
  action : 'fs_get_debug_log',
793
  // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
794
  _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_get_debug_log' ) ); ?>,
freemius/templates/firewall-issues-js.php CHANGED
@@ -48,8 +48,7 @@
48
 
49
  $( this ).css({'cursor': 'wait'});
50
 
51
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
52
- $.post( ajaxurl, data, function( response ) {
53
  if ( 1 == response ) {
54
  // Refresh page on success.
55
  location.reload();
48
 
49
  $( this ).css({'cursor': 'wait'});
50
 
51
+ $.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) {
 
52
  if ( 1 == response ) {
53
  // Refresh page on success.
54
  location.reload();
freemius/templates/forms/affiliation.php CHANGED
@@ -13,8 +13,10 @@
13
  /**
14
  * @var array $VARS
15
  * @var Freemius $fs
 
16
  */
17
- $fs = freemius( $VARS['id'] );
 
18
 
19
  $slug = $fs->get_slug();
20
 
@@ -22,7 +24,6 @@
22
  $affiliate = $fs->get_affiliate();
23
  $affiliate_terms = $fs->get_affiliate_terms();
24
 
25
- $plugin_title = $fs->get_plugin_title();
26
  $module_type = $fs->is_plugin() ?
27
  WP_FS__MODULE_TYPE_PLUGIN :
28
  WP_FS__MODULE_TYPE_THEME;
@@ -45,7 +46,7 @@
45
  $promotion_method_mobile_apps = false;
46
  $statistics_information = false;
47
  $promotion_method_description = false;
48
- $members_dashboard_login_url = 'https://members.freemius.com/login/';
49
 
50
  $affiliate_application_data = $fs->get_affiliate_application_data();
51
 
@@ -71,7 +72,7 @@
71
  $current_user = Freemius::_get_current_wp_user();
72
  $full_name = trim( $current_user->user_firstname . ' ' . $current_user->user_lastname );
73
  $email_address = $current_user->user_email;
74
- $domain = fs_strip_url_protocol( get_site_url() );
75
  }
76
 
77
  $affiliate_tracking = 30;
@@ -365,7 +366,7 @@
365
  }
366
 
367
  $.ajax({
368
- url : ajaxurl,
369
  method : 'POST',
370
  data : {
371
  action : '<?php echo $fs->get_ajax_action( 'submit_affiliate_application' ) ?>',
@@ -506,4 +507,3 @@
506
  'module_version' => $fs->get_plugin_version(),
507
  );
508
  fs_require_template( 'powered-by.php', $params );
509
- ?>
13
  /**
14
  * @var array $VARS
15
  * @var Freemius $fs
16
+ * @var string $plugin_title
17
  */
18
+ $fs = freemius( $VARS['id'] );
19
+ $plugin_title = $VARS['plugin_title'];
20
 
21
  $slug = $fs->get_slug();
22
 
24
  $affiliate = $fs->get_affiliate();
25
  $affiliate_terms = $fs->get_affiliate_terms();
26
 
 
27
  $module_type = $fs->is_plugin() ?
28
  WP_FS__MODULE_TYPE_PLUGIN :
29
  WP_FS__MODULE_TYPE_THEME;
46
  $promotion_method_mobile_apps = false;
47
  $statistics_information = false;
48
  $promotion_method_description = false;
49
+ $members_dashboard_login_url = 'https://users.freemius.com/login';
50
 
51
  $affiliate_application_data = $fs->get_affiliate_application_data();
52
 
72
  $current_user = Freemius::_get_current_wp_user();
73
  $full_name = trim( $current_user->user_firstname . ' ' . $current_user->user_lastname );
74
  $email_address = $current_user->user_email;
75
+ $domain = Freemius::get_unfiltered_site_url( null, true );
76
  }
77
 
78
  $affiliate_tracking = 30;
366
  }
367
 
368
  $.ajax({
369
+ url : <?php echo Freemius::ajax_url() ?>,
370
  method : 'POST',
371
  data : {
372
  action : '<?php echo $fs->get_ajax_action( 'submit_affiliate_application' ) ?>',
507
  'module_version' => $fs->get_plugin_version(),
508
  );
509
  fs_require_template( 'powered-by.php', $params );
 
freemius/templates/forms/data-debug-mode.php CHANGED
@@ -140,7 +140,7 @@ HTML;
140
  };
141
 
142
  $.ajax( {
143
- url : ajaxurl,
144
  method : 'POST',
145
  data : data,
146
  beforeSend: function () {
140
  };
141
 
142
  $.ajax( {
143
+ url : <?php echo Freemius::ajax_url() ?>,
144
  method : 'POST',
145
  data : data,
146
  beforeSend: function () {
freemius/templates/forms/deactivation/form.php CHANGED
@@ -24,6 +24,7 @@
24
  $anonymous_feedback_checkbox_html = '';
25
 
26
  $reasons_list_items_html = '';
 
27
 
28
  if ( $show_deactivation_feedback_form ) {
29
  $reasons = $VARS['reasons'];
@@ -64,6 +65,41 @@ HTML;
64
  fs_esc_html_inline( 'Anonymous feedback', 'anonymous-feedback', $slug )
65
  );
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  // Aliases.
@@ -71,6 +107,13 @@ HTML;
71
  $theme_text = fs_text_inline( 'Theme', 'theme', $slug );
72
  $activate_x_text = fs_text_inline( 'Activate %s', 'activate-x', $slug );
73
 
 
 
 
 
 
 
 
74
  fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
75
 
76
  if ( ! empty( $subscription_cancellation_dialog_box_template_params ) ) {
@@ -92,6 +135,7 @@ HTML;
92
  + ' </div>'
93
  + ' <div class="fs-modal-footer">'
94
  + ' <?php echo $anonymous_feedback_checkbox_html ?>'
 
95
  + ' <a href="#" class="button button-secondary button-deactivate"></a>'
96
  + ' <a href="#" class="button button-secondary button-close"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></a>'
97
  + ' </div>'
@@ -101,6 +145,7 @@ HTML;
101
  selectedReasonID = false,
102
  redirectLink = '',
103
  $anonymousFeedback = $modal.find( '.anonymous-feedback-label' ),
 
104
  isAnonymous = <?php echo ( $is_anonymous ? 'true' : 'false' ); ?>,
105
  otherReasonID = <?php echo Freemius::REASON_OTHER; ?>,
106
  dontShareDataReasonID = <?php echo Freemius::REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION; ?>,
@@ -135,7 +180,7 @@ HTML;
135
  ?>
136
 
137
  $.ajax({
138
- url : ajaxurl,
139
  method : 'POST',
140
  data : {
141
  action : '<?php echo $fs->get_ajax_action( 'cancel_subscription_or_trial' ) ?>',
@@ -230,10 +275,6 @@ HTML;
230
  } ?>
231
 
232
  $modal.on('input propertychange', '.reason-input input', function () {
233
- if (!isOtherReasonSelected()) {
234
- return;
235
- }
236
-
237
  var reason = $(this).val().trim();
238
 
239
  /**
@@ -241,9 +282,12 @@ HTML;
241
  * to change the message color back to default.
242
  */
243
  if (reason.length > 0) {
244
- $('.message').removeClass('error-message');
245
- enableDeactivateButton();
246
- }
 
 
 
247
  });
248
 
249
  $modal.on('blur', '.reason-input input', function () {
@@ -260,8 +304,8 @@ HTML;
260
  */
261
  if (0 === $userReason.val().trim().length) {
262
  $('.message').addClass('error-message');
263
- disableDeactivateButton();
264
- }
265
  }, 150);
266
  });
267
 
@@ -276,15 +320,34 @@ HTML;
276
  var _this = $(this);
277
 
278
  if (_this.hasClass('allow-deactivate')) {
279
- var $radio = $modal.find('input[type="radio"]:checked');
 
 
 
 
 
 
 
280
 
281
- if (0 === $radio.length) {
 
 
 
 
 
 
 
 
 
 
 
 
282
  if ( ! deleteThemeUpdateData ) {
283
  // If no selected reason, just deactivate the plugin.
284
  window.location.href = redirectLink;
285
  } else {
286
  $.ajax({
287
- url : ajaxurl,
288
  method : 'POST',
289
  data : {
290
  action : '<?php echo $fs->get_ajax_action( 'delete_theme_update_data' ) ?>',
@@ -292,8 +355,7 @@ HTML;
292
  module_id: '<?php echo $fs->get_id() ?>'
293
  },
294
  beforeSend: function() {
295
- _parent.find( '.fs-modal-footer .button' ).addClass( 'disabled' );
296
- _parent.find( '.fs-modal-footer .button-secondary' ).text( 'Processing...' );
297
  },
298
  complete : function() {
299
  window.location.href = redirectLink;
@@ -304,28 +366,27 @@ HTML;
304
  return;
305
  }
306
 
307
- var $selected_reason = $radio.parents('li:first'),
308
- $input = $selected_reason.find('textarea, input[type="text"]'),
309
- userReason = ( 0 !== $input.length ) ? $input.val().trim() : '';
310
 
311
- if (isOtherReasonSelected() && ( '' === userReason )) {
312
- return;
313
- }
314
 
315
  $.ajax({
316
- url : ajaxurl,
317
  method : 'POST',
318
  data : {
319
- action : '<?php echo $fs->get_ajax_action( 'submit_uninstall_reason' ) ?>',
320
- security : '<?php echo $fs->get_ajax_security( 'submit_uninstall_reason' ) ?>',
321
- module_id : '<?php echo $fs->get_id() ?>',
322
- reason_id : $radio.val(),
323
- reason_info : userReason,
324
- is_anonymous: isAnonymousFeedback()
 
325
  },
326
  beforeSend: function () {
327
- _parent.find('.fs-modal-footer .button').addClass('disabled');
328
- _parent.find('.fs-modal-footer .button-secondary').text('Processing...');
329
  },
330
  complete : function () {
331
  // Do not show the dialog box, deactivate the plugin.
@@ -365,20 +426,17 @@ HTML;
365
 
366
  $modal.find('.reason-input').remove();
367
  $modal.find( '.internal-message' ).hide();
368
- $modal.find('.button-deactivate').html('<?php echo esc_js( sprintf(
369
- fs_text_inline( 'Submit & %s', 'deactivation-modal-button-submit' , $slug ),
370
- $fs->is_plugin() ?
371
- $deactivate_text :
372
- sprintf( $activate_x_text, $theme_text )
373
- ) ) ?>');
374
-
375
- enableDeactivateButton();
376
 
377
  if ( _parent.hasClass( 'has-internal-message' ) ) {
378
  _parent.find( '.internal-message' ).show();
379
  }
380
 
381
- if (_parent.hasClass('has-input')) {
 
 
 
 
382
  var inputType = _parent.data('input-type'),
383
  inputPlaceholder = _parent.data('input-placeholder'),
384
  reasonInputHtml = '<div class="reason-input"><span class="message"></span>' + ( ( 'textfield' === inputType ) ? '<input type="text" maxlength="128" />' : '<textarea rows="5" maxlength="128"></textarea>' ) + '</div>';
@@ -388,11 +446,60 @@ HTML;
388
 
389
  if (isOtherReasonSelected()) {
390
  showMessage('<?php echo esc_js( fs_text_inline( 'Kindly tell us the reason so we can improve.', 'ask-for-reason-message' , $slug ) ); ?>');
391
- disableDeactivateButton();
392
- }
393
  }
 
 
 
 
 
 
 
394
  });
395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  // If the user has clicked outside the window, cancel it.
397
  $modal.on('click', function (evt) {
398
  var $target = $(evt.target);
@@ -453,8 +560,6 @@ HTML;
453
  function resetModal() {
454
  selectedReasonID = false;
455
 
456
- enableDeactivateButton();
457
-
458
  // Uncheck all radio buttons.
459
  $modal.find('input[type="radio"]').prop('checked', false);
460
 
@@ -463,8 +568,8 @@ HTML;
463
 
464
  $modal.find('.message').hide();
465
 
466
- if ( isAnonymous ) {
467
- $anonymousFeedback.find( 'input' ).prop( 'checked', false );
468
 
469
  // Hide, since by default there is no selected reason.
470
  $anonymousFeedback.hide();
@@ -491,13 +596,31 @@ HTML;
491
  $modal.find('.message').text(message).show();
492
  }
493
 
494
- function enableDeactivateButton() {
495
- $modal.find('.button-deactivate').removeClass('disabled');
496
- }
 
 
 
 
 
 
497
 
498
- function disableDeactivateButton() {
499
- $modal.find('.button-deactivate').addClass('disabled');
500
- }
 
 
 
 
 
 
 
 
 
 
 
 
501
 
502
  function showPanel(panelType) {
503
  $modal.find( '.fs-modal-panel' ).removeClass( 'active' );
24
  $anonymous_feedback_checkbox_html = '';
25
 
26
  $reasons_list_items_html = '';
27
+ $snooze_select_html = '';
28
 
29
  if ( $show_deactivation_feedback_form ) {
30
  $reasons = $VARS['reasons'];
65
  fs_esc_html_inline( 'Anonymous feedback', 'anonymous-feedback', $slug )
66
  );
67
  }
68
+
69
+ $snooze_periods = array(
70
+ array(
71
+ 'increment' => fs_text_inline( 'hour', $slug ),
72
+ 'quantity' => number_format_i18n(1),
73
+ 'value' => 6 * WP_FS__TIME_10_MIN_IN_SEC,
74
+ ),
75
+ array(
76
+ 'increment' => fs_text_inline( 'hours', $slug ),
77
+ 'quantity' => number_format_i18n(24),
78
+ 'value' => WP_FS__TIME_24_HOURS_IN_SEC,
79
+ ),
80
+ array(
81
+ 'increment' => fs_text_inline( 'days', $slug ),
82
+ 'quantity' => number_format_i18n(7),
83
+ 'value' => WP_FS__TIME_WEEK_IN_SEC,
84
+ ),
85
+ array(
86
+ 'increment' => fs_text_inline( 'days', $slug ),
87
+ 'quantity' => number_format_i18n(30),
88
+ 'value' => 30 * WP_FS__TIME_24_HOURS_IN_SEC,
89
+ ),
90
+ );
91
+
92
+ $snooze_select_html = '<select>';
93
+ foreach ($snooze_periods as $period) {
94
+ $snooze_select_html .= sprintf(
95
+ '<option value="%s">%s %s</option>',
96
+ $period['value'],
97
+ $period['quantity'],
98
+ $period['increment']
99
+ );
100
+ }
101
+
102
+ $snooze_select_html .= '</select>';
103
  }
104
 
105
  // Aliases.
107
  $theme_text = fs_text_inline( 'Theme', 'theme', $slug );
108
  $activate_x_text = fs_text_inline( 'Activate %s', 'activate-x', $slug );
109
 
110
+ $submit_deactivate_text = sprintf(
111
+ fs_text_inline( 'Submit & %s', 'deactivation-modal-button-submit', $slug ),
112
+ $fs->is_plugin() ?
113
+ $deactivate_text :
114
+ sprintf( $activate_x_text, $theme_text )
115
+ );
116
+
117
  fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
118
 
119
  if ( ! empty( $subscription_cancellation_dialog_box_template_params ) ) {
135
  + ' </div>'
136
  + ' <div class="fs-modal-footer">'
137
  + ' <?php echo $anonymous_feedback_checkbox_html ?>'
138
+ + ' <label style="display: none" class="feedback-from-snooze-label"><input type="checkbox" class="feedback-from-snooze-checkbox"> <span><?php fs_esc_js_echo_inline( 'Snooze this panel during troubleshooting', 'snooze-panel-during-troubleshooting', $slug ) ?></span><span style="display: none"><?php fs_esc_js_echo_inline( 'Snooze this panel for', 'snooze-panel-for', $slug ) ?> <?php echo $snooze_select_html ?></span></label>'
139
  + ' <a href="#" class="button button-secondary button-deactivate"></a>'
140
  + ' <a href="#" class="button button-secondary button-close"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></a>'
141
  + ' </div>'
145
  selectedReasonID = false,
146
  redirectLink = '',
147
  $anonymousFeedback = $modal.find( '.anonymous-feedback-label' ),
148
+ $feedbackSnooze = $modal.find( '.feedback-from-snooze-label' ),
149
  isAnonymous = <?php echo ( $is_anonymous ? 'true' : 'false' ); ?>,
150
  otherReasonID = <?php echo Freemius::REASON_OTHER; ?>,
151
  dontShareDataReasonID = <?php echo Freemius::REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION; ?>,
180
  ?>
181
 
182
  $.ajax({
183
+ url : <?php echo Freemius::ajax_url() ?>,
184
  method : 'POST',
185
  data : {
186
  action : '<?php echo $fs->get_ajax_action( 'cancel_subscription_or_trial' ) ?>',
275
  } ?>
276
 
277
  $modal.on('input propertychange', '.reason-input input', function () {
 
 
 
 
278
  var reason = $(this).val().trim();
279
 
280
  /**
282
  * to change the message color back to default.
283
  */
284
  if (reason.length > 0) {
285
+ $('.message').removeClass('error-message');
286
+ }
287
+
288
+ toggleDeactivationButtonPrimary( reason.length > 0 );
289
+
290
+ changeDeactivateButtonText();
291
  });
292
 
293
  $modal.on('blur', '.reason-input input', function () {
304
  */
305
  if (0 === $userReason.val().trim().length) {
306
  $('.message').addClass('error-message');
307
+ changeDeactivateButtonText();
308
+ }
309
  }, 150);
310
  });
311
 
320
  var _this = $(this);
321
 
322
  if (_this.hasClass('allow-deactivate')) {
323
+ var
324
+ $radio = $modal.find('input[type="radio"]:checked'),
325
+ isReasonSelected = (0 < $radio.length),
326
+ userReason = '';
327
+
328
+ if ( isReasonSelected ) {
329
+ var $selectedReason = $radio.parents('li:first'),
330
+ $reasonInput = $selectedReason.find('textarea, input[type="text"]');
331
 
332
+ if ( 0 < $reasonInput.length ) {
333
+ userReason = $reasonInput.val().trim();
334
+ }
335
+ }
336
+
337
+ if ( otherReasonID == selectedReasonID && '' === userReason ) {
338
+ // If the 'Other' is selected and a reason is not provided (aka it's empty), treat it as if a reason wasn't selected at all.
339
+ isReasonSelected = false;
340
+ }
341
+
342
+ _parent.find( '.fs-modal-footer .button' ).addClass( 'disabled' );
343
+
344
+ if ( ! isReasonSelected ) {
345
  if ( ! deleteThemeUpdateData ) {
346
  // If no selected reason, just deactivate the plugin.
347
  window.location.href = redirectLink;
348
  } else {
349
  $.ajax({
350
+ url : <?php echo Freemius::ajax_url() ?>,
351
  method : 'POST',
352
  data : {
353
  action : '<?php echo $fs->get_ajax_action( 'delete_theme_update_data' ) ?>',
355
  module_id: '<?php echo $fs->get_id() ?>'
356
  },
357
  beforeSend: function() {
358
+ _parent.find( '.fs-modal-footer .button-deactivate' ).text( '<?php echo esc_js( fs_text_inline( 'Processing', 'processing', $slug ) ) ?>...' );
 
359
  },
360
  complete : function() {
361
  window.location.href = redirectLink;
366
  return;
367
  }
368
 
369
+ var snoozePeriod = 0,
370
+ shouldSnooze = $feedbackSnooze.find( '.feedback-from-snooze-checkbox' ).is( ':checked' );
 
371
 
372
+ if ( shouldSnooze && <?php echo Freemius::REASON_TEMPORARY_DEACTIVATION ?> == selectedReasonID ) {
373
+ snoozePeriod = parseInt($feedbackSnooze.find('select').val(), 10);
374
+ }
375
 
376
  $.ajax({
377
+ url : <?php echo Freemius::ajax_url() ?>,
378
  method : 'POST',
379
  data : {
380
+ action : '<?php echo $fs->get_ajax_action( 'submit_uninstall_reason' ) ?>',
381
+ security : '<?php echo $fs->get_ajax_security( 'submit_uninstall_reason' ) ?>',
382
+ module_id : '<?php echo $fs->get_id() ?>',
383
+ reason_id : $radio.val(),
384
+ reason_info : userReason,
385
+ is_anonymous : isAnonymousFeedback(),
386
+ snooze_period: snoozePeriod
387
  },
388
  beforeSend: function () {
389
+ _parent.find('.fs-modal-footer .button-deactivate').text('<?php echo esc_js( fs_text_inline( 'Processing', 'processing', $slug ) ) ?>...');
 
390
  },
391
  complete : function () {
392
  // Do not show the dialog box, deactivate the plugin.
426
 
427
  $modal.find('.reason-input').remove();
428
  $modal.find( '.internal-message' ).hide();
429
+ $modal.find('.button-deactivate').html('<?php echo esc_js( $submit_deactivate_text ) ?>');
 
 
 
 
 
 
 
430
 
431
  if ( _parent.hasClass( 'has-internal-message' ) ) {
432
  _parent.find( '.internal-message' ).show();
433
  }
434
 
435
+ if ( ! _parent.hasClass('has-input') ) {
436
+ toggleDeactivationButtonPrimary( true );
437
+ } else {
438
+ toggleDeactivationButtonPrimary( false );
439
+
440
  var inputType = _parent.data('input-type'),
441
  inputPlaceholder = _parent.data('input-placeholder'),
442
  reasonInputHtml = '<div class="reason-input"><span class="message"></span>' + ( ( 'textfield' === inputType ) ? '<input type="text" maxlength="128" />' : '<textarea rows="5" maxlength="128"></textarea>' ) + '</div>';
446
 
447
  if (isOtherReasonSelected()) {
448
  showMessage('<?php echo esc_js( fs_text_inline( 'Kindly tell us the reason so we can improve.', 'ask-for-reason-message' , $slug ) ); ?>');
449
+ changeDeactivateButtonText();
450
+ }
451
  }
452
+
453
+ $anonymousFeedback.toggle( <?php echo Freemius::REASON_TEMPORARY_DEACTIVATION ?> != selectedReasonID );
454
+ $feedbackSnooze.toggle( <?php echo Freemius::REASON_TEMPORARY_DEACTIVATION ?> == selectedReasonID );
455
+
456
+ if ( <?php echo Freemius::REASON_TEMPORARY_DEACTIVATION ?> == selectedReasonID ) {
457
+ updateDeactivationButtonOnTrouble();
458
+ }
459
  });
460
 
461
+ var toggleDeactivationButtonPrimary = function ( isPrimary ) {
462
+ if ( isPrimary ) {
463
+ $modal.find('.button-deactivate')
464
+ .removeClass( 'button-secondary' )
465
+ .addClass( 'button-primary' );
466
+ } else {
467
+ $modal.find('.button-deactivate')
468
+ .addClass( 'button-secondary' )
469
+ .removeClass( 'button-primary' );
470
+ }
471
+ };
472
+
473
+ var snooze = false;
474
+
475
+ var updateDeactivationButtonOnTrouble = function () {
476
+ if ( snooze ) {
477
+ $modal.find('.button-deactivate').html('<?php echo esc_js( sprintf(
478
+ fs_text_inline( 'Snooze & %s', 'snooze-modal-button-submit' , $slug ),
479
+ $fs->is_plugin() ?
480
+ $deactivate_text :
481
+ sprintf( $activate_x_text, $theme_text )
482
+ ) ) ?>');
483
+ } else {
484
+ $modal.find('.button-deactivate').html('<?php echo esc_js(
485
+ $fs->is_plugin() ?
486
+ $deactivate_text :
487
+ sprintf( $activate_x_text, $theme_text )
488
+ ) ?>');
489
+ }
490
+ };
491
+
492
+ $feedbackSnooze.on( 'click', 'input', function () {
493
+ var $spans = $feedbackSnooze.find( 'span' );
494
+
495
+ snooze = ( ! snooze );
496
+
497
+ $( $spans[0] ).toggle();
498
+ $( $spans[1] ).toggle();
499
+
500
+ updateDeactivationButtonOnTrouble();
501
+ });
502
+
503
  // If the user has clicked outside the window, cancel it.
504
  $modal.on('click', function (evt) {
505
  var $target = $(evt.target);
560
  function resetModal() {
561
  selectedReasonID = false;
562
 
 
 
563
  // Uncheck all radio buttons.
564
  $modal.find('input[type="radio"]').prop('checked', false);
565
 
568
 
569
  $modal.find('.message').hide();
570
 
571
+ if ( isAnonymous ) {
572
+ $anonymousFeedback.find( 'input' ).prop( 'checked', <?php echo $fs->apply_filters( 'default_to_anonymous_feedback', false ) ? 'true' : 'false' ?> );
573
 
574
  // Hide, since by default there is no selected reason.
575
  $anonymousFeedback.hide();
596
  $modal.find('.message').text(message).show();
597
  }
598
 
599
+ /**
600
+ * @author Xiaheng Chen (@xhchen)
601
+ *
602
+ * @since 2.4.2
603
+ */
604
+ function changeDeactivateButtonText() {
605
+ if ( ! isOtherReasonSelected()) {
606
+ return;
607
+ }
608
 
609
+ var
610
+ $userReason = $modal.find('.reason-input input'),
611
+ $deactivateButton = $modal.find('.button-deactivate');
612
+
613
+ if (0 === $userReason.val().trim().length) {
614
+ // If the reason is empty, just change the text to 'Deactivate' (plugin) or 'Activate themeX' (theme).
615
+ $deactivateButton.html('<?php echo
616
+ $fs->is_plugin() ?
617
+ $deactivate_text :
618
+ sprintf( $activate_x_text, $theme_text )
619
+ ?>');
620
+ } else {
621
+ $deactivateButton.html('<?php echo esc_js( $submit_deactivate_text ) ?>');
622
+ }
623
+ }
624
 
625
  function showPanel(panelType) {
626
  $modal.find( '.fs-modal-panel' ).removeClass( 'active' );
freemius/templates/forms/email-address-update.php ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ *
7
+ * @author Leo Fajardo (@leorw)
8
+ * @since 2.5.0
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
+
15
+ /**
16
+ * @var array $VARS
17
+ */
18
+ $fs = freemius( $VARS['id'] );
19
+ $slug = $fs->get_slug();
20
+
21
+ $user = $fs->get_user();
22
+ $current_email_address = $user->email;
23
+
24
+ fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
25
+ ?>
26
+ <script type="text/javascript">
27
+ ( function ( $ ) {
28
+ var modalHtml =
29
+ '<div class="fs-modal fs-modal-email-address-update">'
30
+ + ' <div class="fs-modal-dialog">'
31
+ + ' <div class="fs-modal-header">'
32
+ + ' <h4><?php fs_esc_attr_echo_inline( 'Email address update', 'email-address-update', $slug ) ?></h4>'
33
+ + ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'close window', 'dismiss', $slug ) ) ?>"></i></a>'
34
+ + ' </div>'
35
+ + ' <div class="fs-modal-body">'
36
+ + ' <div class="fs-modal-panel active">'
37
+ + ' <div class="notice notice-error inline fs-update-error-message"><p></p></div>'
38
+ + ' <p><?php fs_echo_inline( 'Enter the new email address', 'enter-new-email-address' , $slug ) ?>:</p>'
39
+ + ' <input type="text" class="fs-new-email-address-input" />'
40
+ + ' <div class="fs-email-addresses-ownership-options" style="display: none">'
41
+ + ' <p><?php echo sprintf(
42
+ fs_esc_html_inline( 'Are both %s and %s your email addresses?', 'email-addresses-ownership-confirmation' , $slug ),
43
+ sprintf( '<strong>%s</strong>', $current_email_address ),
44
+ '<strong class="fs-new-email-address"></strong>'
45
+ ) ?></p>'
46
+ + ' <ul>'
47
+ + ' <li>'
48
+ + ' <label>'
49
+ + ' <span><input type="radio" name="email-addresses-ownership" value="both"/></span>'
50
+ + ' <span><?php fs_echo_inline( 'Yes - both addresses are mine', 'both-addresses-are-mine', $slug ); ?></span>'
51
+ + ' </label>'
52
+ + ' </li>'
53
+ + ' <li>'
54
+ + ' <label>'
55
+ + ' <span><input type="radio" name="email-addresses-ownership" value="current"/></span>'
56
+ + ' <div><?php echo sprintf(
57
+ fs_esc_html_inline( "%s is my client's email address", 'client-email-address-confirmation', $slug ),
58
+ '<strong class="fs-new-email-address"></strong>'
59
+ ) ?></span>'
60
+ + ' </label>'
61
+ + ' </li>'
62
+ + ' <li>'
63
+ + ' <label>'
64
+ + ' <span><input type="radio" name="email-addresses-ownership" value="new"/></span>'
65
+ + ' <div><?php echo sprintf(
66
+ fs_esc_html_inline( "%s is my email address", 'email-address-ownership-confirmation', $slug ),
67
+ '<strong class="fs-new-email-address"></strong>'
68
+ ) ?></span>'
69
+ + ' </label>'
70
+ + ' </li>'
71
+ + ' </ul>'
72
+ + ' </div>'
73
+ + ' <div class="fs-assets-transfership-options" style="display: none">'
74
+ + ' <p><?php echo sprintf(
75
+ fs_esc_html_inline( 'Would you like to merge %s into %s?', 'accounts-merge-confirmation' , $slug ),
76
+ sprintf( '<strong>%s</strong>', $current_email_address ),
77
+ '<strong class="fs-new-email-address"></strong>'
78
+ ) ?></p>'
79
+ + ' <ul>'
80
+ + ' <li>'
81
+ + ' <label>'
82
+ + ' <span><input type="radio" name="assets-transfer-type" value="all" /></span>'
83
+ + ' <span><?php echo sprintf(
84
+ fs_esc_html_inline( 'Yes - move all my data and assets from %s to %s', 'move-all-data-and-assets-into-new-account', $slug ),
85
+ sprintf( '<strong>%s</strong>', $current_email_address ),
86
+ '<strong class="fs-new-email-address"></strong>'
87
+ ) ?></span>'
88
+ + ' </label>'
89
+ + ' </li>'
90
+ + ' <li>'
91
+ + ' <label>'
92
+ + ' <span><input type="radio" name="assets-transfer-type" value="plugin" /></span>'
93
+ + ' <span><?php echo sprintf(
94
+ fs_esc_html_inline( "No - only move this site's data to %s", 'move-only-plugin-data-into-new-account', $slug ),
95
+ '<strong class="fs-new-email-address"></strong>'
96
+ ) ?></span>'
97
+ + ' </label>'
98
+ + ' </li>'
99
+ + ' </ul>'
100
+ + ' </div>'
101
+ + ' </div>'
102
+ + ' </div>'
103
+ + ' <div class="fs-modal-footer">'
104
+ + ' <button class="button button-primary button-update" disabled><?php fs_esc_js_echo_inline( 'Update', 'update-email-address', $slug ) ?></button>'
105
+ + ' <button class="button button-secondary button-close"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'
106
+ + ' </div>'
107
+ + ' </div>'
108
+ + '</div>',
109
+ $modal = $( modalHtml ),
110
+ $updateButton = $modal.find( '.button-update' ),
111
+ $updateResultMessage = $modal.find( '.fs-update-error-message' ),
112
+ selectedEmailAddressesOwnershipOption = null,
113
+ selectedAssetsTransfershipOption = null,
114
+ previousEmailAddress = '',
115
+ $body = $( 'body' );
116
+
117
+ $modal.appendTo( $body );
118
+
119
+ registerEventHandlers();
120
+
121
+ function registerEventHandlers() {
122
+ $body.on( 'click', '#fs_account_details .button-edit-email-address', function ( evt ) {
123
+ evt.preventDefault();
124
+
125
+ showModal( evt );
126
+ } );
127
+
128
+ $modal.on( 'input propertychange keyup paste delete cut', '.fs-new-email-address-input', function () {
129
+ var emailAddress = $( this ).val().trim();
130
+
131
+ if ( emailAddress === previousEmailAddress ) {
132
+ return;
133
+ }
134
+
135
+ var isValidEmailAddressInput = isValidEmailAddress( emailAddress );
136
+
137
+ toggleOptions( isValidEmailAddressInput );
138
+
139
+ if ( ! isValidEmailAddressInput ) {
140
+ disableUpdateButton();
141
+ } else {
142
+ $modal.find( '.fs-new-email-address').text( emailAddress );
143
+
144
+ maybeEnableUpdateButton();
145
+ }
146
+
147
+ previousEmailAddress = emailAddress;
148
+ } );
149
+
150
+ $modal.on( 'blur', '.fs-new-email-address-input', function() {
151
+ var emailAddress = $( this ).val().trim(),
152
+ isValidEmailAddressInput = isValidEmailAddress( emailAddress );
153
+
154
+ toggleOptions( isValidEmailAddressInput );
155
+
156
+ if ( ! isValidEmailAddressInput ) {
157
+ disableUpdateButton();
158
+ }
159
+ } );
160
+
161
+ $modal.on( 'click', '.fs-close, .button-secondary', function () {
162
+ closeModal();
163
+ return false;
164
+ } );
165
+
166
+ $modal.on( 'click', '.fs-modal-footer .button-update', function ( evt ) {
167
+ if ( ! isValidEmailAddress( previousEmailAddress ) ) {
168
+ return;
169
+ }
170
+
171
+ if ( previousEmailAddress === '<?php echo $current_email_address ?>' ) {
172
+ closeModal();
173
+ return;
174
+ }
175
+
176
+ var transferType = 'transfer';
177
+
178
+ if ( 'current' === selectedEmailAddressesOwnershipOption ) {
179
+ transferType = 'transfer_to_client';
180
+ } else if (
181
+ 'both' === selectedEmailAddressesOwnershipOption &&
182
+ 'all' === selectedAssetsTransfershipOption
183
+ ) {
184
+ transferType = 'merge';
185
+ }
186
+
187
+ $.ajax( {
188
+ url : <?php echo Freemius::ajax_url() ?>,
189
+ method : 'POST',
190
+ data : {
191
+ action : '<?php echo $fs->get_ajax_action( 'update_email_address' ) ?>',
192
+ security : '<?php echo $fs->get_ajax_security( 'update_email_address' ) ?>',
193
+ module_id : '<?php echo $fs->get_id() ?>',
194
+ transfer_type: transferType,
195
+ email_address: previousEmailAddress
196
+ },
197
+ beforeSend: function () {
198
+ disableUpdateButton();
199
+
200
+ $updateButton.find( '.fs-modal-footer .button' ).prop( 'disabled', true );
201
+ $updateButton.text( 'Processing...' );
202
+ },
203
+ success : function( result ) {
204
+ if ( result.success ) {
205
+ // Redirect to the "Account" page.
206
+ window.location.reload();
207
+ } else {
208
+ if ('change_ownership' === result.error.code) {
209
+ window.location = result.error.url;
210
+ } else {
211
+ showError(result.error.message ? result.error.message : result.error);
212
+ resetUpdateButton();
213
+ }
214
+ }
215
+ },
216
+ error : function () {
217
+ showError( '<?php fs_esc_js_echo_inline( 'Unexpected error, try again in 5 minutes. If the error persists, please contact support.', 'unexpected-error', $slug ) ?>' );
218
+
219
+ resetUpdateButton();
220
+ }
221
+ } );
222
+ } );
223
+
224
+ $modal.on( 'click', 'input[type="radio"]', function () {
225
+ var $selectedOption = $( this ),
226
+ selectedOptionValue = $selectedOption.val();
227
+
228
+ // If the selection has not changed, do not proceed.
229
+ if (
230
+ selectedEmailAddressesOwnershipOption === selectedOptionValue ||
231
+ selectedAssetsTransfershipOption === selectedOptionValue
232
+ ) {
233
+ return;
234
+ }
235
+
236
+ if ( 'assets-transfer-type' === $selectedOption.attr( 'name' ) ) {
237
+ selectedAssetsTransfershipOption = selectedOptionValue;
238
+ } else {
239
+ selectedEmailAddressesOwnershipOption = selectedOptionValue;
240
+
241
+ if ( 'both' !== selectedEmailAddressesOwnershipOption ) {
242
+ $modal.find( '.fs-assets-transfership-options' ).hide();
243
+ } else {
244
+ $modal.find( '.fs-assets-transfership-options' ).show();
245
+ $modal.find( '.fs-assets-transfership-options input[type="radio"]' ).prop('checked', false);
246
+
247
+ selectedAssetsTransfershipOption = null;
248
+
249
+ disableUpdateButton();
250
+ }
251
+ }
252
+
253
+ if ( isValidEmailAddress( $( '.fs-new-email-address-input' ).val().trim() ) ) {
254
+ maybeEnableUpdateButton();
255
+ }
256
+ });
257
+ }
258
+
259
+ function showModal() {
260
+ resetModal();
261
+
262
+ // Display the dialog box.
263
+ $modal.addClass( 'active' );
264
+ $modal.find( '.fs-new-email-address-input' ).focus();
265
+
266
+ $( 'body' ).addClass( 'has-fs-modal' );
267
+ }
268
+
269
+ function closeModal() {
270
+ selectedEmailAddressesOwnershipOption = null;
271
+
272
+ disableUpdateButton();
273
+
274
+ $modal.removeClass( 'active' );
275
+
276
+ $( 'body' ).removeClass( 'has-fs-modal' );
277
+ }
278
+
279
+ function resetModal() {
280
+ hideError();
281
+
282
+ // Deselect all radio buttons.
283
+ $modal.find( 'input[type="radio"]' ).prop( 'checked', false );
284
+
285
+ // Clear the value of the email address text field.
286
+ $modal.find( 'input[type="text"]' ).val( '' );
287
+
288
+ toggleOptions( false );
289
+
290
+ disableUpdateButton();
291
+
292
+ $updateButton.text( <?php echo json_encode( fs_text_inline( 'Update', 'update-email-address', $slug ) ) ?> );
293
+ }
294
+
295
+ function resetUpdateButton() {
296
+ maybeEnableUpdateButton();
297
+
298
+ $updateButton.text( <?php echo json_encode( fs_text_inline( 'Update', 'update-email-address', $slug ) ) ?> );
299
+ }
300
+
301
+ function maybeEnableUpdateButton() {
302
+ if ( null === selectedEmailAddressesOwnershipOption ) {
303
+ return;
304
+ }
305
+
306
+ if (
307
+ 'both' === selectedEmailAddressesOwnershipOption &&
308
+ null === selectedAssetsTransfershipOption
309
+ ) {
310
+ return;
311
+ }
312
+
313
+ $updateButton.prop( 'disabled', false );
314
+ }
315
+
316
+ function disableUpdateButton() {
317
+ $updateButton.prop( 'disabled', true );
318
+ }
319
+
320
+ function hideError() {
321
+ $updateResultMessage.hide();
322
+ }
323
+
324
+ function showError( msg ) {
325
+ $updateResultMessage.find( ' > p' ).html( msg );
326
+ $updateResultMessage.show();
327
+ }
328
+
329
+ function isValidEmailAddress( emailAddress ) {
330
+ if ( '' === emailAddress ) {
331
+ return false;
332
+ }
333
+
334
+ return /[0-9a-zA-Z][a-zA-Z\+0-9\.\_\-]*@[0-9a-zA-Z\-]+(\.[a-zA-Z]{2,24}){1,3}/.test( emailAddress );
335
+ }
336
+
337
+ function toggleOptions( show ) {
338
+ $modal.find( '.fs-email-addresses-ownership-options' ).toggle( show );
339
+
340
+ if ( ! show ) {
341
+ $modal.find( '.fs-assets-transfership-options' ).hide();
342
+ } else if ( 'both' === selectedEmailAddressesOwnershipOption ) {
343
+ $modal.find( '.fs-assets-transfership-options' ).show();
344
+ }
345
+ }
346
+ } )( jQuery );
347
+ </script>
freemius/templates/forms/license-activation.php CHANGED
@@ -30,17 +30,10 @@
30
  if ( $fs->is_registered() ) {
31
  $activate_button_text = $header_title;
32
  } else {
33
- $freemius_site_url = $fs->has_paid_plan() ?
34
- 'https://freemius.com/' :
35
- // Insights platform information.
36
- $fs->get_usage_tracking_terms_url();
37
-
38
- $freemius_link = '<a href="' . $freemius_site_url . '" target="_blank" rel="noopener" tabindex="0">freemius.com</a>';
39
-
40
  $message_below_input_field = sprintf(
41
- fs_text_inline( 'The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license.', 'license-sync-disclaimer', $slug ),
42
  $fs->get_module_label( true ),
43
- $freemius_link
44
  );
45
 
46
  $activate_button_text = fs_text_inline( 'Agree & Activate License', 'agree-activate-license', $slug );
@@ -59,23 +52,51 @@
59
  if ( $is_network_activation ) {
60
  $all_sites = Freemius::get_sites();
61
 
 
 
 
62
  foreach ( $all_sites as $site ) {
63
  $site_details = $fs->get_site_info( $site );
64
 
 
 
 
 
65
  $blog_id = Freemius::get_site_blog_id( $site );
66
  $install = $fs->get_install_by_blog_id($blog_id);
67
 
68
- if ( is_object( $install ) && FS_Plugin_License::is_valid_id( $install->license_id ) ) {
69
- $site_details['license_id'] = $install->license_id;
70
- }
 
71
 
72
- $sites_details[] = $site_details;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
  if ( $is_network_activation ) {
76
  $vars = array(
77
  'id' => $fs->get_id(),
78
- 'sites' => $sites_details,
79
  'require_license_key' => true
80
  );
81
 
@@ -341,7 +362,7 @@ HTML;
341
  $activateLicenseButton.html( '<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait', $slug ) ?>...' );
342
 
343
  $.ajax( {
344
- url : ajaxurl,
345
  method : 'POST',
346
  data : {
347
  action : '<?php echo $fs->get_ajax_action( 'fetch_is_marketing_required_flag_value' ) ?>',
@@ -589,7 +610,6 @@ HTML;
589
  url : $this.find( '.url' ).val(),
590
  title : $this.find( '.title' ).val(),
591
  language: $this.find( '.language' ).val(),
592
- charset : $this.find( '.charset' ).val(),
593
  blog_id : $this.find( '.blog-id' ).find( 'span' ).text()
594
  };
595
 
@@ -607,7 +627,7 @@ HTML;
607
  }
608
 
609
  $.ajax({
610
- url: ajaxurl,
611
  method: 'POST',
612
  data: data,
613
  beforeSend: function () {
@@ -867,4 +887,4 @@ HTML;
867
  }
868
  });
869
  })( jQuery );
870
- </script>
30
  if ( $fs->is_registered() ) {
31
  $activate_button_text = $header_title;
32
  } else {
 
 
 
 
 
 
 
33
  $message_below_input_field = sprintf(
34
+ fs_text_inline( 'The %1$s will be periodically sending essential license data to %2$s to check for security and feature updates, and verify the validity of your license.', 'license-sync-disclaimer', $slug ),
35
  $fs->get_module_label( true ),
36
+ "<b>{$fs->get_plugin_title()}</b>"
37
  );
38
 
39
  $activate_button_text = fs_text_inline( 'Agree & Activate License', 'agree-activate-license', $slug );
52
  if ( $is_network_activation ) {
53
  $all_sites = Freemius::get_sites();
54
 
55
+ $subsite_data_by_install_id = array();
56
+ $install_url_by_install_id = array();
57
+
58
  foreach ( $all_sites as $site ) {
59
  $site_details = $fs->get_site_info( $site );
60
 
61
+ if ( FS_Clone_Manager::instance()->is_temporary_duplicate_by_blog_id( $site_details['blog_id'] ) ) {
62
+ continue;
63
+ }
64
+
65
  $blog_id = Freemius::get_site_blog_id( $site );
66
  $install = $fs->get_install_by_blog_id($blog_id);
67
 
68
+ if ( is_object( $install ) ) {
69
+ if ( isset( $subsite_data_by_install_id[ $install->id ] ) ) {
70
+ $clone_subsite_data = $subsite_data_by_install_id[ $install->id ];
71
+ $clone_install_url = $install_url_by_install_id[ $install->id ];
72
 
73
+ if (
74
+ /**
75
+ * If we already have an install with the same URL as the subsite it's stored in, skip the current subsite. Otherwise, replace the existing install's data with the current subsite's install's data if the URLs match.
76
+ *
77
+ * @author Leo Fajardo (@leorw)
78
+ * @since 2.5.0
79
+ */
80
+ fs_strip_url_protocol( untrailingslashit( $clone_install_url ) ) === fs_strip_url_protocol( untrailingslashit( $clone_subsite_data['url'] ) ) ||
81
+ fs_strip_url_protocol( untrailingslashit( $install->url ) ) !== fs_strip_url_protocol( untrailingslashit( $site_details['url'] ) )
82
+ ) {
83
+ continue;
84
+ }
85
+ }
86
+
87
+ if ( FS_Plugin_License::is_valid_id( $install->license_id ) ) {
88
+ $site_details['license_id'] = $install->license_id;
89
+ }
90
+
91
+ $subsite_data_by_install_id[ $install->id ] = $site_details;
92
+ $install_url_by_install_id[ $install->id ] = $install->url;
93
+ }
94
  }
95
 
96
  if ( $is_network_activation ) {
97
  $vars = array(
98
  'id' => $fs->get_id(),
99
+ 'sites' => array_values( $subsite_data_by_install_id ),
100
  'require_license_key' => true
101
  );
102
 
362
  $activateLicenseButton.html( '<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait', $slug ) ?>...' );
363
 
364
  $.ajax( {
365
+ url : <?php echo Freemius::ajax_url() ?>,
366
  method : 'POST',
367
  data : {
368
  action : '<?php echo $fs->get_ajax_action( 'fetch_is_marketing_required_flag_value' ) ?>',
610
  url : $this.find( '.url' ).val(),
611
  title : $this.find( '.title' ).val(),
612
  language: $this.find( '.language' ).val(),
 
613
  blog_id : $this.find( '.blog-id' ).find( 'span' ).text()
614
  };
615
 
627
  }
628
 
629
  $.ajax({
630
+ url: <?php echo Freemius::ajax_url() ?>,
631
  method: 'POST',
632
  data: data,
633
  beforeSend: function () {
887
  }
888
  });
889
  })( jQuery );
890
+ </script>
freemius/templates/forms/optout.php CHANGED
@@ -17,320 +17,166 @@
17
  $fs = freemius( $VARS['id'] );
18
  $slug = $fs->get_slug();
19
 
20
- $action = $fs->is_tracking_allowed() ?
21
- 'stop_tracking' :
22
- 'allow_tracking';
23
-
24
  $reconnect_url = $fs->get_activation_url( array(
25
  'nonce' => wp_create_nonce( $fs->get_unique_affix() . '_reconnect' ),
26
  'fs_action' => ( $fs->get_unique_affix() . '_reconnect' ),
27
  ) );
28
 
29
- $plugin_title = "<strong>{$fs->get_plugin()->title}</strong>";
30
- $opt_out_text = fs_text_x_inline( 'Opt Out', 'verb', 'opt-out', $slug );
31
- $opt_in_text = fs_text_x_inline( 'Opt In', 'verb', 'opt-in', $slug );
32
-
33
- if ( $fs->is_premium() ) {
34
- $opt_in_message_appreciation = fs_text_inline( 'Connectivity to the licensing engine was successfully re-established. Automatic security & feature updates are now available through the WP Admin Dashboard.', 'premium-opt-in-message-appreciation', $slug );
35
-
36
- $opt_out_message_subtitle = sprintf( fs_text_inline( 'Warning: Opting out will block automatic updates', 'premium-opt-out-message-appreciation', $slug ), $fs->get_module_type() );
37
- $opt_out_message_usage_tracking = sprintf( fs_text_inline( 'Ongoing connectivity with the licensing engine is essential for receiving automatic security & feature updates of the paid product. To receive these updates, data like your license key, %1$s version, and WordPress version, is periodically sent to the server to check for updates. By opting out, you understand that your site won\'t receive automatic updates for %2$s from within the WP Admin Dashboard. This can put your site at risk, and we highly recommend to keep this connection active. If you do choose to opt-out, you\'ll need to check for %1$s updates and install them manually.', 'premium-opt-out-message-usage-tracking', $slug ), $fs->get_module_type(), $plugin_title );
38
-
39
- $primary_cta_label = fs_text_inline( 'I\'d like to keep automatic updates', 'premium-opt-out-cancel', $slug );
40
- } else {
41
- $opt_in_message_appreciation = sprintf( fs_text_inline( 'We appreciate your help in making the %s better by letting us track some usage data.', 'opt-in-message-appreciation', $slug ), $fs->get_module_type() );
42
-
43
- $opt_out_message_subtitle = $opt_in_message_appreciation;
44
- $opt_out_message_usage_tracking = sprintf( fs_text_inline( "Usage tracking is done in the name of making %s better. Making a better user experience, prioritizing new features, and more good things. We'd really appreciate if you'll reconsider letting us continue with the tracking.", 'opt-out-message-usage-tracking', $slug ), $plugin_title );
45
- $primary_cta_label = fs_text_inline( 'On second thought - I want to continue helping', 'opt-out-cancel', $slug );
46
- }
47
-
48
- $opt_out_message_clicking_opt_out = sprintf(
49
- fs_text_inline( 'By clicking "Opt Out", we will no longer be sending any data from %s to %s.', 'opt-out-message-clicking-opt-out', $slug ),
50
- $plugin_title,
51
- sprintf(
52
- '<a href="%s" target="_blank" rel="noopener">%s</a>',
53
- 'https://freemius.com',
54
- 'freemius.com'
55
- )
56
- );
57
 
58
- $admin_notice_params = array(
59
- 'id' => '',
60
- 'slug' => $fs->get_id(),
61
- 'type' => 'success',
62
- 'sticky' => false,
63
- 'plugin' => $fs->get_plugin()->title,
64
- 'message' => $opt_in_message_appreciation
65
- );
66
-
67
- $admin_notice_html = fs_get_template( 'admin-notice.php', $admin_notice_params );
68
-
69
- $modal_content_html = "
70
- <h2" . ( $fs->is_premium() ? ' style="color: red"' : '' ) . ">{$opt_out_message_subtitle}</h2>
71
- <div class=\"notice notice-error inline opt-out-error-message\"><p></p></div>
72
- <p>{$opt_out_message_usage_tracking}</p>
73
- <p>{$opt_out_message_clicking_opt_out}</p>
74
- <label class=\"fs-permission-extensions\"><div class=\"fs-switch fs-small fs-round fs-" . ( $fs->is_extensions_tracking_allowed() ? 'on' : 'off' ) . "\"><div class=\"fs-toggle\"></div></div> " . fs_text_inline( 'Plugins & themes tracking' ) . " <span class=\"fs-switch-feedback success\"></span></label>";
75
 
76
  fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
 
77
  fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  <script type="text/javascript">
80
  (function( $ ) {
81
  $( document ).ready(function() {
82
- var modalContentHtml = <?php echo json_encode( $modal_content_html ) ?>,
83
- modalHtml =
84
- '<div class="fs-modal fs-modal-opt-out">'
85
- + ' <div class="fs-modal-dialog">'
86
- + ' <div class="fs-modal-header">'
87
- + ' <h4><?php echo esc_js( $opt_out_text ) ?></h4>'
88
- + ' </div>'
89
- + ' <div class="fs-modal-body">'
90
- + ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
91
- + ' </div>'
92
- + ' <div class="fs-modal-footer">'
93
- + ' <button class="button <?php echo $fs->is_premium() ? 'button-primary warn' : 'button-secondary' ?> button-opt-out" tabindex="1"><?php echo esc_js( $opt_out_text ) ?></button>'
94
- + ' <button class="button <?php echo $fs->is_premium() ? 'button-secondary' : 'button-primary' ?> button-close" tabindex="2"><?php echo esc_js( $primary_cta_label ) ?></button>'
95
- + ' </div>'
96
- + ' </div>'
97
- + '</div>',
98
- $modal = $(modalHtml),
99
- $adminNotice = $( <?php echo json_encode( $admin_notice_html ) ?> ),
100
- action = '<?php echo $action ?>',
101
- actionLinkSelector = 'span.opt-in-or-opt-out.<?php echo $slug ?> a',
102
- $optOutButton = $modal.find( '.button-opt-out' ),
103
- $optOutErrorMessage = $modal.find( '.opt-out-error-message' ),
104
- $extensionsTracking = $modal.find( '.fs-permission-extensions' ),
105
- $body = $( 'body' ),
106
- moduleID = '<?php echo $fs->get_id() ?>';
107
-
108
- $modal.data( 'action', action );
109
- $modal.appendTo( $body );
110
-
111
- function registerActionLinkClick() {
112
- $body.on( 'click', actionLinkSelector, function( evt ) {
113
- evt.preventDefault();
114
-
115
- if ( 'stop_tracking' == $modal.data( 'action' ) ) {
116
- showModal();
117
- } else {
118
- optIn();
119
- }
120
-
121
- return false;
122
- });
123
- }
124
-
125
- function registerEventHandlers() {
126
- registerActionLinkClick();
127
-
128
- $modal.on( 'click', '.button-opt-out', function( evt ) {
129
- evt.preventDefault();
130
-
131
- if ( $( this ).hasClass( 'disabled' ) ) {
132
- return;
133
- }
134
-
135
- disableOptOutButton();
136
- optOut();
137
- });
138
-
139
- // If the user has clicked outside the window, close the modal.
140
- $modal.on( 'click', '.fs-close, .button-close', function() {
141
- closeModal();
142
- return false;
143
- });
144
- }
145
-
146
- <?php if ( $fs->is_registered() ) : ?>
147
- registerEventHandlers();
148
- <?php endif ?>
149
-
150
- function showModal() {
151
- resetModal();
152
-
153
- // Display the dialog box.
154
- $modal.addClass( 'active' );
155
- $body.addClass( 'has-fs-modal' );
156
- }
157
-
158
- function closeModal() {
159
- $modal.removeClass( 'active' );
160
- $body.removeClass( 'has-fs-modal' );
161
- }
162
-
163
- function resetOptOutButton() {
164
- enableOptOutButton();
165
- $optOutButton.text( <?php echo json_encode( $opt_out_text ) ?> );
166
- }
167
-
168
- function resetModal() {
169
- hideError();
170
- resetOptOutButton();
171
- }
172
-
173
- function optIn() {
174
- sendRequest();
175
- }
176
-
177
- function optOut() {
178
- sendRequest();
179
- }
180
-
181
- function sendRequest() {
182
- var $actionLink = $( actionLinkSelector );
183
-
184
- $.ajax({
185
- url: ajaxurl,
186
- method: 'POST',
187
- data: {
188
- action : ( 'stop_tracking' == action ?
189
- '<?php echo $fs->get_ajax_action( 'stop_tracking' ) ?>' :
190
- '<?php echo $fs->get_ajax_action( 'allow_tracking' ) ?>'
191
- ),
192
- security : ( 'stop_tracking' == action ?
193
- '<?php echo $fs->get_ajax_security( 'stop_tracking' ) ?>' :
194
- '<?php echo $fs->get_ajax_security( 'allow_tracking' ) ?>'
195
- ),
196
- module_id: moduleID,
197
- _wp_http_referer: '<?php echo $fs->current_page_url() ?>'
198
- },
199
- beforeSend: function() {
200
- if ( 'allow_tracking' == action ) {
201
- $actionLink.text( '<?php fs_esc_js_echo_inline( 'Opting in', 'opting-in', $slug ) ?>...' );
202
- } else {
203
- $optOutButton.text( '<?php fs_esc_js_echo_inline( 'Opting out', 'opting-out', $slug ) ?>...' );
204
- }
205
- },
206
- success: function( resultObj ) {
207
- if ( resultObj.success ) {
208
- if ( 'allow_tracking' == action ) {
209
- action = 'stop_tracking';
210
- $actionLink.text( '<?php echo esc_js( $opt_out_text ) ?>' );
211
- showOptInAppreciationMessageAndScrollToTop();
212
- } else {
213
- action = 'allow_tracking';
214
- $actionLink.text( '<?php echo esc_js( $opt_in_text ) ?>' );
215
- closeModal();
216
-
217
- if ( $adminNotice.length > 0 ) {
218
- $adminNotice.remove();
219
- }
220
- }
221
-
222
- $modal.data( 'action', action );
223
- } else {
224
- showError( resultObj.error );
225
- resetOptOutButton();
226
- }
227
- }
228
- });
229
- }
230
-
231
- var isUpdatingPermission = false;
232
- $extensionsTracking.on('click', function() {
233
- if (isUpdatingPermission) {
234
- return false;
235
- }
236
-
237
- isUpdatingPermission = true;
238
-
239
- var $switch = $extensionsTracking.find( '.fs-switch' ),
240
- $switchFeedback = $extensionsTracking.find( '.fs-switch-feedback' );
241
-
242
- $switch
243
- .toggleClass( 'fs-on' )
244
- .toggleClass( 'fs-off' );
245
-
246
- $switchFeedback.html( '<i class="fs-ajax-spinner"></i>' );
247
-
248
- $.ajax({
249
- url: ajaxurl,
250
- method: 'POST',
251
- data: {
252
- action : '<?php echo $fs->get_ajax_action( 'update_tracking_permission' ) ?>',
253
- security : '<?php echo $fs->get_ajax_security( 'update_tracking_permission' ) ?>',
254
- module_id : moduleID,
255
- _wp_http_referer: '<?php echo $fs->current_page_url() ?>',
256
- permission: 'extensions',
257
- is_enabled: $switch.hasClass('fs-on')
258
- },
259
- success: function( resultObj ) {
260
- if ( resultObj.success ) {
261
- $switchFeedback.html( '<i class="dashicons dashicons-yes"></i> <?php echo esc_js( fs_text_inline( 'Saved', 'saved', $slug ) ) ?>' )
262
- } else {
263
- $switch
264
- .toggleClass( 'fs-on' )
265
- .toggleClass( 'fs-off' );
266
- }
267
-
268
- isUpdatingPermission = false;
269
- }
270
- });
271
- });
272
-
273
- function enableOptOutButton() {
274
- $optOutButton.removeClass( 'disabled' );
275
- }
276
-
277
- function disableOptOutButton() {
278
- $optOutButton.addClass( 'disabled' );
279
- }
280
-
281
- function hideError() {
282
- $optOutErrorMessage.hide();
283
- }
284
-
285
- function showOptInAppreciationMessageAndScrollToTop() {
286
- $adminNotice.insertAfter( $( '#wpbody-content' ).find( ' > .wrap > h1' ) );
287
- window.scrollTo(0, 0);
288
- }
289
-
290
- function showError( msg ) {
291
- $optOutErrorMessage.find( ' > p' ).html( msg );
292
- $optOutErrorMessage.show();
293
- }
294
-
295
- <?php if ( $fs->is_theme() ) : ?>
296
- /**
297
- * Add opt-in/out button to the active theme's buttons collection
298
- * in the theme's extended details overlay.
299
- *
300
- * @author Vova Feldman (@svovaf)
301
- * @since 1.2.2.7
302
- */
303
- $('.theme-overlay').contentChange(function () {
304
- if (0 === $('.theme-overlay.active').length) {
305
- // Add opt-in/out button only to the currently active theme.
306
- return;
307
- }
308
-
309
- if ($('#fs_theme_opt_in_out').length > 0){
310
- // Button already there.
311
- return;
312
- }
313
-
314
- var label = (('stop_tracking' == action) ?
315
- '<?php echo esc_js( $opt_out_text ) ?>' :
316
- '<?php echo esc_js( $opt_in_text ) ?>'),
317
- href = (('stop_tracking' != action) ?
318
- '<?php echo ( $fs->is_registered() ? '' : esc_js( $reconnect_url ) ) ?>' :
319
- '');
320
-
321
- var $actionLink = $('<a id="fs_theme_opt_in_out" href="' + encodeURI(href) + '" class="button">' + label + '</a>');
322
-
323
- actionLinkSelector = '#fs_theme_opt_in_out';
324
-
325
- $modal.data( 'action', action );
326
-
327
- $('.theme-wrap .theme-actions .active-theme').append($actionLink);
328
-
329
- if ('' === href) {
330
- registerActionLinkClick();
331
- }
332
- });
333
- <?php endif ?>
334
  });
335
  })( jQuery );
336
  </script>
17
  $fs = freemius( $VARS['id'] );
18
  $slug = $fs->get_slug();
19
 
 
 
 
 
20
  $reconnect_url = $fs->get_activation_url( array(
21
  'nonce' => wp_create_nonce( $fs->get_unique_affix() . '_reconnect' ),
22
  'fs_action' => ( $fs->get_unique_affix() . '_reconnect' ),
23
  ) );
24
 
25
+ $plugin_title = "<strong>" . esc_html( $fs->get_plugin()->title ) . "</strong>";
26
+ $opt_out_text = fs_text_x_inline( 'Opt Out', 'verb', 'opt-out', $slug );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ $permission_manager = FS_Permission_Manager::instance( $fs );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
31
+ fs_enqueue_local_style( 'fs_optout', '/admin/optout.css' );
32
  fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
33
+
34
+ if ( ! $fs->is_premium() ) {
35
+ $optional_permissions = array( $permission_manager->get_extensions_permission( false,
36
+ false,
37
+ true
38
+ ) );
39
+
40
+ $permission_groups = array(
41
+ array(
42
+ 'id' => 'communication',
43
+ 'type' => 'required',
44
+ 'title' => $fs->get_text_inline( 'Communication', 'communication' ),
45
+ 'desc' => '',
46
+ 'permissions' => $permission_manager->get_opt_in_required_permissions( true ),
47
+ 'is_enabled' => $fs->is_registered(),
48
+ 'prompt' => array(
49
+ $fs->esc_html_inline( "Sharing your name and email allows us to keep you in the loop about new features and important updates, warn you about security issues before they become public knowledge, and send you special offers.", 'opt-out-message_user' ),
50
+ sprintf(
51
+ $fs->esc_html_inline( 'By clicking "Opt Out", %s will no longer be able to view your name and email.',
52
+ 'opt-out-message-clicking-opt-out' ),
53
+ $plugin_title
54
+ ),
55
+ ),
56
+ 'prompt_cancel_label' => $fs->get_text_inline( 'Stay Connected', 'stay-connected' )
57
+ ),
58
+ array(
59
+ 'id' => 'diagnostic',
60
+ 'type' => 'required',
61
+ 'title' => $fs->get_text_inline( 'Diagnostic Info', 'diagnostic-info' ),
62
+ 'desc' => '',
63
+ 'permissions' => $permission_manager->get_opt_in_diagnostic_permissions( true ),
64
+ 'is_enabled' => $fs->is_tracking_allowed(),
65
+ 'prompt' => array(
66
+ sprintf(
67
+ $fs->esc_html_inline( 'Sharing diagnostic data helps to provide additional functionality that\'s relevant to your website, avoid WordPress or PHP version incompatibilities that can break the website, and recognize which languages & regions the %s should be translated and tailored to.',
68
+ 'opt-out-message-clicking-opt-out' ),
69
+ $fs->get_module_type()
70
+ ),
71
+ sprintf(
72
+ $fs->esc_html_inline( 'By clicking "Opt Out", diagnostic data will no longer be sent to %s.',
73
+ 'opt-out-message-clicking-opt-out' ),
74
+ $plugin_title
75
+ ),
76
+ ),
77
+ 'prompt_cancel_label' => $fs->get_text_inline( 'Keep Sharing', 'keep-sharing' )
78
+ ),
79
+ array(
80
+ 'id' => 'extensions',
81
+ 'type' => 'optional',
82
+ 'title' => $fs->get_text_inline( 'Extensions', 'extensions' ),
83
+ 'desc' => '',
84
+ 'permissions' => $optional_permissions,
85
+ ),
86
+ );
87
+ } else {
88
+ $optional_permissions = $permission_manager->get_license_optional_permissions( false, true );
89
+
90
+ $permission_groups = array(
91
+ array(
92
+ 'id' => 'essentials',
93
+ 'type' => 'required',
94
+ 'title' => $fs->esc_html_inline( 'Required', 'required' ),
95
+ 'desc' => sprintf( $fs->esc_html_inline( 'For automatic delivery of security & feature updates, and license management & protection, %s needs to:',
96
+ 'license-sync-disclaimer' ),
97
+ '<b>' . esc_html( $fs->get_plugin_title() ) . '</b>' ),
98
+ 'permissions' => $permission_manager->get_license_required_permissions( true ),
99
+ 'is_enabled' => $permission_manager->is_essentials_tracking_allowed(),
100
+ 'prompt' => array(
101
+ sprintf( $fs->esc_html_inline( 'To ensure that security & feature updates are automatically delivered directly to your WordPress Admin Dashboard while protecting your license from unauthorized abuse, %2$s needs to view the website’s homepage URL, %1$s version, SDK version, and whether the %1$s is active.', 'premium-opt-out-message-usage-tracking' ), $fs->get_module_type(), $plugin_title ),
102
+ sprintf( $fs->esc_html_inline( 'By opting out from sharing this information with the updates server, you’ll have to check for new %1$s releases and manually download & install them. Not just a hassle, but missing an update can put your site at risk and cause undue compatibility issues, so we highly recommend keeping these essential permissions on.', 'opt-out-message-clicking-opt-out' ), $fs->get_module_type(), $plugin_title ),
103
+ ),
104
+ 'prompt_cancel_label' => $fs->get_text_inline( 'Keep automatic updates', 'premium-opt-out-cancel' )
105
+ ),
106
+ array(
107
+ 'id' => 'optional',
108
+ 'type' => 'optional',
109
+ 'title' => $fs->esc_html_inline( 'Optional', 'optional' ),
110
+ 'desc' => sprintf( $fs->esc_html_inline( 'For ongoing compatibility with your website, you can optionally allow %s to:',
111
+ 'optional-permissions-disclaimer' ), $plugin_title ),
112
+ 'permissions' => $optional_permissions,
113
+ ),
114
+ );
115
+ }
116
+
117
+ $ajax_action = 'toggle_permission_tracking';
118
+
119
+ $form_id = "fs_opt_out_{$fs->get_id()}";
120
  ?>
121
+ <div id="<?php echo $form_id ?>"
122
+ class="fs-modal fs-modal-opt-out"
123
+ data-plugin-id="<?php echo $fs->get_id() ?>"
124
+ data-action="<?php echo $fs->get_ajax_action( $ajax_action ) ?>"
125
+ data-security="<?php echo $fs->get_ajax_security( $ajax_action ) ?>"
126
+ style="display: none">
127
+ <div class="fs-modal-dialog">
128
+ <div class="fs-modal-header">
129
+ <h4><?php echo esc_html( $opt_out_text ) ?></h4>
130
+ <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="Dismiss"></i></a>
131
+ </div>
132
+ <div class="fs-opt-out-permissions">
133
+ <div class="fs-modal-body">
134
+ <div class="notice notice-error inline opt-out-error-message"><p></p></div>
135
+ <div class="fs-permissions fs-open">
136
+ <?php foreach ( $permission_groups as $i => $permission_group ) : ?>
137
+ <?php $permission_manager->render_permissions_group( $permission_group ) ?>
138
+ <?php if ( $i < count( $permission_groups ) - 1 ) : ?><hr><?php endif ?>
139
+ <?php endforeach ?>
140
+ </div>
141
+ </div>
142
+ <div class="fs-modal-footer">
143
+ <button class="button button-primary button-close" tabindex="1"><?php echo $fs->esc_html_inline( 'Done', 'done' ) ?></button>
144
+ </div>
145
+ </div>
146
+ <?php foreach ( $permission_groups as $i => $permission_group ) : ?>
147
+ <?php if ( ! empty( $permission_group[ 'prompt' ] ) ) : ?>
148
+ <div class="fs-<?php echo $permission_group[ 'id' ] ?>-opt-out fs-opt-out-disclaimer" data-group-id="<?php echo $permission_group[ 'id' ] ?>" style="display: none">
149
+ <div class="fs-modal-body">
150
+ <div class="fs-modal-panel active">
151
+ <div class="notice notice-error inline opt-out-error-message"><p></p></div>
152
+ <?php foreach ( $permission_group[ 'prompt' ] as $p ) : ?>
153
+ <p><?php echo $p ?></p>
154
+ <?php endforeach ?>
155
+ </div>
156
+ </div>
157
+ <div class="fs-modal-footer">
158
+ <a class="fs-opt-out-button" tabindex="2" href="#"><?php echo esc_html( $opt_out_text ) ?></a>
159
+ <button class="button button-primary fs-opt-out-cancel-button" tabindex="1"><?php echo esc_html( $permission_group[ 'prompt_cancel_label' ] ) ?></button>
160
+ </div>
161
+ </div>
162
+ <?php endif ?>
163
+ <?php endforeach ?>
164
+ </div>
165
+ </div>
166
+
167
+ <?php $permission_manager->require_permissions_js( false ) ?>
168
+
169
  <script type="text/javascript">
170
  (function( $ ) {
171
  $( document ).ready(function() {
172
+ FS.OptOut(
173
+ '<?php echo $fs->get_id() ?>',
174
+ '<?php echo $slug ?>',
175
+ '<?php echo $fs->get_module_type() ?>',
176
+ <?php echo $fs->is_registered( true ) ? 'true' : 'false' ?>,
177
+ <?php echo $fs->is_tracking_allowed() ? 'true' : 'false' ?>,
178
+ '<?php echo esc_js( $reconnect_url ) ?>'
179
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  });
181
  })( jQuery );
182
  </script>
freemius/templates/forms/resend-key.php CHANGED
@@ -54,7 +54,10 @@ HTML;
54
  HTML;
55
  }
56
 
57
- $message_above_input_field = fs_esc_html_inline( "Enter the email address you've used for the upgrade below and we will resend you the license key.", 'ask-for-upgrade-email-address', $slug );
 
 
 
58
  $modal_content_html = <<< HTML
59
  <div class="notice notice-error inline license-resend-message"><p></p></div>
60
  <p>{$message_above_input_field}</p>
@@ -142,7 +145,7 @@ HTML;
142
  }
143
 
144
  $.ajax({
145
- url : ajaxurl,
146
  method : 'POST',
147
  data : {
148
  action : '<?php echo $fs->get_ajax_action( 'resend_license_key' ) ?>',
54
  HTML;
55
  }
56
 
57
+ $message_above_input_field = $fs->is_only_premium() ?
58
+ fs_esc_html_inline( "Enter the email address you've used during the purchase and we will resend you the license key.", 'ask-for-upgrade-email-address-premium-only', $slug ) :
59
+ fs_esc_html_inline( "Enter the email address you've used for the upgrade below and we will resend you the license key.", 'ask-for-upgrade-email-address', $slug );
60
+
61
  $modal_content_html = <<< HTML
62
  <div class="notice notice-error inline license-resend-message"><p></p></div>
63
  <p>{$message_above_input_field}</p>
145
  }
146
 
147
  $.ajax({
148
+ url : <?php echo Freemius::ajax_url() ?>,
149
  method : 'POST',
150
  data : {
151
  action : '<?php echo $fs->get_ajax_action( 'resend_license_key' ) ?>',
freemius/templates/forms/trial-start.php CHANGED
@@ -80,7 +80,7 @@ HTML;
80
  var $button = $(this);
81
 
82
  $.ajax({
83
- url : ajaxurl,
84
  method : 'POST',
85
  data : {
86
  action : '<?php echo $fs->get_ajax_action( 'start_trial' ) ?>',
80
  var $button = $(this);
81
 
82
  $.ajax({
83
+ url : <?php echo Freemius::ajax_url() ?>,
84
  method : 'POST',
85
  data : {
86
  action : '<?php echo $fs->get_ajax_action( 'start_trial' ) ?>',
freemius/templates/forms/user-change.php CHANGED
@@ -194,7 +194,7 @@ HTML;
194
  disableUserChangeButton();
195
 
196
  $.ajax( {
197
- url : ajaxurl,
198
  method : 'POST',
199
  data : {
200
  action : '<?php echo $fs->get_ajax_action( 'change_user' ) ?>',
194
  disableUserChangeButton();
195
 
196
  $.ajax( {
197
+ url : <?php echo Freemius::ajax_url() ?>,
198
  method : 'POST',
199
  data : {
200
  action : '<?php echo $fs->get_ajax_action( 'change_user' ) ?>',
freemius/templates/gdpr-optin-js.php CHANGED
@@ -38,7 +38,7 @@
38
  }
39
 
40
  $.ajax({
41
- url : ajaxurl + '?' + $.param({
42
  action : '<?php echo $fs->get_ajax_action( 'gdpr_optin_action' ) ?>',
43
  security : '<?php echo $fs->get_ajax_security( 'gdpr_optin_action' ) ?>',
44
  module_id: '<?php echo $fs->get_id() ?>'
38
  }
39
 
40
  $.ajax({
41
+ url : <?php echo Freemius::ajax_url() ?> + '?' + $.param({
42
  action : '<?php echo $fs->get_ajax_action( 'gdpr_optin_action' ) ?>',
43
  security : '<?php echo $fs->get_ajax_security( 'gdpr_optin_action' ) ?>',
44
  module_id: '<?php echo $fs->get_id() ?>'
freemius/templates/js/permissions.php ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Freemius
4
+ * @copyright Copyright (c) 2015, Freemius, Inc.
5
+ * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
+ * @since 2.5.1
7
+ */
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+ ?>
12
+ <script type="text/javascript">
13
+ ( function ( $ ) {
14
+ var global = this;
15
+
16
+ // Namespace.
17
+ global.FS = global.FS || {};
18
+
19
+ //region Switches
20
+
21
+ function toggleSwitches( $switches, isOn ) {
22
+ $switches
23
+ .toggleClass( 'fs-on', ( null != isOn ? ( true === isOn ) : isOn ) )
24
+ .toggleClass( 'fs-off', ( null != isOn ? ( false === isOn ) : isOn ) );
25
+ }
26
+
27
+ function isSwitch( $switch, isOn ) {
28
+ return $switch.hasClass( isOn ? 'fs-on' : 'fs-off' );
29
+ }
30
+
31
+ function getSwitchesStates( $switches, isEnabled ) {
32
+ var switchStates = [];
33
+ for ( var i = 0; i < $switches.length; i++ ) {
34
+ switchStates.push( isSwitch( $( $switches[ i ] ), isEnabled ) );
35
+ }
36
+
37
+ return switchStates;
38
+ }
39
+
40
+ //endregion
41
+
42
+ function toggleGroupOptOut( $button, isEnabled ) {
43
+ setOptInLabel( $button, ! isEnabled );
44
+
45
+ $button.data( 'is-enabled', isEnabled );
46
+ }
47
+
48
+ /**
49
+ * @param {object} $permissionsSection
50
+ *
51
+ * @returns {string[]}
52
+ */
53
+ function getGroupPermissionIDs( $permissionsSection ) {
54
+ var permissions = [];
55
+ $permissionsSection.find( 'ul li').each( function() {
56
+ permissions.push( $( this ).data( 'permission-id' ) );
57
+ });
58
+
59
+ return permissions;
60
+ }
61
+
62
+ function getGroupOptOutButton( $section ) {
63
+ return $section.find( '.fs-group-opt-out-button' );
64
+ }
65
+
66
+ //region Opt-in/out Labels
67
+
68
+ function setUpdatingLabel( $button, isEnabled ) {
69
+ $button.text( isEnabled ?
70
+ '<?php fs_esc_js_echo_inline( 'Opting in', 'opting-in' ) ?>...' :
71
+ '<?php fs_esc_js_echo_inline( 'Opting out', 'opting-out' ) ?>...'
72
+ );
73
+ }
74
+
75
+ function getOptInLabel( isEnabled ) {
76
+ return isEnabled ?
77
+ '<?php echo esc_js( fs_text_x_inline( 'Opt In', 'verb', 'opt-in' ) ) ?>' :
78
+ '<?php echo esc_js( fs_text_x_inline( 'Opt Out', 'verb', 'opt-out' ) ) ?>';
79
+ }
80
+
81
+ function setOptInLabel( $button, isEnabled ) {
82
+ $button.text( getOptInLabel( isEnabled ) );
83
+ }
84
+
85
+ //endregion
86
+
87
+ global.FS.Permissions = function () {
88
+ var isUpdating = false;
89
+
90
+ function updateStarted() {
91
+ isUpdating = true;
92
+ $body.addClass( 'fs-loading' );
93
+ }
94
+
95
+ function updateCompleted() {
96
+ isUpdating = false;
97
+ $body.removeClass( 'fs-loading' );
98
+ }
99
+
100
+ return {
101
+ isUpdating: function() {
102
+ return isUpdating;
103
+ },
104
+ /**
105
+ * @param {Number} pluginID
106
+ * @param {Array} permissions
107
+ * @param {Boolean} isEnabled
108
+ * @param {Callback} [success]
109
+ * @param {Callback} [failure]
110
+ * @param {Callback} [complete]
111
+ */
112
+ updatePermissions: function(
113
+ pluginID,
114
+ permissions,
115
+ isEnabled,
116
+ success,
117
+ failure,
118
+ complete
119
+ ) {
120
+ if ( isUpdating ) {
121
+ return;
122
+ }
123
+
124
+ updateStarted();
125
+
126
+ var
127
+ $permissionsContainer = $( '#fs_opt_out_' + pluginID );
128
+
129
+ $.ajax( {
130
+ url : <?php echo Freemius::ajax_url() ?>,
131
+ method : 'POST',
132
+ data : {
133
+ action : $permissionsContainer.data( 'action' ),
134
+ security : $permissionsContainer.data( 'security' ),
135
+ module_id : pluginID,
136
+ _wp_http_referer: '<?php echo Freemius::current_page_url() ?>',
137
+ permissions : permissions.join( ',' ),
138
+ is_enabled : isEnabled
139
+ },
140
+ success : function ( resultObj ) {
141
+ if ( resultObj.success ) {
142
+ if ( success ) {
143
+ success( resultObj );
144
+ }
145
+ } else {
146
+ if ( failure ) {
147
+ failure( resultObj );
148
+ }
149
+ }
150
+ },
151
+ error : failure,
152
+ complete: function () {
153
+ if ( complete ) {
154
+ complete();
155
+ }
156
+
157
+ updateCompleted();
158
+ }
159
+ });
160
+ },
161
+ updateGroupPermissions: function(
162
+ pluginID,
163
+ groupID,
164
+ isEnabled,
165
+ success,
166
+ failure,
167
+ complete
168
+ ) {
169
+ if ( isUpdating ) {
170
+ return;
171
+ }
172
+
173
+ var
174
+ $modal = $( '#fs_opt_out_' + pluginID ),
175
+ $permissionsSection = $modal.find( '.fs-permissions-section.fs-' + groupID + '-permissions' ),
176
+ $optOutButton = getGroupOptOutButton( $permissionsSection ),
177
+ $permissions = $permissionsSection.find( 'ul li'),
178
+ permissions = [];
179
+
180
+ $permissions.each( function() {
181
+ permissions.push( $( this ).data( 'permission-id' ) );
182
+ });
183
+
184
+ setUpdatingLabel( $optOutButton, isEnabled );
185
+
186
+ this.updatePermissions(
187
+ pluginID,
188
+ permissions,
189
+ isEnabled,
190
+ function( resultObj ) {
191
+ if ( resultObj.success ) {
192
+ toggleGroupOptOut( $optOutButton, isEnabled );
193
+
194
+ // Update permissions state.
195
+ $permissions.toggleClass( 'fs-disabled', ! isEnabled );
196
+
197
+ // Update switches state, if there are any.
198
+ toggleSwitches( $permissions.find( '.fs-switch' ), isEnabled );
199
+
200
+ if ( success ) {
201
+ success();
202
+ }
203
+ }
204
+ },
205
+ function ( resultObj ) {
206
+ setOptInLabel( $optOutButton, isEnabled );
207
+
208
+ if ( failure ) {
209
+ failure( resultObj );
210
+ }
211
+ },
212
+ complete
213
+ );
214
+ }
215
+ };
216
+ }();
217
+
218
+ var $body = $( 'body' )
219
+
220
+ global.FS.OptOut = function (
221
+ pluginID,
222
+ slug,
223
+ type,
224
+ isRegistered,
225
+ isTrackingAllowed,
226
+ reconnectUrl
227
+ ) {
228
+ var $modal = $( '#fs_opt_out_' + pluginID ),
229
+ actionLinkSelector = ('theme' === type ? '#fs_theme_opt_in_out' : 'span.opt-in-or-opt-out.' + slug + ' a' );
230
+
231
+ //region Error Handling
232
+
233
+ function hideError( $optOutErrorMessage ) {
234
+ $optOutErrorMessage = $optOutErrorMessage || $modal.find( '.opt-out-error-message' );
235
+ $optOutErrorMessage.hide();
236
+ }
237
+
238
+ function showError( $optOutErrorMessage, msg ) {
239
+ $optOutErrorMessage.find( ' > p' ).html( msg );
240
+ $optOutErrorMessage.show();
241
+ }
242
+
243
+ //endregion
244
+
245
+ function backToPermissionsList() {
246
+ $modal.find( '.fs-opt-out-disclaimer' )
247
+ .hide();
248
+
249
+ $modal.find( '.fs-opt-out-permissions' )
250
+ .show();
251
+ }
252
+
253
+ function removeFeedbackIndicators() {
254
+ $modal.find( '.fs-switch-feedback' )
255
+ .remove();
256
+ }
257
+
258
+ //region Modal Dialog
259
+
260
+ function closeModal() {
261
+ $modal.removeClass( 'active' );
262
+ $body.removeClass( 'has-fs-modal' );
263
+ $modal.hide();
264
+ }
265
+
266
+ function resetModal() {
267
+ hideError();
268
+ removeFeedbackIndicators();
269
+ backToPermissionsList();
270
+ }
271
+
272
+ function showModal() {
273
+ resetModal();
274
+
275
+ // Display the dialog box.
276
+ $modal.show();
277
+ $modal.addClass( 'active' );
278
+ $body.addClass( 'has-fs-modal' );
279
+ }
280
+
281
+ //endregion
282
+
283
+ function registerActionLinkClick() {
284
+ $body.on( 'click', actionLinkSelector, function( evt ) {
285
+ evt.preventDefault();
286
+
287
+ showModal();
288
+
289
+ return false;
290
+ });
291
+ }
292
+
293
+ function registerEventHandlers() {
294
+ // If the user has clicked outside the window, close the modal.
295
+ $modal.on( 'click', '.fs-close, .button-close', function() {
296
+ closeModal();
297
+ return false;
298
+ } );
299
+
300
+ $modal.on( 'click', '.fs-permissions .fs-switch', function () {
301
+ if ( FS.Permissions.isUpdating() ) {
302
+ return false;
303
+ }
304
+
305
+ var $switch = $( this ),
306
+ $permission = $switch.closest( '.fs-permission' );
307
+
308
+ toggleSwitches( $switch );
309
+
310
+ $permission.toggleClass( 'fs-disabled' );
311
+
312
+ var $optOutContainer = $switch.closest( '.fs-modal-opt-out' );
313
+
314
+ if ( 0 === $optOutContainer.length ) {
315
+ return;
316
+ }
317
+
318
+ // Remove previously added feedback element.
319
+ $switch.closest( '.fs-modal-dialog' )
320
+ .find( '.fs-switch-feedback' )
321
+ .remove();
322
+
323
+ var $switchFeedback = $( '<span class="fs-switch-feedback"><i class="fs-ajax-spinner"></i></span>' );
324
+
325
+ $switch.after( $switchFeedback )
326
+
327
+ var
328
+ permissionID = $permission.data( 'permission-id' ),
329
+ isEnabled = isSwitch( $switch, true );
330
+
331
+ FS.Permissions.updatePermissions(
332
+ $optOutContainer.data( 'plugin-id' ),
333
+ [ permissionID ],
334
+ isEnabled,
335
+ function () {
336
+ $switchFeedback.addClass( 'success' );
337
+ $switchFeedback.html( '<i class="dashicons dashicons-yes"></i> <?php echo esc_js( fs_text_inline( 'Saved', 'saved' ) ) ?>' );
338
+
339
+ var
340
+ $permissionsGroup = $switch.closest( '.fs-permissions-section' ),
341
+ $groupPermissions = $permissionsGroup.find( 'ul li' );
342
+
343
+ var allGroupPermissionsUseSameValue = false;
344
+
345
+ if (
346
+ isEnabled &&
347
+ 0 === $groupPermissions.filter( '.fs-disabled' ).length )
348
+ {
349
+ allGroupPermissionsUseSameValue = true;
350
+ } else if (
351
+ ! isEnabled &&
352
+ $groupPermissions.length === $groupPermissions.filter( '.fs-disabled' ).length
353
+ ) {
354
+ allGroupPermissionsUseSameValue = true;
355
+ }
356
+
357
+ if ( allGroupPermissionsUseSameValue ) {
358
+ toggleGroupOptOut( getGroupOptOutButton( $permissionsGroup ), isEnabled );
359
+ }
360
+ },
361
+ function () {
362
+ // Revert switch.
363
+ toggleSwitches( $switch );
364
+
365
+ $switchFeedback.remove();
366
+ }
367
+ )
368
+ });
369
+
370
+ // Move back to the permissions list if cancelling opt-out.
371
+ $modal.on( 'click', '.fs-opt-out-disclaimer .fs-opt-out-cancel-button', function ( evt ) {
372
+ backToPermissionsList();
373
+ });
374
+
375
+ $modal.on( 'click', '.fs-opt-out-disclaimer .fs-modal-footer .fs-opt-out-button', function ( evt ) {
376
+ var
377
+ $optOutButton = $( this ),
378
+ $actionLink = $( actionLinkSelector ),
379
+ isEnabled = true,
380
+ $optOutDisclaimer = $( $optOutButton.closest( '.fs-opt-out-disclaimer' )[ 0 ] ),
381
+ groupID = $optOutDisclaimer.data( 'group-id' ),
382
+ $errorMessage = $optOutDisclaimer.find( '.opt-out-error-message' );
383
+
384
+ setUpdatingLabel( $optOutButton, ! isEnabled );
385
+
386
+ $optOutDisclaimer.find( '.button-primary' ).prop( 'disabled', true );
387
+
388
+ hideError( $errorMessage );
389
+
390
+ FS.Permissions.updateGroupPermissions(
391
+ pluginID,
392
+ groupID,
393
+ ! isEnabled,
394
+ function () {
395
+ if ( 'communication' === groupID ) {
396
+ window.location.reload();
397
+ } else {
398
+ setOptInLabel( $actionLink, ! isEnabled );
399
+
400
+ backToPermissionsList();
401
+ }
402
+ },
403
+ function ( resultObj ) {
404
+ setOptInLabel( $optOutButton, false );
405
+
406
+ showError( $errorMessage, resultObj.error );
407
+ },
408
+ function () {
409
+ if ( 'communication' !== groupID ) {
410
+ setOptInLabel( $optOutButton, false );
411
+ }
412
+
413
+ $optOutDisclaimer.find( '.button-primary' ).prop( 'disabled', false );
414
+ }
415
+ );
416
+ } );
417
+
418
+ $modal.on( 'click', '.fs-group-opt-out-button', function ( evt ) {
419
+ evt.preventDefault();
420
+
421
+ if ( FS.Permissions.isUpdating() ) {
422
+ return;
423
+ }
424
+
425
+ var
426
+ $optOutButton = $( this ),
427
+ groupID = $optOutButton.data( 'group-id' ),
428
+ isEnabled = $optOutButton.data( 'is-enabled' ),
429
+ $optOutDisclaimer = $modal.find( '.fs-' + groupID + '-opt-out' ),
430
+ isConfirmRequired = ( 0 < $optOutDisclaimer.length ),
431
+ $errorMessage = $modal.find( '.fs-opt-out-permissions .opt-out-error-message' );
432
+
433
+ $errorMessage.hide();
434
+
435
+ if ( isConfirmRequired ) {
436
+ if ( isEnabled ) {
437
+ // Move to disclaimer window.
438
+ $modal.find( '.fs-opt-out-permissions' )
439
+ .hide();
440
+
441
+ $optOutDisclaimer.show();
442
+ } else {
443
+ // Opt-in.
444
+ FS.Permissions.updateGroupPermissions(
445
+ pluginID,
446
+ groupID,
447
+ ! isEnabled,
448
+ ( 'communication' !== groupID ) ?
449
+ null :
450
+ function () {
451
+ window.location.reload();
452
+ },
453
+ function ( resultObj ) {
454
+ showError( $errorMessage, resultObj.error );
455
+ }
456
+ );
457
+ }
458
+ } else {
459
+ // Remove previously added feedback element.
460
+ $modal.find( '.fs-switch-feedback' )
461
+ .remove();
462
+
463
+ var $switches = $optOutButton.closest( '.fs-permissions-section' )
464
+ .find( '.fs-permission .fs-switch' );
465
+
466
+ var switchStates = getSwitchesStates( $switches, isEnabled );
467
+
468
+ toggleSwitches( $switches, ! isEnabled );
469
+
470
+ $switches.closest( '.fs-permission' )
471
+ .toggleClass( 'fs-disabled', isEnabled );
472
+
473
+ var $switchFeedback = $( '<span class="fs-switch-feedback"><i class="fs-ajax-spinner"></i></span>' );
474
+
475
+ $optOutButton.after( $switchFeedback )
476
+
477
+ setUpdatingLabel( $optOutButton, ! isEnabled );
478
+
479
+ FS.Permissions.updatePermissions(
480
+ pluginID,
481
+ getGroupPermissionIDs( $modal.find( '.fs-permissions-section.fs-' + groupID + '-permissions' ) ),
482
+ ! isEnabled,
483
+ function () {
484
+ $switchFeedback.addClass( 'success' );
485
+ $switchFeedback.html( '<i class="dashicons dashicons-yes"></i> <?php echo esc_js( fs_text_inline( 'Saved', 'saved' ) ) ?>' );
486
+
487
+ toggleGroupOptOut( $optOutButton, ! isEnabled );
488
+ },
489
+ function () {
490
+ // Revert switches to their previous state.
491
+ for ( var i = 0; i < switchStates.length; i++ ) {
492
+ if ( switchStates[ i ] ) {
493
+ toggleSwitches( $( $switches[ i ] ), isEnabled );
494
+ $( $switches[ i ] ).removeClass( 'fs-disabled' );
495
+ }
496
+ }
497
+
498
+ toggleGroupOptOut( $optOutButton, isEnabled );
499
+ }
500
+ )
501
+ }
502
+ });
503
+ }
504
+
505
+ if ( 'theme' === type ) {
506
+ /**
507
+ * Add opt-in/out button to the active theme's buttons collection
508
+ * in the theme's extended details overlay.
509
+ *
510
+ * @author Vova Feldman (@svovaf)
511
+ * @since 1.2.2.7
512
+ */
513
+ $( '.theme-overlay' ).contentChange( function () {
514
+ if ( 0 === $( '.theme-overlay.active' ).length ) {
515
+ // Add opt-in/out button only to the currently active theme.
516
+ return;
517
+ }
518
+
519
+ if ( $( '#fs_theme_opt_in_out' ).length > 0 ) {
520
+ // Button already there.
521
+ return;
522
+ }
523
+
524
+ var label = getOptInLabel( ! isTrackingAllowed ),
525
+ href = ( isTrackingAllowed || isRegistered ) ? '' : reconnectUrl,
526
+ $actionLink = $( '<a id="fs_theme_opt_in_out" href="' + encodeURI( href ) + '" class="button">' + label + '</a>' );
527
+
528
+ $( '.theme-wrap .theme-actions .active-theme' ).append( $actionLink );
529
+
530
+ if ( isRegistered && '' === href ) {
531
+ registerActionLinkClick();
532
+ }
533
+ });
534
+ }
535
+
536
+ if ( isRegistered ) {
537
+ if ( 'theme' !== type ) {
538
+ registerActionLinkClick();
539
+ }
540
+
541
+ registerEventHandlers();
542
+ }
543
+
544
+ };
545
+ } )( jQuery );
546
+ </script>
freemius/templates/partials/network-activation.php CHANGED
@@ -58,7 +58,7 @@
58
  <div class="fs-sites-list-container">
59
  <table cellspacing="0">
60
  <tbody>
61
- <?php $site_props = array('uid', 'url', 'title', 'charset', 'language') ?>
62
  <?php foreach ( $sites as $site ) : ?>
63
  <tr<?php if ( ! empty( $site['license_id'] ) ) {
64
  echo ' data-license-id="' . $site['license_id'] . '"';
58
  <div class="fs-sites-list-container">
59
  <table cellspacing="0">
60
  <tbody>
61
+ <?php $site_props = array('uid', 'url', 'title', 'language') ?>
62
  <?php foreach ( $sites as $site ) : ?>
63
  <tr<?php if ( ! empty( $site['license_id'] ) ) {
64
  echo ' data-license-id="' . $site['license_id'] . '"';
freemius/templates/plugin-icon.php CHANGED
@@ -14,7 +14,9 @@
14
  * @var array $VARS
15
  */
16
  $fs = freemius( $VARS['id'] );
 
 
17
  ?>
18
  <div class="fs-plugin-icon">
19
- <img src="<?php echo $fs->get_local_icon_url() ?>" width="80" height="80"/>
20
  </div>
14
  * @var array $VARS
15
  */
16
  $fs = freemius( $VARS['id'] );
17
+
18
+ $size = isset( $VARS['size'] ) ? $VARS['size'] : 80;
19
  ?>
20
  <div class="fs-plugin-icon">
21
+ <img src="<?php echo $fs->get_local_icon_url() ?>" width="<?php echo $size ?>" height="<?php echo $size ?>" />
22
  </div>
freemius/templates/plugin-info/features.php CHANGED
@@ -43,7 +43,7 @@
43
  $support_feature->title = fs_text_inline( 'Support', $plugin->slug );
44
  $features_plan_map[ $support_feature->id ] = array( 'feature' => $support_feature, 'plans' => array() );
45
  } else {
46
- $support_feature = $features_plan_map['support'];
47
  }
48
 
49
  $features_plan_map[ $support_feature->id ]['plans'][ $plan->id ] = $support_feature;
43
  $support_feature->title = fs_text_inline( 'Support', $plugin->slug );
44
  $features_plan_map[ $support_feature->id ] = array( 'feature' => $support_feature, 'plans' => array() );
45
  } else {
46
+ $support_feature = $features_plan_map['support']['feature'];
47
  }
48
 
49
  $features_plan_map[ $support_feature->id ]['plans'][ $plan->id ] = $support_feature;
freemius/templates/powered-by.php CHANGED
@@ -33,12 +33,12 @@
33
 
34
  $fs = freemius( $VARS['module_id'] );
35
 
36
- wp_enqueue_script( 'jquery' );
37
- wp_enqueue_script( 'json2' );
38
- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
39
- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
40
- ?>
41
- <?php if ( ! $fs->is_whitelabeled() ) : ?>
42
  <div id="pframe"></div>
43
  <script type="text/javascript">
44
  (function ($) {
@@ -58,4 +58,4 @@
58
  });
59
  })(jQuery);
60
  </script>
61
- <?php endif ?>
33
 
34
  $fs = freemius( $VARS['module_id'] );
35
 
36
+ if ( ! $fs->is_whitelabeled() && ! $fs->apply_filters( 'hide_freemius_powered_by', false ) ) {
37
+ wp_enqueue_script( 'jquery' );
38
+ wp_enqueue_script( 'json2' );
39
+ fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
40
+ fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
41
+ ?>
42
  <div id="pframe"></div>
43
  <script type="text/javascript">
44
  (function ($) {
58
  });
59
  })(jQuery);
60
  </script>
61
+ <?php } ?>
freemius/templates/pricing.php CHANGED
@@ -88,7 +88,8 @@
88
  // Billing cycle.
89
  'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),
90
  'is_network_admin' => fs_is_network_admin() ? 'true' : 'false',
91
- 'currency' => $fs->apply_filters( 'default_currency', 'usd' ),
 
92
  ) );
93
 
94
  $use_external_pricing = $fs->should_use_external_pricing();
@@ -122,21 +123,21 @@
122
  <div id="fs_pricing_wrapper" data-public-url="<?php echo trailingslashit( dirname( $pricing_js_url ) ) ?>"></div>
123
  <?php
124
  $pricing_config = array_merge( array(
125
- 'contact_url' => $fs->contact_url(),
126
- 'is_network_admin' => fs_is_network_admin(),
127
- 'is_production' => ( defined( 'WP_FS__IS_PRODUCTION_MODE' ) ? WP_FS__IS_PRODUCTION_MODE : null ),
128
- 'menu_slug' => $fs->get_menu_slug(),
129
- 'mode' => 'dashboard',
130
- 'fs_wp_endpoint_url' => WP_FS__ADDRESS,
131
- 'request_handler_url' => admin_url(
132
  'admin-ajax.php?' . http_build_query( array(
133
  'module_id' => $fs->get_id(),
134
  'action' => $fs->get_ajax_action( 'pricing_ajax_action' ),
135
  'security' => $fs->get_ajax_security( 'pricing_ajax_action' )
136
  ) )
137
  ),
138
- 'selector' => '#fs_pricing_wrapper',
139
- 'unique_affix' => $fs->get_unique_affix(),
 
140
  ), $query_params );
141
 
142
  wp_add_inline_script( 'freemius-pricing', 'Freemius.pricing.new( ' . json_encode( $pricing_config ) . ' )' );
@@ -206,4 +207,4 @@
206
  'module_slug' => $slug,
207
  'module_version' => $fs->get_plugin_version(),
208
  );
209
- fs_require_template( 'powered-by.php', $params );
88
  // Billing cycle.
89
  'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),
90
  'is_network_admin' => fs_is_network_admin() ? 'true' : 'false',
91
+ 'currency' => $fs->apply_filters( 'default_currency', 'usd' ),
92
+ 'discounts_model' => $fs->apply_filters( 'pricing/discounts_model', 'absolute' ),
93
  ) );
94
 
95
  $use_external_pricing = $fs->should_use_external_pricing();
123
  <div id="fs_pricing_wrapper" data-public-url="<?php echo trailingslashit( dirname( $pricing_js_url ) ) ?>"></div>
124
  <?php
125
  $pricing_config = array_merge( array(
126
+ 'contact_url' => $fs->contact_url(),
127
+ 'is_production' => ( defined( 'WP_FS__IS_PRODUCTION_MODE' ) ? WP_FS__IS_PRODUCTION_MODE : null ),
128
+ 'menu_slug' => $fs->get_menu_slug(),
129
+ 'mode' => 'dashboard',
130
+ 'fs_wp_endpoint_url' => WP_FS__ADDRESS,
131
+ 'request_handler_url' => admin_url(
 
132
  'admin-ajax.php?' . http_build_query( array(
133
  'module_id' => $fs->get_id(),
134
  'action' => $fs->get_ajax_action( 'pricing_ajax_action' ),
135
  'security' => $fs->get_ajax_security( 'pricing_ajax_action' )
136
  ) )
137
  ),
138
+ 'selector' => '#fs_pricing_wrapper',
139
+ 'unique_affix' => $fs->get_unique_affix(),
140
+ 'show_annual_in_monthly' => $fs->apply_filters( 'pricing/show_annual_in_monthly', true ),
141
  ), $query_params );
142
 
143
  wp_add_inline_script( 'freemius-pricing', 'Freemius.pricing.new( ' . json_encode( $pricing_config ) . ' )' );
207
  'module_slug' => $slug,
208
  'module_version' => $fs->get_plugin_version(),
209
  );
210
+ fs_require_template( 'powered-by.php', $params );
freemius/templates/sticky-admin-notice-js.php CHANGED
@@ -29,8 +29,7 @@
29
  message_id: id
30
  };
31
 
32
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
33
- $.post( ajaxurl, data, function( response ) {
34
 
35
  });
36
 
29
  message_id: id
30
  };
31
 
32
+ $.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) {
 
33
 
34
  });
35
 
freemius/templates/tabs-capture-js.php CHANGED
@@ -45,7 +45,7 @@
45
  var tabsHtml = $('.wrap .nav-tab-wrapper').clone().wrap('<div>').parent().html();
46
 
47
  $.ajax({
48
- url : ajaxurl + '?' + $.param({
49
  action : '<?php echo $fs->get_ajax_action( 'store_tabs' ) ?>',
50
  security : '<?php echo $fs->get_ajax_security( 'store_tabs' ) ?>',
51
  module_id: '<?php echo $fs->get_id() ?>'
45
  var tabsHtml = $('.wrap .nav-tab-wrapper').clone().wrap('<div>').parent().html();
46
 
47
  $.ajax({
48
+ url : <?php echo Freemius::ajax_url() ?> + '?' + $.param({
49
  action : '<?php echo $fs->get_ajax_action( 'store_tabs' ) ?>',
50
  security : '<?php echo $fs->get_ajax_security( 'store_tabs' ) ?>',
51
  module_id: '<?php echo $fs->get_id() ?>'
includes/admin-approve.php CHANGED
@@ -173,7 +173,7 @@ class pw_new_user_approve_admin_approve
173
  if (isset($_SERVER['REQUEST_URI'])) { $SERVER_URI = sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])); }
174
  $edit_link = add_query_arg('wp_http_referer', urlencode(esc_url($SERVER_URI)), "user-edit.php?user_id=$user->ID");
175
  }
176
- $edit = ($avatar == true) ? ('<strong style="position: relative; top: -17px; left: 6px;"><a href="' . esc_url($edit_link) . '">' . esc_html($user->user_login) . '</a></strong>') : ('<strong style="top: -17px; left: 6px;"><a href="' . esc_url($edit_link) . '">' . esc_html($user->user_login) . '</a></strong>');
177
 
178
  } else {
179
  $edit = ($avatar == true) ? ('<strong style="position: relative; top: -17px; left: 6px;">' . esc_html($user->user_login) . '</strong>') : ('<strong style="top: -17px; left: 6px;">' . esc_html($user->user_login) . '</strong>');
@@ -187,16 +187,20 @@ class pw_new_user_approve_admin_approve
187
  <td><a href="mailto:<?php esc_attr_e($user->user_email);?>"
188
  title="<?php esc_attr_e('email:', 'new-user-approve')?> <?php esc_attr_e($user->user_email);?>"><?php esc_html_e($user->user_email);?></a>
189
  </td>
190
- <?php if ($approve && $user->ID != get_current_user_id()) {?>
191
- <td><a class="button" href= "<?php echo esc_url($approve_link) ?>" title="<?php esc_attr_e('Approve', 'new-user-approve');?> <?php esc_attr_e($user->user_login);?>"><?php esc_html_e('Approve', 'new-user-approve');?></a>
192
- </td>
193
- <?php }?>
194
- <?php if ($deny && $user->ID != get_current_user_id()) {?>
195
- <td><a class="button" href="<?php echo esc_url($deny_link); ?>" title="<?php esc_attr_e('Deny', 'new-user-approve');?> <?php esc_attr_e($user->user_login);?>"><?php echo esc_html('Deny', 'new-user-approve'); ?></a>
196
- </td>
197
- <?php }?>
 
 
 
 
198
  <?php if ($user->ID == get_current_user_id()): ?>
199
- <td colspan="2">&nbsp;</td>
200
  <?php endif;?>
201
  </tr><?php
202
  $row++;
173
  if (isset($_SERVER['REQUEST_URI'])) { $SERVER_URI = sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])); }
174
  $edit_link = add_query_arg('wp_http_referer', urlencode(esc_url($SERVER_URI)), "user-edit.php?user_id=$user->ID");
175
  }
176
+ $edit = ($avatar == true) ? ('<strong style="position: relative; top: -17px; left: 6px;"><a class="users_edit_links" href="' . esc_url($edit_link) . '">' . esc_html($user->user_login) . '</a></strong>') : ('<strong style="top: -17px; left: 6px;"><a href="' . esc_url($edit_link) . '">' . esc_html($user->user_login) . '</a></strong>');
177
 
178
  } else {
179
  $edit = ($avatar == true) ? ('<strong style="position: relative; top: -17px; left: 6px;">' . esc_html($user->user_login) . '</strong>') : ('<strong style="top: -17px; left: 6px;">' . esc_html($user->user_login) . '</strong>');
187
  <td><a href="mailto:<?php esc_attr_e($user->user_email);?>"
188
  title="<?php esc_attr_e('email:', 'new-user-approve')?> <?php esc_attr_e($user->user_email);?>"><?php esc_html_e($user->user_email);?></a>
189
  </td>
190
+
191
+ <td>
192
+ <?php if ($approve && $user->ID != get_current_user_id()) {?>
193
+ <span><a class="button approve-btn" href= "<?php echo esc_url($approve_link) ?>" title="<?php esc_attr_e('Approve', 'new-user-approve');?> <?php esc_attr_e($user->user_login);?>"><?php esc_html_e('Approve', 'new-user-approve');?></a> </span>
194
+ <?php }?>
195
+
196
+ <?php if ($deny && $user->ID != get_current_user_id()) {?>
197
+ <span><a class="button deny-btn" href="<?php echo esc_url($deny_link); ?>" title="<?php esc_attr_e('Deny', 'new-user-approve');?> <?php esc_attr_e($user->user_login);?>"><?php echo esc_html('Deny', 'new-user-approve'); ?></a></span>
198
+ <?php }?>
199
+
200
+ </td>
201
+
202
  <?php if ($user->ID == get_current_user_id()): ?>
203
+ <td>&nbsp;</td>
204
  <?php endif;?>
205
  </tr><?php
206
  $row++;
includes/invitation-code.php CHANGED
@@ -57,17 +57,29 @@ class nua_invitation_code {
57
  add_action('manage_' . $this->code_post_type . '_posts_custom_column', array($this, 'invitation_code_columns_content'), 10, 2);
58
  add_filter('post_row_actions', array($this, 'remove_row_actions_from_table'), 10, 2);
59
  add_action('admin_head', array($this, 'invitation_code_edit_page_css'));
60
-
61
 
62
  $options = get_option('nua_free_invitation');
63
  if ($options == 'enable') {
64
  add_action('register_form', array($this, 'nua_invitation_code_field'));
 
65
  add_filter('new_user_approve_default_status', array($this, 'nua_invitation_status_code'), 10, 2);
66
  add_action('woocommerce_register_form', array($this, 'nua_invitation_code_field'));
67
  add_action('um_after_form_fields', array($this, 'nua_invitation_code_field'), 10, 2);
 
 
68
  }
69
  }
70
-
 
 
 
 
 
 
 
 
 
71
  public function nua_deactivate_code() {
72
 
73
  if (isset($_GET['post_type']) && $_GET['post_type'] == $this->code_post_type && is_admin()) {
@@ -499,14 +511,83 @@ class nua_invitation_code {
499
  }
500
 
501
  public function nua_invitation_code_field() {
 
 
 
 
502
  ?> <?php $nonce = wp_create_nonce('nua-invitation-code-nonce'); ?>
 
503
  <p>
504
- <label> <?php esc_html_e('Invitation Code', 'new-user-approve'); ?></label>
505
- <input type="hidden" name="nua_invitation_code_nonce_field" value = <?php esc_attr_e($nonce) ?>/>
506
  <input type="text" class="nua_invitation_code" name="nua_invitation_code" />
507
  </p>
508
  <?php
509
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
 
511
  public function nua_invitation_status_code($status, $user_id) {
512
  $nonce = isset($_POST['nua_invitation_code_nonce_field']) ? sanitize_text_field(wp_unslash($_POST['nua_invitation_code_nonce_field'])):'';
@@ -570,12 +651,38 @@ class nua_invitation_code {
570
  update_post_meta($post_inv->ID, $this->status_key, 'Expired');
571
  }
572
  $status = 'approved';
 
 
573
  return $status;
574
  }
575
  }
576
  }
577
  return $status;
578
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  public function invitation_code_columns($columns) {
580
  unset($columns['date']);
581
  unset($columns['title']);
57
  add_action('manage_' . $this->code_post_type . '_posts_custom_column', array($this, 'invitation_code_columns_content'), 10, 2);
58
  add_filter('post_row_actions', array($this, 'remove_row_actions_from_table'), 10, 2);
59
  add_action('admin_head', array($this, 'invitation_code_edit_page_css'));
60
+ add_filter( 'nua_disable_welcome_email',array($this,'nua_disable_welcome_email_callback'),10,2);
61
 
62
  $options = get_option('nua_free_invitation');
63
  if ($options == 'enable') {
64
  add_action('register_form', array($this, 'nua_invitation_code_field'));
65
+ add_filter('register_post', array($this, 'nua_invitation_status_code_field_validation'), 6, 3);
66
  add_filter('new_user_approve_default_status', array($this, 'nua_invitation_status_code'), 10, 2);
67
  add_action('woocommerce_register_form', array($this, 'nua_invitation_code_field'));
68
  add_action('um_after_form_fields', array($this, 'nua_invitation_code_field'), 10, 2);
69
+ add_action('nua_invited_user',array($this,'message_above_regform'),10,1);
70
+
71
  }
72
  }
73
+ public function nua_disable_welcome_email_callback($disabled,$user_id)
74
+ {
75
+ $status=get_user_meta( $user_id, 'pw_user_status', true );
76
+ if('approved'==$status)
77
+ {
78
+ $disabled=true;
79
+ }
80
+ return $disabled;
81
+ }
82
+
83
  public function nua_deactivate_code() {
84
 
85
  if (isset($_GET['post_type']) && $_GET['post_type'] == $this->code_post_type && is_admin()) {
511
  }
512
 
513
  public function nua_invitation_code_field() {
514
+ $required = ' *';
515
+ if (true === apply_filters('nua_invitation_code_optional', true)) {
516
+ $required = ' (optional)';
517
+ }
518
  ?> <?php $nonce = wp_create_nonce('nua-invitation-code-nonce'); ?>
519
+
520
  <p>
521
+ <label> <?php esc_html_e('Invitation Code', 'new-user-approve'); ?><span><?php esc_attr_e($required); ?></span></label>
522
+ <input type="hidden" name="nua_invitation_code_nonce_field" value = <?php esc_attr_e($nonce); ?>/>
523
  <input type="text" class="nua_invitation_code" name="nua_invitation_code" />
524
  </p>
525
  <?php
526
  }
527
+
528
+
529
+ public function nua_invitation_status_code_field_validation( $user_login, $user_email, $errors ){
530
+ $options = get_option('new_user_approve_options' );
531
+ $code_optional = apply_filters('nua_invitation_code_optional', true);
532
+ if ( isset($_POST['nua_invitation_code']) && !empty($_POST['nua_invitation_code'])) {
533
+ $args = array (
534
+ 'numberposts' => -1,
535
+ 'post_type' => $this->code_post_type,
536
+ 'post_status' => 'publish',
537
+ 'meta_query' =>
538
+ array(
539
+ 'relation' => 'AND',
540
+ array(
541
+ array(
542
+ 'key' => $this->code_key,
543
+ 'value' => sanitize_text_field($_POST['nua_invitation_code']),
544
+ 'compare' => '=',
545
+ ),
546
+ array(
547
+ 'key' => $this->usage_limit_key,
548
+ 'value' => '1',
549
+ 'compare' => '>=',
550
+ ),
551
+ array(
552
+ 'key' => $this->expiry_date_key,
553
+ 'value' => time(),
554
+ 'compare' => '>=',
555
+ ),
556
+ array(
557
+ 'key' => $this->status_key,
558
+ 'value' => 'Active',
559
+ 'compare' => '=',
560
+ ),
561
+ ),
562
+
563
+ ),
564
+
565
+ );
566
+ $posts = get_posts( $args );
567
+ $code_inv = '';
568
+ foreach ($posts as $post_inv) {
569
+
570
+ $code_inv = get_post_meta($post_inv->ID , $this->code_key, true );
571
+
572
+ if ($_POST['nua_invitation_code'] == $code_inv) {
573
+ // echo $_POST['nua_invitation_code']. ' = '. $code_inv;
574
+ return $errors;
575
+
576
+ }
577
+ }
578
+
579
+ $error_message = apply_filters('nua_invitation_code_err', __('<strong>ERROR</strong>: The Invitation code is invalid','new-user-approve'), $code_inv , $errors);
580
+ $errors->add( 'invcode_error', $error_message);
581
+ } else if ( !isset($_POST['nua_invitation_code']) || (isset($_POST['nua_invitation_code']) && empty($_POST['nua_invitation_code']) && !empty(get_option('nua_free_invitation'))) && true !== $code_optional ) {
582
+ $error_message = apply_filters('nua_invitation_code_err', __('<strong>ERROR</strong>: Please add an Invitation code.','new-user-approve'), '' , $errors);
583
+ $errors->add( 'invcode_error', $error_message );
584
+ }
585
+ return $errors;
586
+ }
587
+
588
+
589
+
590
+
591
 
592
  public function nua_invitation_status_code($status, $user_id) {
593
  $nonce = isset($_POST['nua_invitation_code_nonce_field']) ? sanitize_text_field(wp_unslash($_POST['nua_invitation_code_nonce_field'])):'';
651
  update_post_meta($post_inv->ID, $this->status_key, 'Expired');
652
  }
653
  $status = 'approved';
654
+ pw_new_user_approve()->approve_user( $user_id );
655
+ do_action('nua_invited_user',$user_id);
656
  return $status;
657
  }
658
  }
659
  }
660
  return $status;
661
  }
662
+
663
+
664
+
665
+ function message_above_regform($user_id)
666
+ {
667
+ add_filter( 'new_user_approve_pending_message', array($this,'msg_on_auto_approve_invitation_callback'), 10, 1 );
668
+
669
+ }
670
+
671
+ function msg_on_auto_approve_invitation_callback( $message )
672
+ {
673
+ // $opt=pw_new_user_approve_options()->option_key();
674
+ // $id = 'nua_registration_auto_approve_complete_message';
675
+ //require_once ( plugin_dir_path(__FILE__).'/includes/messages.php');
676
+ $message = nua_auto_approve_message();
677
+ $message = nua_do_email_tags( $message, array(
678
+ 'context' => 'approved_message',
679
+ ) );
680
+ // $message=pw_new_user_approve_options()->auto_approve_registration_complete_message($message);
681
+ return $message;
682
+ }
683
+
684
+
685
+
686
  public function invitation_code_columns($columns) {
687
  unset($columns['date']);
688
  unset($columns['title']);
includes/messages.php CHANGED
@@ -17,6 +17,8 @@ function nua_default_approve_user_message() {
17
  return $message;
18
  }
19
 
 
 
20
  /**
21
  * The default email message that will be sent to users as they are denied.
22
  *
@@ -45,6 +47,22 @@ function nua_default_registration_complete_message() {
45
  return $message;
46
  }
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  /**
49
  * The default welcome message that is shown to all users on the login page.
50
  *
17
  return $message;
18
  }
19
 
20
+
21
+
22
  /**
23
  * The default email message that will be sent to users as they are denied.
24
  *
47
  return $message;
48
  }
49
 
50
+ function nua_auto_approve_message() {
51
+
52
+
53
+ $message = sprintf( __( 'You have been approved to access {sitename}. You will receive an email with instructions on what you will need to do next. Thanks for your patience.
54
+
55
+ ', 'new-user-approve' ) );
56
+ $message .= ' ';
57
+ $message = apply_filters( 'new_user_approve_auto_approve_message', $message );
58
+
59
+ return $message;
60
+
61
+ }
62
+
63
+
64
+
65
+
66
  /**
67
  * The default welcome message that is shown to all users on the login page.
68
  *
includes/zapier/includes/rest-api.php CHANGED
@@ -37,17 +37,20 @@ class RestRoutes
37
  {
38
  register_rest_route( 'nua-zapier', '/v1/auth',array(
39
  'methods' => WP_REST_Server::EDITABLE,
40
- 'callback' => [ $this, 'authenticate' ]
 
41
  ) );
42
 
43
  register_rest_route( 'nua-zapier', '/v1/user-approved',array(
44
  'methods' => WP_REST_Server::EDITABLE,
45
- 'callback' => [ $this, 'user_approved' ]
 
46
  ) );
47
 
48
  register_rest_route( 'nua-zapier', '/v1/user-denied',array(
49
  'methods' => WP_REST_Server::EDITABLE,
50
- 'callback' => [ $this, 'user_denied' ]
 
51
  ) );
52
  }
53
 
@@ -70,10 +73,10 @@ class RestRoutes
70
 
71
  if( $api_key == $this->api_key() )
72
  return new \WP_REST_Response( true, 200 );
73
-
74
  if( $api_key == null )
75
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
76
-
77
  if( $api_key != $this->api_key() )
78
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
79
  }
@@ -81,13 +84,13 @@ class RestRoutes
81
  public function user_approved( $request )
82
  {
83
  $api_key = $request->get_param( 'api_key' );
84
-
85
  if( $api_key == null )
86
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
87
-
88
  if( $api_key != $this->api_key() )
89
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
90
-
91
  if( $api_key == $this->api_key() )
92
  {
93
  return $this->user_data( 'nua_user_approved' );
@@ -97,13 +100,13 @@ class RestRoutes
97
  public function user_denied( $request )
98
  {
99
  $api_key = $request->get_param( 'api_key' );
100
-
101
  if( $api_key == null )
102
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
103
-
104
  if( $api_key != $this->api_key() )
105
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
106
-
107
  if( $api_key == $this->api_key() )
108
  {
109
  return $this->user_data( 'nua_user_denied' );
@@ -119,13 +122,13 @@ class RestRoutes
119
  $data = array();
120
 
121
  $time_key = $option_name == 'nua_user_approved' ? 'approval_time' : 'denial_time';
122
-
123
  foreach( $user_data as $key => $value )
124
  {
125
  $user_id = $value['user_id'];
126
 
127
  $user = get_userdata( $user_id );
128
-
129
  $data[] = array(
130
  'id' => $value['id'],
131
  'user_login' => $user->user_login,
@@ -135,7 +138,7 @@ class RestRoutes
135
  $time_key => date( DATE_ISO8601, $value['time'] )
136
  );
137
  }
138
-
139
  return apply_filters( "{$option_name}_zapier", $data );
140
  }
141
  }
37
  {
38
  register_rest_route( 'nua-zapier', '/v1/auth',array(
39
  'methods' => WP_REST_Server::EDITABLE,
40
+ 'callback' => [ $this, 'authenticate' ],
41
+ 'permission_callback' => '__return_true'
42
  ) );
43
 
44
  register_rest_route( 'nua-zapier', '/v1/user-approved',array(
45
  'methods' => WP_REST_Server::EDITABLE,
46
+ 'callback' => [ $this, 'user_approved' ],
47
+ 'permission_callback' => '__return_true'
48
  ) );
49
 
50
  register_rest_route( 'nua-zapier', '/v1/user-denied',array(
51
  'methods' => WP_REST_Server::EDITABLE,
52
+ 'callback' => [ $this, 'user_denied' ],
53
+ 'permission_callback' => '__return_true'
54
  ) );
55
  }
56
 
73
 
74
  if( $api_key == $this->api_key() )
75
  return new \WP_REST_Response( true, 200 );
76
+
77
  if( $api_key == null )
78
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
79
+
80
  if( $api_key != $this->api_key() )
81
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
82
  }
84
  public function user_approved( $request )
85
  {
86
  $api_key = $request->get_param( 'api_key' );
87
+
88
  if( $api_key == null )
89
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
90
+
91
  if( $api_key != $this->api_key() )
92
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
93
+
94
  if( $api_key == $this->api_key() )
95
  {
96
  return $this->user_data( 'nua_user_approved' );
100
  public function user_denied( $request )
101
  {
102
  $api_key = $request->get_param( 'api_key' );
103
+
104
  if( $api_key == null )
105
  return new \WP_Error( 400, __( 'Required Parameter Missing', 'new-user-approve' ), 'api_key required' );
106
+
107
  if( $api_key != $this->api_key() )
108
  return new \WP_Error( 400, __( 'Invalid API Key', 'new-user-approve' ), 'invalid api_key' );
109
+
110
  if( $api_key == $this->api_key() )
111
  {
112
  return $this->user_data( 'nua_user_denied' );
122
  $data = array();
123
 
124
  $time_key = $option_name == 'nua_user_approved' ? 'approval_time' : 'denial_time';
125
+
126
  foreach( $user_data as $key => $value )
127
  {
128
  $user_id = $value['user_id'];
129
 
130
  $user = get_userdata( $user_id );
131
+
132
  $data[] = array(
133
  'id' => $value['id'],
134
  'user_login' => $user->user_login,
138
  $time_key => date( DATE_ISO8601, $value['time'] )
139
  );
140
  }
141
+
142
  return apply_filters( "{$option_name}_zapier", $data );
143
  }
144
  }
localization/new-user-approve-fr_FR.mo CHANGED
Binary file
localization/new-user-approve-fr_FR.po CHANGED
@@ -3,337 +3,592 @@ msgstr ""
3
  "Project-Id-Version: New User Approve 1.0\n"
4
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/new-user-approve\n"
5
  "POT-Creation-Date: 2014-10-08 23:50-0700\n"
6
- "PO-Revision-Date: 2014-12-31 00:55-0700\n"
7
- "Last-Translator: Josh Harrison <josh@picklewagon.com>\n"
8
- "Language-Team: Philippe Scoffoni <philippe@scoffoni.net>\n"
9
- "Language: fr\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
- "X-Generator: Poedit 1.5.7\n"
14
  "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
15
 
16
- #: ../new-user-approve.php:98
17
- #, php-format
18
- msgid "New User Approve requires WordPress %s or newer."
19
- msgstr "New User Approve nécessite WordPress en version %s ou supérieure."
20
-
21
- #: ../new-user-approve.php:145
22
- #, php-format
23
  msgid ""
24
- "The Membership setting must be turned on in order for the New User Approve "
25
- "to work correctly. <a href=\"%1$s\">Update in settings</a>. | <a href=\"%2$s"
26
- "\">Hide Notice</a>"
 
27
  msgstr ""
28
 
29
- #: ../new-user-approve.php:257
30
- msgid "<strong>ERROR</strong>: Your account is still pending approval."
 
 
 
 
 
 
 
 
31
  msgstr ""
32
- "<strong>ERREUR</strong>&nbsp;: Votre compte est toujours en attente "
33
- "d'approbation."
34
 
35
- #: ../new-user-approve.php:260
 
 
 
 
 
 
36
  msgid ""
37
  "<strong>ERROR</strong>: Your account has been denied access to this site."
38
  msgstr ""
39
  "<strong>ERREUR</strong>&nbsp;: Votre compte n'a pas été autorisé à accéder à "
40
  "ce site."
41
 
42
- #: ../new-user-approve.php:362
43
- msgid "Users"
44
- msgstr "Utilisateurs"
45
-
46
- #: ../new-user-approve.php:392
47
- #, php-format
48
- msgid "[%s] User Approval"
49
- msgstr "[%s] Demande d'approbation pour un utilisateur"
50
-
51
- #: ../new-user-approve.php:454
52
- #, php-format
53
- msgid ""
54
- "<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a "
55
- "href=\"mailto:%s\">webmaster</a> !"
56
  msgstr ""
57
- "<strong>ERREUR</strong>&nbsp;: Il n'a pas été possible de vous enregistrer. "
58
- "Veuillez contacter le <a href=\"mailto:%s\">webmestre</a>du site !"
59
 
60
- #: ../new-user-approve.php:520
61
  #, php-format
62
  msgid "[%s] Registration Approved"
63
  msgstr "[%s] Inscription approuvée"
64
 
65
- #: ../new-user-approve.php:550
66
  #, php-format
67
  msgid "[%s] Registration Denied"
68
  msgstr "[%s] Inscription refusée"
69
 
70
- #: ../new-user-approve.php:614
71
- msgid "Registration successful."
72
- msgstr "Inscription réussie."
 
73
 
74
- #: ../new-user-approve.php:617
75
- msgid "Pending Approval"
76
- msgstr "Approbation en attente"
77
 
78
- #: ../admin/templates/approve.php:6
79
- msgid "User successfully updated."
80
- msgstr "Utilisateur correctement mis à jour."
81
 
82
- #: ../admin/templates/approve.php:11
83
- msgid "User Registration Approval"
84
- msgstr "Validation des utilisateurs enregistrés"
85
 
86
- #: ../includes/admin-approve.php:50
87
- msgid "Approve New Users"
88
- msgstr "Approuver les nouveaux utilisateurs"
89
 
90
- #: ../includes/admin-approve.php:82
91
- msgid "Username"
92
- msgstr "Nom de compte"
 
 
93
 
94
- #: ../includes/admin-approve.php:83
95
- msgid "Name"
96
- msgstr "Nom"
97
 
98
- #: ../includes/admin-approve.php:84
99
- msgid "E-mail"
100
- msgstr "Courriel"
 
 
 
 
 
101
 
102
- #: ../includes/admin-approve.php:86 ../includes/admin-approve.php:88
103
- msgid "Actions"
104
- msgstr "Actions"
 
105
 
106
- #: ../includes/admin-approve.php:129
107
- msgid "email:"
108
- msgstr "courriel :"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
- #: ../includes/admin-approve.php:133 ../includes/user-list.php:97
111
- #: ../includes/user-list.php:223 ../includes/user-list.php:224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  msgid "Approve"
113
  msgstr "Approuver"
114
 
115
- #: ../includes/admin-approve.php:138 ../includes/user-list.php:98
116
- #: ../includes/user-list.php:226 ../includes/user-list.php:227
117
- msgid "Deny"
118
- msgstr "Refuser"
119
 
120
- #: ../includes/admin-approve.php:154
 
 
 
 
 
121
  msgid "approved"
122
  msgstr "approuvé"
123
 
124
- #: ../includes/admin-approve.php:156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  msgid "denied"
126
  msgstr "refusé"
127
 
128
- #: ../includes/admin-approve.php:158
129
- msgid "pending"
130
- msgstr "en attente"
131
 
132
- #: ../includes/admin-approve.php:161
133
- #, php-format
134
- msgid "There are no users with a status of %s"
135
- msgstr "Il n'y a aucun utilisateur avec le status %s"
136
 
137
- #: ../includes/admin-approve.php:197
138
- #, php-format
139
- msgid ""
140
- "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
141
- "| <a href=\"%2$s\">Hide Notice</a>"
142
- msgstr ""
143
- "Vous pouvez désormais mettre à jour le statut des utilisateurs depuis la <a "
144
- "href=\"%1$s\">page de gestion des utilisateurs</a>. | <a href=\"%2$s"
145
- "\">Masquer cette note</a>"
146
 
147
- #: ../includes/admin-approve.php:220
148
- #, fuzzy
149
- msgid "Approve Users"
150
- msgstr "Utilisateurs approuvés"
151
 
152
- #: ../includes/admin-approve.php:221
153
- msgid "Updates"
154
- msgstr ""
155
 
156
- #: ../includes/admin-approve.php:222
157
- msgid "Support"
158
- msgstr ""
 
 
 
 
159
 
160
- #: ../includes/admin-approve.php:223
 
 
 
 
 
 
 
 
 
 
 
 
161
  msgid "Feedback"
162
  msgstr ""
 
 
163
 
164
- #: ../includes/admin-approve.php:231
165
- msgid "Users Pending Approval"
166
- msgstr "Utilisateurs en attente d'approbation"
167
-
168
- #: ../includes/admin-approve.php:233
169
- msgid "Approved Users"
170
- msgstr "Utilisateurs approuvés"
171
 
172
- #: ../includes/admin-approve.php:235
173
- msgid "Denied Users"
174
- msgstr "Utilisateurs refusés"
 
 
175
 
176
- #: ../includes/email-tags.php:235
177
- msgid "The user's username on the site as well as the Username label"
178
  msgstr ""
 
 
179
 
180
- #: ../includes/email-tags.php:241
181
- msgid "The user's email address"
182
  msgstr ""
183
 
184
- #: ../includes/email-tags.php:247
185
- msgid "Your site name"
186
  msgstr ""
187
 
188
- #: ../includes/email-tags.php:253
189
- msgid "Your site URL"
 
 
 
 
 
 
 
 
 
 
190
  msgstr ""
 
 
191
 
192
- #: ../includes/email-tags.php:259
193
- msgid "The URL to approve/deny users"
 
 
194
  msgstr ""
 
 
195
 
196
- #: ../includes/email-tags.php:265
197
- msgid "The URL to login to the site"
 
 
 
 
198
  msgstr ""
 
 
199
 
200
- #: ../includes/email-tags.php:271
201
- msgid "Generates the password for the user to add to the email"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  msgstr ""
203
 
204
- #: ../includes/email-tags.php:299
205
  #, php-format
206
- msgid "Username: %s"
207
- msgstr "Nom de compte : %s"
 
 
 
 
208
 
209
- #: ../includes/email-tags.php:390
210
  #, php-format
211
  msgid "Password: %s"
212
  msgstr "Mot de passe : %s"
213
 
214
- #: ../includes/messages.php:9
215
- #, fuzzy
216
- msgid "You have been approved to access {sitename}"
217
- msgstr "Votre inscription a été acceptée pour accéder au site %s"
218
 
219
- #: ../includes/messages.php:25
220
- #, fuzzy
221
- msgid "You have been denied access to {sitename}."
222
- msgstr "Désolé, votre inscription pour accéder au site « %s » a été refusée."
 
 
 
223
 
224
- #: ../includes/messages.php:38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  msgid ""
226
- "An email has been sent to the site administrator. The administrator will "
227
- "review the information that has been submitted and either approve or deny "
228
- "your request."
229
  msgstr ""
230
- "Un courriel a été envoyé à l'administrateur du site. Il va vérifier les "
231
- "informations que vous avez transmises et approuver ou refuser votre demande "
232
- "d'inscription. "
233
 
234
- #: ../includes/messages.php:40
235
  msgid ""
236
- "You will receive an email with instructions on what you will need to do "
237
- "next. Thanks for your patience."
 
238
  msgstr ""
239
- "Vous allez recevoir un courriel avec les instructions sur ce que vous devrez "
240
- "faire ensuite. Merci de votre patience."
 
241
 
242
- #: ../includes/messages.php:53
243
- #, fuzzy
244
- msgid ""
245
- "Welcome to {sitename}. This site is accessible to approved users only. To be "
246
- "approved, you must first register."
247
  msgstr ""
248
- "Bienvenue sur le site %s. Ce site est accessible aux utilisateurs approuvés. "
249
- "Pour être approuvé, vous devez d'abord vous inscrire."
250
 
251
- #: ../includes/messages.php:66
252
- #, fuzzy
253
- msgid "{username} ({user_email}) has requested a username at {sitename}"
254
- msgstr "%1$s (%2$s) a demandé l'approbation d'un compte sur %3$s"
255
 
256
- #: ../includes/messages.php:68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  #, fuzzy
258
  msgid "To approve or deny this user access to {sitename} go to"
259
  msgstr "Pour approuver ou refuser cet utilisateur, aller sur le site %s"
260
 
261
- #: ../includes/messages.php:83
262
- msgid ""
263
- "After you register, your request will be sent to the site administrator for "
264
- "approval. You will then receive an email with further instructions."
265
  msgstr ""
266
- "Après l'inscription, votre demande sera envoyée à l'administrateur pour "
267
- "approbation. Vous recevrez alors un courriel avec les informations "
268
- "supplémentaires."
269
 
270
- #: ../includes/user-list.php:120
271
- msgid "Status"
272
- msgstr "Statut"
273
 
274
- #: ../includes/user-list.php:156
275
- msgid "Filter"
276
- msgstr "Filtrer"
277
 
278
- #: ../includes/user-list.php:161 ../includes/user-list.php:163
279
- msgid "View all users"
280
- msgstr "Voir tous les utilisateurs"
281
 
282
- #: ../includes/user-list.php:320
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  #, php-format
284
  msgid "User denied."
285
  msgid_plural "%s users denied."
286
  msgstr[0] "Utilisateur refusé."
287
  msgstr[1] "%s utilisateurs refusés."
288
 
289
- #: ../includes/user-list.php:325
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  #, php-format
291
- msgid "User approved."
292
- msgid_plural "%s users approved."
293
- msgstr[0] "Utilisateur approuvé."
294
- msgstr[1] "%s utilisateurs approuvés."
295
 
296
- #: ../includes/user-list.php:349
297
- msgid "Access Status"
298
- msgstr "Statut d'accès"
299
 
300
- #: ../includes/user-list.php:354
301
- msgid "-- Status --"
302
- msgstr "-- Statut --"
303
 
304
- #: ../includes/user-list.php:362
305
- msgid "If user has access to sign in or not."
306
- msgstr "Indique si l'utilisateur est autorisé à se connecter ou non."
307
 
308
- #: ../includes/user-list.php:365
309
- msgid "Current user status is <strong>pending</strong>."
310
- msgstr "Le statut de l'utilisateur actuel est <strong>en attente</strong>."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
- #~ msgid "Settings"
313
- #~ msgstr "Paramètres"
 
314
 
315
- #~ msgid "User Management"
316
- #~ msgstr "Gestion des utilisateurs"
 
 
 
 
 
 
 
317
 
318
- #~ msgid "ID"
319
- #~ msgstr "ID"
 
 
320
 
321
- #~ msgid "User name already exists"
322
- #~ msgstr "Nom d'utilisateur déjà existant"
 
 
 
 
 
 
 
 
323
 
324
- #~ msgid "http://www.picklewagon.com/wordpress/new-user-approve"
325
- #~ msgstr "http://www.picklewagon.com/wordpress/new-user-approve"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
- #~ msgid ""
328
- #~ "This plugin allows administrators to approve users once they register. "
329
- #~ "Only approved users will be allowed to access the blog."
330
- #~ msgstr ""
331
- #~ "Cette extension permet aux administrateurs d'approuver les utilisateurs "
332
- #~ "après leur inscription. Seuls les utilisateurs approuvés seront autorisés "
333
- #~ "à accéder au blog."
334
 
335
- #~ msgid "Josh Harrison"
336
- #~ msgstr "Josh Harrison"
 
337
 
338
- #~ msgid "http://www.picklewagon.com/"
339
- #~ msgstr "http://www.picklewagon.com/"
 
 
 
 
 
 
 
 
 
 
3
  "Project-Id-Version: New User Approve 1.0\n"
4
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/new-user-approve\n"
5
  "POT-Creation-Date: 2014-10-08 23:50-0700\n"
6
+ "PO-Revision-Date: 2022-07-19 12:12+0000\n"
7
+ "Last-Translator: \n"
8
+ "Language-Team: French (France)\n"
9
+ "Language: fr_FR\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Loco https://localise.biz/\n"
14
  "Plural-Forms: nplurals=2; plural=(n > 1);\n"
15
+ "X-Loco-Version: 2.6.2; wp-6.0.1"
16
 
17
+ #: new-user-approve.php:959
 
 
 
 
 
 
18
  msgid ""
19
+ " To start using New User Approve Options, please <a href=\"https://users."
20
+ "freemius.com\" target=\"_blank\"> login to your freemius account</a> in "
21
+ "order to download the premium version <br /> For more details <a "
22
+ "target=\"_blank\" href=\"https://newuserapprove.com/\">Click here</a>!"
23
  msgstr ""
24
 
25
+ #: includes/user-list.php:388
26
+ msgid "-- Status --"
27
+ msgstr "-- Statut --"
28
+
29
+ #: includes/invitation-code.php:582
30
+ msgid "<strong>ERROR</strong>: Please add an Invitation code."
31
+ msgstr "<strong>ERREUR</strong> : veuillez ajouter un code d'invitation."
32
+
33
+ #: includes/invitation-code.php:579
34
+ msgid "<strong>ERROR</strong>: The Invitation code is invalid"
35
  msgstr ""
36
+ "\n"
37
+ "<strong>ERREUR</strong> : le code d'invitation n'est pas valide"
38
 
39
+ #: new-user-approve.php:825
40
+ msgid "<strong>ERROR</strong>: User has not been approved."
41
+ msgstr ""
42
+ "\n"
43
+ "<strong>ERREUR</strong> : l'utilisateur n'a pas été approuvé."
44
+
45
+ #: new-user-approve.php:347
46
  msgid ""
47
  "<strong>ERROR</strong>: Your account has been denied access to this site."
48
  msgstr ""
49
  "<strong>ERREUR</strong>&nbsp;: Votre compte n'a pas été autorisé à accéder à "
50
  "ce site."
51
 
52
+ #: new-user-approve.php:342
53
+ msgid "<strong>ERROR</strong>: Your account is still pending approval."
 
 
 
 
 
 
 
 
 
 
 
 
54
  msgstr ""
55
+ "<strong>ERREUR</strong>&nbsp;: Votre compte est toujours en attente "
56
+ "d'approbation."
57
 
58
+ #: new-user-approve.php:698
59
  #, php-format
60
  msgid "[%s] Registration Approved"
61
  msgstr "[%s] Inscription approuvée"
62
 
63
+ #: new-user-approve.php:728
64
  #, php-format
65
  msgid "[%s] Registration Denied"
66
  msgstr "[%s] Inscription refusée"
67
 
68
+ #: new-user-approve.php:559
69
+ #, php-format
70
+ msgid "[%s] User Approval"
71
+ msgstr "[%s] Demande d'approbation pour un utilisateur"
72
 
73
+ #: includes/user-list.php:383
74
+ msgid "Access Status"
75
+ msgstr "Statut d'accès"
76
 
77
+ #: includes/admin-approve.php:136 includes/admin-approve.php:138
78
+ msgid "Action"
79
+ msgstr ""
80
 
81
+ #: includes/invitation-code.php:693
82
+ msgid "Actions"
83
+ msgstr "Actions"
84
 
85
+ #: includes/invitation-code.php:187 includes/invitation-code.php:293
86
+ msgid "Add Codes"
87
+ msgstr "Ajouter des codes"
88
 
89
+ #: includes/invitation-code.php:145
90
+ msgid "Add New"
91
+ msgstr ""
92
+ "\n"
93
+ "Ajouter nouveau"
94
 
95
+ #: includes/invitation-code.php:146
96
+ msgid "Add New Invitation Code"
97
+ msgstr "Ajouter un nouveau code d'invitation"
98
 
99
+ #: includes/messages.php:104
100
+ msgid ""
101
+ "After you register, your request will be sent to the site administrator for "
102
+ "approval. You will then receive an email with further instructions."
103
+ msgstr ""
104
+ "Après l'inscription, votre demande sera envoyée à l'administrateur pour "
105
+ "approbation. Vous recevrez alors un courriel avec les informations "
106
+ "supplémentaires."
107
 
108
+ #: includes/invitation-code.php:125 includes/invitation-code.php:143
109
+ #: includes/invitation-code.php:144
110
+ msgid "All Codes"
111
+ msgstr "Tous les codes"
112
 
113
+ #: includes/invitation-code.php:150
114
+ msgid "All Invitation Code"
115
+ msgstr ""
116
+ "\n"
117
+ "Tous les codes d'invitation"
118
+
119
+ #. Description of the plugin
120
+ msgid ""
121
+ "Allow administrators to approve users once they register. Only approved "
122
+ "users will be allowed to access the site. For support, please go to the <a "
123
+ "href=\"http://wordpress.org/support/plugin/new-user-approve\">support "
124
+ "forums</a> on wordpress.org."
125
+ msgstr ""
126
+ "Autorisez les administrateurs à approuver les utilisateurs une fois qu'ils "
127
+ "sont enregistrés. Seuls les utilisateurs autorisés seront autorisés à "
128
+ "accéder au site. Pour obtenir de l'aide, veuillez vous rendre sur les <a "
129
+ "href=\"http://wordpress.org/support/plugin/new-user-approve\">forums "
130
+ "d'assistance</a> sur wordpress.org.\n"
131
 
132
+ #: includes/messages.php:41
133
+ msgid ""
134
+ "An email has been sent to the site administrator. The administrator will "
135
+ "review the information that has been submitted and either approve or deny "
136
+ "your request."
137
+ msgstr ""
138
+ "Un courriel a été envoyé à l'administrateur du site. Il va vérifier les "
139
+ "informations que vous avez transmises et approuver ou refuser votre demande "
140
+ "d'inscription."
141
+
142
+ #: includes/admin-approve.php:397
143
+ msgid "API Key: "
144
+ msgstr ""
145
+ "\n"
146
+ "Clé API:"
147
+
148
+ #: includes/admin-approve.php:191 includes/user-list.php:104
149
+ #: includes/user-list.php:257 includes/user-list.php:258
150
  msgid "Approve"
151
  msgstr "Approuver"
152
 
153
+ #: includes/admin-approve.php:66
154
+ msgid "Approve New Users"
155
+ msgstr "Approuver les nouveaux utilisateurs"
 
156
 
157
+ #: includes/admin-approve.php:287
158
+ #, fuzzy
159
+ msgid "Approve Users"
160
+ msgstr "Utilisateurs approuvés"
161
+
162
+ #: includes/admin-approve.php:211 includes/user-list.php:150
163
  msgid "approved"
164
  msgstr "approuvé"
165
 
166
+ #: includes/admin-approve.php:121 includes/admin-approve.php:308
167
+ msgid "Approved Users"
168
+ msgstr "Utilisateurs approuvés"
169
+
170
+ #: includes/invitation-code.php:203
171
+ msgid "Auto Generate"
172
+ msgstr "Génération automatique"
173
+
174
+ #: includes/user-list.php:399
175
+ msgid "Current user status is <strong>pending</strong>."
176
+ msgstr "Le statut de l'utilisateur actuel est <strong>en attente</strong>."
177
+
178
+ #: includes/invitation-code.php:425
179
+ msgid "Date"
180
+ msgstr ""
181
+
182
+ #: includes/invitation-code.php:723
183
+ msgid "Deactivate"
184
+ msgstr ""
185
+ "\n"
186
+ "Désactiver"
187
+
188
+ #: includes/invitation-code.php:723
189
+ msgid "Delete"
190
+ msgstr "Effacer"
191
+
192
+ #: includes/admin-approve.php:213 includes/user-list.php:152
193
  msgid "denied"
194
  msgstr "refusé"
195
 
196
+ #: includes/admin-approve.php:117 includes/admin-approve.php:310
197
+ msgid "Denied Users"
198
+ msgstr "Utilisateurs refusés"
199
 
200
+ #: includes/admin-approve.php:195 includes/user-list.php:105
201
+ #: includes/user-list.php:260 includes/user-list.php:261
202
+ msgid "Deny"
203
+ msgstr "Refuser"
204
 
205
+ #: includes/admin-approve.php:134
206
+ msgid "E-mail"
207
+ msgstr "Courriel"
 
 
 
 
 
 
208
 
209
+ #: includes/invitation-code.php:723
210
+ msgid "Edit"
211
+ msgstr "Éditer"
 
212
 
213
+ #: includes/invitation-code.php:148
214
+ msgid "Edit Invitation Code"
215
+ msgstr "Modifier le code d'invitation"
216
 
217
+ #: includes/invitation-code.php:191
218
+ msgid "Email"
219
+ msgstr "E-mail"
220
+
221
+ #: includes/admin-approve.php:188
222
+ msgid "email:"
223
+ msgstr "courriel :"
224
 
225
+ #: includes/invitation-code.php:298
226
+ msgid "Enter one code per line."
227
+ msgstr "Entrez un code par ligne."
228
+
229
+ #: includes/invitation-code.php:691
230
+ msgid "Expiry"
231
+ msgstr "Expiration"
232
+
233
+ #: includes/invitation-code.php:310
234
+ msgid "Expiry Date"
235
+ msgstr "Date d'expiration"
236
+
237
+ #: includes/admin-approve.php:289
238
  msgid "Feedback"
239
  msgstr ""
240
+ "\n"
241
+ "Retour d'information"
242
 
243
+ #: includes/user-list.php:173
244
+ msgid "Filter"
245
+ msgstr "Filtrer"
 
 
 
 
246
 
247
+ #: includes/email-tags.php:277
248
+ msgid "Generates the password for the user to add to the email"
249
+ msgstr ""
250
+ "\n"
251
+ "Génère le mot de passe que l'utilisateur doit ajouter à l'e-mail"
252
 
253
+ #: includes/messages.php:112
254
+ msgid "Hello,"
255
  msgstr ""
256
+ "\n"
257
+ "Bonjour,"
258
 
259
+ #. URI of the plugin
260
+ msgid "http://newuserapprove.com/"
261
  msgstr ""
262
 
263
+ #. Author URI of the plugin
264
+ msgid "https://newuserapprove.com/"
265
  msgstr ""
266
 
267
+ #: includes/user-list.php:396
268
+ msgid "If user has access to sign in or not."
269
+ msgstr "Indique si l'utilisateur est autorisé à se connecter ou non."
270
+
271
+ #: includes/invitation-code.php:190
272
+ msgid "Import Codes"
273
+ msgstr "Codes d'importation"
274
+
275
+ #: includes/zapier/includes/rest-api.php:78
276
+ #: includes/zapier/includes/rest-api.php:89
277
+ #: includes/zapier/includes/rest-api.php:105
278
+ msgid "Invalid API Key"
279
  msgstr ""
280
+ "\n"
281
+ "Clé API invalide"
282
 
283
+ #: includes/invitation-code.php:123 includes/invitation-code.php:141
284
+ #: includes/invitation-code.php:142 includes/invitation-code.php:412
285
+ #: includes/invitation-code.php:521 includes/invitation-code.php:689
286
+ msgid "Invitation Code"
287
  msgstr ""
288
+ "\n"
289
+ "code d'invitation"
290
 
291
+ #: includes/invitation-code.php:392
292
+ msgid "Invitation code for new user"
293
+ msgstr "Code d'invitation pour nouvel utilisateur"
294
+
295
+ #: includes/invitation-code.php:747
296
+ msgid "Invitation Code for user to register"
297
  msgstr ""
298
+ "\n"
299
+ "Code d'invitation permettant à l'utilisateur de s'inscrire"
300
 
301
+ #: includes/invitation-code.php:183
302
+ msgid "Invitation Code Settings"
303
+ msgstr "Paramètres du code d'invitation"
304
+
305
+ #: includes/invitation-code.php:202
306
+ msgid "Manual Generate"
307
+ msgstr "Génération manuelle"
308
+
309
+ #: includes/admin-approve.php:133
310
+ msgid "Name"
311
+ msgstr "Nom"
312
+
313
+ #: includes/invitation-code.php:147
314
+ msgid "New Invitation Code"
315
+ msgstr "Nouveau code d'invitation"
316
+
317
+ #. Name of the plugin
318
+ msgid "New User Approve"
319
  msgstr ""
320
 
321
+ #: new-user-approve.php:169
322
  #, php-format
323
+ msgid "New User Approve requires WordPress %s or newer."
324
+ msgstr "New User Approve nécessite WordPress en version %s ou supérieure."
325
+
326
+ #: includes/invitation-code.php:476
327
+ msgid "No User Found"
328
+ msgstr "Aucun utilisateur trouvé"
329
 
330
+ #: includes/email-tags.php:396
331
  #, php-format
332
  msgid "Password: %s"
333
  msgstr "Mot de passe : %s"
334
 
335
+ #: includes/admin-approve.php:215 includes/user-list.php:154
336
+ msgid "pending"
337
+ msgstr "en attente"
 
338
 
339
+ #: new-user-approve.php:794
340
+ msgid "Pending Approval"
341
+ msgstr "Approbation en attente"
342
+
343
+ #: includes/admin-approve.php:125 includes/admin-approve.php:306
344
+ msgid "Pending Users"
345
+ msgstr "Utilisateurs en attente"
346
 
347
+ #: includes/admin-approve.php:314
348
+ msgid "Pro Features"
349
+ msgstr "Fonctionnalités professionnelles"
350
+
351
+ #: new-user-approve.php:790
352
+ msgid "Registration successful."
353
+ msgstr "Inscription réussie."
354
+
355
+ #: includes/zapier/includes/rest-api.php:75
356
+ #: includes/zapier/includes/rest-api.php:86
357
+ #: includes/zapier/includes/rest-api.php:102
358
+ msgid "Required Parameter Missing"
359
+ msgstr "Paramètre requis manquant"
360
+
361
+ #: includes/invitation-code.php:189
362
+ msgid "Settings"
363
+ msgstr "Réglages"
364
+
365
+ #: includes/invitation-code.php:429 includes/invitation-code.php:692
366
+ #: includes/user-list.php:127
367
+ msgid "Status"
368
+ msgstr "Statut"
369
+
370
+ #: includes/admin-approve.php:288
371
+ msgid "Support"
372
+ msgstr "Soutien"
373
+
374
+ #: includes/messages.php:118
375
+ msgid "Thank You"
376
+ msgstr "Merci"
377
+
378
+ #: includes/messages.php:114
379
  msgid ""
380
+ "Thank you for registering on our site. We have successfully received your "
381
+ "request and is currently pending for approval."
 
382
  msgstr ""
383
+ "Merci de vous être inscrit sur notre site. Nous avons bien reçu votre "
384
+ "demande et sommes actuellement en attente d'approbation."
 
385
 
386
+ #: includes/messages.php:116
387
  msgid ""
388
+ "The administrator will review the information that has been submitted after "
389
+ "which they will either approve or deny your request. You will receive an "
390
+ "email with the instructions on what you will need to do next."
391
  msgstr ""
392
+ "L'administrateur examinera les informations qui ont été soumises, après quoi "
393
+ "il approuvera ou refusera votre demande. Vous recevrez un e-mail avec les "
394
+ "instructions sur ce que vous devrez faire ensuite."
395
 
396
+ #: includes/email-tags.php:271
397
+ msgid "The URL for a user to set/reset their password"
 
 
 
398
  msgstr ""
399
+ "L'URL permettant à un utilisateur de définir/réinitialiser son mot de passe"
 
400
 
401
+ #: includes/email-tags.php:259
402
+ msgid "The URL to approve/deny users"
403
+ msgstr "L'URL pour approuver/refuser les utilisateurs"
 
404
 
405
+ #: includes/email-tags.php:265
406
+ msgid "The URL to login to the site"
407
+ msgstr "L'URL pour se connecter au site"
408
+
409
+ #: includes/email-tags.php:241
410
+ msgid "The user's email address"
411
+ msgstr "L'adresse e-mail de l'utilisateur"
412
+
413
+ #: includes/email-tags.php:235
414
+ msgid "The user's username on the site as well as the Username label"
415
+ msgstr ""
416
+ "Le nom d'utilisateur de l'utilisateur sur le site ainsi que le libellé Nom "
417
+ "d'utilisateur"
418
+
419
+ #: includes/admin-approve.php:220
420
+ #, php-format
421
+ msgid "There are no users with a status of %s"
422
+ msgstr "Il n'y a aucun utilisateur avec le status %s"
423
+
424
+ #: includes/messages.php:89
425
  #, fuzzy
426
  msgid "To approve or deny this user access to {sitename} go to"
427
  msgstr "Pour approuver ou refuser cet utilisateur, aller sur le site %s"
428
 
429
+ #: includes/messages.php:12
430
+ msgid "To set or reset your password, visit the following address:"
 
 
431
  msgstr ""
432
+ "Pour définir ou réinitialiser votre mot de passe, rendez-vous à l'adresse "
433
+ "suivante :"
 
434
 
435
+ #: includes/admin-approve.php:411
436
+ msgid "Triggers"
437
+ msgstr "Déclencheurs"
438
 
439
+ #: includes/admin-approve.php:379
440
+ msgid "Triggers when a user is Approved."
441
+ msgstr "Se déclenche lorsqu'un utilisateur est approuvé."
442
 
443
+ #: includes/admin-approve.php:380
444
+ msgid "Triggers when a user is Denied."
445
+ msgstr "Se déclenche lorsqu'un utilisateur est refusé."
446
 
447
+ #: includes/admin-approve.php:67
448
+ msgid "Upgrade"
449
+ msgstr "Mise à niveau"
450
+
451
+ #: includes/invitation-code.php:302 includes/invitation-code.php:421
452
+ msgid "Usage Limit"
453
+ msgstr "Limite d'utilisation"
454
+
455
+ #: includes/user-list.php:359
456
+ #, php-format
457
+ msgid "User approved."
458
+ msgid_plural "%s users approved."
459
+ msgstr[0] "Utilisateur approuvé."
460
+ msgstr[1] "%s utilisateurs approuvés."
461
+
462
+ #: includes/user-list.php:354
463
  #, php-format
464
  msgid "User denied."
465
  msgid_plural "%s users denied."
466
  msgstr[0] "Utilisateur refusé."
467
  msgstr[1] "%s utilisateurs refusés."
468
 
469
+ #: includes/invitation-code.php:469
470
+ msgid "User Not Found"
471
+ msgstr "Utilisateur non trouvé"
472
+
473
+ #: admin/templates/approve.php:11
474
+ msgid "User Registration Approval"
475
+ msgstr "Validation des utilisateurs enregistrés"
476
+
477
+ #: admin/templates/approve.php:6
478
+ msgid "User successfully updated."
479
+ msgstr "Utilisateur correctement mis à jour."
480
+
481
+ #: includes/admin-approve.php:132
482
+ msgid "Username"
483
+ msgstr "Nom de compte"
484
+
485
+ #: includes/email-tags.php:305
486
  #, php-format
487
+ msgid "Username: %s"
488
+ msgstr "Nom de compte : %s"
 
 
489
 
490
+ #: new-user-approve.php:522
491
+ msgid "Users"
492
+ msgstr "Utilisateurs"
493
 
494
+ #: includes/invitation-code.php:441
495
+ msgid "Users that have registered by using this invitation code"
496
+ msgstr "Utilisateurs qui se sont inscrits en utilisant ce code d'invitation"
497
 
498
+ #: includes/invitation-code.php:417
499
+ msgid "Uses left"
500
+ msgstr "Utilisations restantes"
501
 
502
+ #: includes/invitation-code.php:690
503
+ msgid "Uses Remaining"
504
+ msgstr "Utilisations restantes"
505
+
506
+ #: includes/user-list.php:177 includes/user-list.php:179
507
+ msgid "View all users"
508
+ msgstr "Voir tous les utilisateurs"
509
+
510
+ #: includes/invitation-code.php:149
511
+ msgid "View Invitation Code"
512
+ msgstr "Afficher le code d'invitation"
513
+
514
+ #: includes/admin-approve.php:393
515
+ msgid "Website URL: "
516
+ msgstr "URL de site web:"
517
+
518
+ #: includes/messages.php:74
519
+ #, fuzzy
520
+ msgid ""
521
+ "Welcome to {sitename}. This site is accessible to approved users only. To be "
522
+ "approved, you must first register."
523
+ msgstr ""
524
+ "Bienvenue sur le site %s. Ce site est accessible aux utilisateurs approuvés. "
525
+ "Pour être approuvé, vous devez d'abord vous inscrire."
526
 
527
+ #. Author of the plugin
528
+ msgid "WPExpertsio"
529
+ msgstr ""
530
 
531
+ #: includes/admin-approve.php:260
532
+ #, php-format
533
+ msgid ""
534
+ "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
535
+ "| <a href=\"%2$s\">Hide Notice</a>"
536
+ msgstr ""
537
+ "Vous pouvez désormais mettre à jour le statut des utilisateurs depuis la <a "
538
+ "href=\"%1$s\">page de gestion des utilisateurs</a>. | <a href=\"%2$s\">"
539
+ "Masquer cette note</a>"
540
 
541
+ #: includes/messages.php:9
542
+ #, fuzzy
543
+ msgid "You have been approved to access {sitename}"
544
+ msgstr "Votre inscription a été acceptée pour accéder au site %s"
545
 
546
+ #: includes/messages.php:53
547
+ msgid ""
548
+ "You have been approved to access {sitename}. You will receive an email with "
549
+ "instructions on what you will need to do next. Thanks for your patience.\n"
550
+ "\n"
551
+ "\t"
552
+ msgstr ""
553
+ "Vous avez été autorisé à accéder à {sitename}. Vous recevrez un e-mail avec "
554
+ "des instructions sur ce que vous devrez faire ensuite. Merci pour votre "
555
+ "patience."
556
 
557
+ #: includes/messages.php:28
558
+ #, fuzzy
559
+ msgid "You have been denied access to {sitename}."
560
+ msgstr "Désolé, votre inscription pour accéder au site « %s » a été refusée."
561
+
562
+ #: includes/messages.php:43 includes/messages.php:57
563
+ msgid ""
564
+ "You will receive an email with instructions on what you will need to do next."
565
+ " Thanks for your patience."
566
+ msgstr ""
567
+ "Vous allez recevoir un courriel avec les instructions sur ce que vous devrez "
568
+ "faire ensuite. Merci de votre patience."
569
+
570
+ #: new-user-approve.php:631
571
+ #, php-format
572
+ msgid "Your registration is pending for approval - [%s]"
573
+ msgstr "Votre inscription est en attente d'approbation - [%s]"
574
 
575
+ #: includes/email-tags.php:247
576
+ msgid "Your site name"
577
+ msgstr "Nom de votre site"
 
 
 
 
578
 
579
+ #: includes/email-tags.php:253
580
+ msgid "Your site URL"
581
+ msgstr "URL de votre site"
582
 
583
+ #: includes/admin-approve.php:312
584
+ msgid "Zapier"
585
+ msgstr ""
586
+
587
+ #: includes/admin-approve.php:389
588
+ msgid "Zapier Settings"
589
+ msgstr ""
590
+
591
+ #: includes/messages.php:87
592
+ #, fuzzy
593
+ msgid "{username} ({user_email}) has requested a username at {sitename}"
594
+ msgstr "%1$s (%2$s) a demandé l'approbation d'un compte sur %3$s"
localization/new-user-approve-it_IT.mo CHANGED
Binary file
localization/new-user-approve-it_IT.po CHANGED
@@ -3,327 +3,570 @@ msgstr ""
3
  "Project-Id-Version: New User Approve 1.0\n"
4
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/new-user-approve\n"
5
  "POT-Creation-Date: 2014-10-08 23:50-0700\n"
6
- "PO-Revision-Date: 2014-12-31 00:55-0700\n"
7
- "Last-Translator: Josh Harrison <josh@picklewagon.com>\n"
8
- "Language-Team: Philippe Scoffoni <philippe@scoffoni.net>\n"
9
- "Language: fr\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
- "X-Generator: Poedit 1.5.7\n"
 
 
14
 
15
- #: ../new-user-approve.php:98
16
- #, php-format
17
- msgid "New User Approve requires WordPress %s or newer."
18
- msgstr ""
19
-
20
- #: ../new-user-approve.php:145
21
- #, php-format
22
  msgid ""
23
- "The Membership setting must be turned on in order for the New User Approve "
24
- "to work correctly. <a href=\"%1$s\">Update in settings</a>. | <a href=\"%2$s"
25
- "\">Hide Notice</a>"
 
26
  msgstr ""
27
 
28
- #: ../new-user-approve.php:257
29
- msgid "<strong>ERROR</strong>: Your account is still pending approval."
30
  msgstr ""
31
 
32
- #: ../new-user-approve.php:260
33
- msgid ""
34
- "<strong>ERROR</strong>: Your account has been denied access to this site."
35
- msgstr ""
36
 
37
- #: ../new-user-approve.php:362
38
- msgid "Users"
39
- msgstr "Utenti"
40
 
41
- #: ../new-user-approve.php:392
42
- #, php-format
43
- msgid "[%s] User Approval"
44
- msgstr "[%s] Approvazione Utente"
45
 
46
- #: ../new-user-approve.php:454
47
- #, php-format
48
  msgid ""
49
- "<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a "
50
- "href=\"mailto:%s\">webmaster</a> !"
51
  msgstr ""
 
 
52
 
53
- #: ../new-user-approve.php:520
 
 
 
 
 
54
  #, php-format
55
  msgid "[%s] Registration Approved"
56
  msgstr "[%s] Registrazione Approvata"
57
 
58
- #: ../new-user-approve.php:550
59
  #, php-format
60
  msgid "[%s] Registration Denied"
61
  msgstr "[%s] Registrazione Negata"
62
 
63
- #: ../new-user-approve.php:614
64
- msgid "Registration successful."
65
- msgstr "Registrazione richiesta."
 
66
 
67
- #: ../new-user-approve.php:617
68
- msgid "Pending Approval"
69
- msgstr "Richiesta in Attesa"
70
 
71
- #: ../admin/templates/approve.php:6
72
- msgid "User successfully updated."
73
- msgstr "Utente correttamente aggiornato"
74
 
75
- #: ../admin/templates/approve.php:11
76
- msgid "User Registration Approval"
77
- msgstr "Gestione delle Registrazioni"
78
 
79
- #: ../includes/admin-approve.php:50
80
- msgid "Approve New Users"
81
- msgstr "Gestione Richieste"
82
 
83
- #: ../includes/admin-approve.php:82
84
- msgid "Username"
85
- msgstr "Nome utente"
86
 
87
- #: ../includes/admin-approve.php:83
88
- msgid "Name"
89
- msgstr "Nome"
90
 
91
- #: ../includes/admin-approve.php:84
92
- msgid "E-mail"
93
- msgstr "E-mail"
 
 
 
 
94
 
95
- #: ../includes/admin-approve.php:86 ../includes/admin-approve.php:88
96
- msgid "Actions"
97
- msgstr "Azioni"
 
98
 
99
- #: ../includes/admin-approve.php:129
100
- msgid "email:"
101
- msgstr "email:"
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- #: ../includes/admin-approve.php:133 ../includes/user-list.php:97
104
- #: ../includes/user-list.php:223 ../includes/user-list.php:224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  msgid "Approve"
106
  msgstr "Approva"
107
 
108
- #: ../includes/admin-approve.php:138 ../includes/user-list.php:98
109
- #: ../includes/user-list.php:226 ../includes/user-list.php:227
110
- msgid "Deny"
111
- msgstr "Blocca"
112
 
113
- #: ../includes/admin-approve.php:154
 
 
 
 
 
114
  msgid "approved"
115
  msgstr "approvato"
116
 
117
- #: ../includes/admin-approve.php:156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  msgid "denied"
119
  msgstr "bloccato"
120
 
121
- #: ../includes/admin-approve.php:158
122
- msgid "pending"
123
- msgstr "in attesa"
124
 
125
- #: ../includes/admin-approve.php:161
126
- #, php-format
127
- msgid "There are no users with a status of %s"
128
- msgstr "Non ci sono utenti nello lo stato \"%s\""
129
 
130
- #: ../includes/admin-approve.php:197
131
- #, php-format
132
- msgid ""
133
- "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
134
- "| <a href=\"%2$s\">Hide Notice</a>"
135
- msgstr ""
136
 
137
- #: ../includes/admin-approve.php:220
138
- #, fuzzy
139
- msgid "Approve Users"
140
- msgstr "Utenti Approvati"
141
 
142
- #: ../includes/admin-approve.php:221
143
- msgid "Updates"
144
- msgstr ""
145
 
146
- #: ../includes/admin-approve.php:222
147
- msgid "Support"
148
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
- #: ../includes/admin-approve.php:223
 
 
 
 
151
  msgid "Feedback"
152
  msgstr ""
153
 
154
- #: ../includes/admin-approve.php:231
155
- msgid "Users Pending Approval"
156
- msgstr "Utenti in attesa di Approvazione"
157
 
158
- #: ../includes/admin-approve.php:233
159
- msgid "Approved Users"
160
- msgstr "Utenti Approvati"
161
 
162
- #: ../includes/admin-approve.php:235
163
- msgid "Denied Users"
164
- msgstr "Utenti Bloccati"
165
 
166
- #: ../includes/email-tags.php:235
167
- msgid "The user's username on the site as well as the Username label"
168
  msgstr ""
169
 
170
- #: ../includes/email-tags.php:241
171
- msgid "The user's email address"
172
  msgstr ""
173
 
174
- #: ../includes/email-tags.php:247
175
- msgid "Your site name"
176
  msgstr ""
177
 
178
- #: ../includes/email-tags.php:253
179
- msgid "Your site URL"
180
- msgstr ""
181
 
182
- #: ../includes/email-tags.php:259
183
- msgid "The URL to approve/deny users"
184
- msgstr ""
 
 
185
 
186
- #: ../includes/email-tags.php:265
187
- msgid "The URL to login to the site"
188
- msgstr ""
 
 
189
 
190
- #: ../includes/email-tags.php:271
191
- msgid "Generates the password for the user to add to the email"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  msgstr ""
193
 
194
- #: ../includes/email-tags.php:299
195
  #, php-format
196
- msgid "Username: %s"
197
- msgstr "Nome utente : %s"
198
 
199
- #: ../includes/email-tags.php:390
 
 
 
 
200
  #, php-format
201
  msgid "Password: %s"
202
  msgstr "Password: %s"
203
 
204
- #: ../includes/messages.php:9
205
- #, fuzzy
206
- msgid "You have been approved to access {sitename}"
207
- msgstr "Il vostro accesso a %s e' stato approvato."
208
 
209
- #: ../includes/messages.php:25
210
- #, fuzzy
211
- msgid "You have been denied access to {sitename}."
212
- msgstr "Vi è stato negato l'accesso a %s"
 
 
 
213
 
214
- #: ../includes/messages.php:38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  msgid ""
216
- "An email has been sent to the site administrator. The administrator will "
217
- "review the information that has been submitted and either approve or deny "
218
- "your request."
219
  msgstr ""
220
- "Una email con la vostra richiesta è stata spedita all'amministratore del "
221
- "sito. Dopo averla controllata l'amministratore deciderà se approvarla o "
222
- "negarla."
223
 
224
- #: ../includes/messages.php:40
225
  msgid ""
226
- "You will receive an email with instructions on what you will need to do "
227
- "next. Thanks for your patience."
 
228
  msgstr ""
229
- "Riceverete una email con ulteriori istruzioni su come procedere. Grazie "
230
- "della vostra pazienza. "
 
 
231
 
232
- #: ../includes/messages.php:53
233
- #, fuzzy
234
- msgid ""
235
- "Welcome to {sitename}. This site is accessible to approved users only. To be "
236
- "approved, you must first register."
237
  msgstr ""
238
- "Benvenuto su  %s. Questo sito è accessibile soltanto ad utenti registrati e "
239
- "approvati da un amministratore. Per chiedere un accesso dovete prima "
240
- "registrarvi."
241
 
242
- #: ../includes/messages.php:66
243
- #, fuzzy
244
- msgid "{username} ({user_email}) has requested a username at {sitename}"
245
- msgstr "%1$s (%2$s) ha richiesto un nome utente a %3$s"
 
 
 
 
 
 
 
 
246
 
247
- #: ../includes/messages.php:68
 
 
 
 
 
 
 
 
 
248
  #, fuzzy
249
  msgid "To approve or deny this user access to {sitename} go to"
250
  msgstr "Per approvare o bloccare questo utente a %s vai su"
251
 
252
- #: ../includes/messages.php:83
253
- msgid ""
254
- "After you register, your request will be sent to the site administrator for "
255
- "approval. You will then receive an email with further instructions."
256
  msgstr ""
257
- "Dopo esservi registrati la vostra richiesta sarà spedita ad un "
258
- "amministratore. Riceverete ulteriori istruzioni su come procedere via email."
259
 
260
- #: ../includes/user-list.php:120
261
- msgid "Status"
262
  msgstr ""
263
 
264
- #: ../includes/user-list.php:156
265
- msgid "Filter"
266
  msgstr ""
267
 
268
- #: ../includes/user-list.php:161 ../includes/user-list.php:163
269
- msgid "View all users"
270
  msgstr ""
271
 
272
- #: ../includes/user-list.php:320
273
- #, fuzzy, php-format
274
- msgid "User denied."
275
- msgid_plural "%s users denied."
276
- msgstr[0] "bloccato"
277
- msgstr[1] "bloccato"
 
278
 
279
- #: ../includes/user-list.php:325
280
  #, fuzzy, php-format
281
  msgid "User approved."
282
  msgid_plural "%s users approved."
283
  msgstr[0] "Approvazione Nuovo Utente"
284
  msgstr[1] "Approvazione Nuovo Utente"
285
 
286
- #: ../includes/user-list.php:349
287
- msgid "Access Status"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  msgstr ""
 
 
 
289
 
290
- #: ../includes/user-list.php:354
291
- msgid "-- Status --"
292
  msgstr ""
293
 
294
- #: ../includes/user-list.php:362
295
- msgid "If user has access to sign in or not."
 
 
 
296
  msgstr ""
 
 
 
297
 
298
- #: ../includes/user-list.php:365
299
- msgid "Current user status is <strong>pending</strong>."
 
 
 
 
 
 
 
 
 
300
  msgstr ""
 
 
 
301
 
302
- #~ msgid "Settings"
303
- #~ msgstr "Impostazioni"
 
 
304
 
305
- #~ msgid "User Management"
306
- #~ msgstr "Gestione Utenti"
 
 
 
 
 
307
 
308
- #~ msgid "ID"
309
- #~ msgstr "ID"
 
 
310
 
311
- #~ msgid "User name already exists"
312
- #~ msgstr "L'utente esiste già"
 
 
 
313
 
314
- #~ msgid "http://www.picklewagon.com/wordpress/new-user-approve"
315
- #~ msgstr "http://www.picklewagon.com/wordpress/new-user-approve"
 
 
 
316
 
317
- #~ msgid ""
318
- #~ "This plugin allows administrators to approve users once they register. "
319
- #~ "Only approved users will be allowed to access the blog."
320
- #~ msgstr ""
321
- #~ "Questo plugin permette agli amministratori di approvare le richieste di "
322
- #~ "registrazione degli utenti. Solo gli utenti approvati potranno accedere "
323
- #~ "al blog."
324
 
325
- #~ msgid "Josh Harrison"
326
- #~ msgstr "Josh Harrison"
 
327
 
328
- #~ msgid "http://www.picklewagon.com/"
329
- #~ msgstr "http://www.picklewagon.com/"
 
 
3
  "Project-Id-Version: New User Approve 1.0\n"
4
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/new-user-approve\n"
5
  "POT-Creation-Date: 2014-10-08 23:50-0700\n"
6
+ "PO-Revision-Date: 2022-07-15 07:46+0000\n"
7
+ "Last-Translator: \n"
8
+ "Language-Team: Italiano\n"
9
+ "Language: it_IT\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Loco https://localise.biz/\n"
14
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
15
+ "X-Loco-Version: 2.6.2; wp-6.0.1"
16
 
17
+ #: new-user-approve.php:959
 
 
 
 
 
 
18
  msgid ""
19
+ " To start using New User Approve Options, please <a href=\"https://users."
20
+ "freemius.com\" target=\"_blank\"> login to your freemius account</a> in "
21
+ "order to download the premium version <br /> For more details <a "
22
+ "target=\"_blank\" href=\"https://newuserapprove.com/\">Click here</a>!"
23
  msgstr ""
24
 
25
+ #: includes/user-list.php:388
26
+ msgid "-- Status --"
27
  msgstr ""
28
 
29
+ #: includes/invitation-code.php:582
30
+ msgid "<strong>ERROR</strong>: Please add an Invitation code."
31
+ msgstr "<strong>ERRORE</strong>: aggiungi un codice invito."
 
32
 
33
+ #: includes/invitation-code.php:579
34
+ msgid "<strong>ERROR</strong>: The Invitation code is invalid"
35
+ msgstr "<strong>ERRORE</strong>: il codice di invito non è valido"
36
 
37
+ #: new-user-approve.php:825
38
+ msgid "<strong>ERROR</strong>: User has not been approved."
39
+ msgstr "<strong>ERRORE</strong>: l'utente non è stato approvato."
 
40
 
41
+ #: new-user-approve.php:347
 
42
  msgid ""
43
+ "<strong>ERROR</strong>: Your account has been denied access to this site."
 
44
  msgstr ""
45
+ "<strong>ERRORE</strong>: al tuo account è stato negato l'accesso a questo "
46
+ "sito."
47
 
48
+ #: new-user-approve.php:342
49
+ msgid "<strong>ERROR</strong>: Your account is still pending approval."
50
+ msgstr ""
51
+ "<strong>ERRORE</strong>: il tuo account è ancora in attesa di approvazione."
52
+
53
+ #: new-user-approve.php:698
54
  #, php-format
55
  msgid "[%s] Registration Approved"
56
  msgstr "[%s] Registrazione Approvata"
57
 
58
+ #: new-user-approve.php:728
59
  #, php-format
60
  msgid "[%s] Registration Denied"
61
  msgstr "[%s] Registrazione Negata"
62
 
63
+ #: new-user-approve.php:559
64
+ #, php-format
65
+ msgid "[%s] User Approval"
66
+ msgstr "[%s] Approvazione Utente"
67
 
68
+ #: includes/user-list.php:383
69
+ msgid "Access Status"
70
+ msgstr "Stato di accesso"
71
 
72
+ #: includes/admin-approve.php:136 includes/admin-approve.php:138
73
+ msgid "Action"
74
+ msgstr ""
75
 
76
+ #: includes/invitation-code.php:693
77
+ msgid "Actions"
78
+ msgstr "Azioni"
79
 
80
+ #: includes/invitation-code.php:187 includes/invitation-code.php:293
81
+ msgid "Add Codes"
82
+ msgstr "Aggiungi codici"
83
 
84
+ #: includes/invitation-code.php:145
85
+ msgid "Add New"
86
+ msgstr "Aggiungere nuova"
87
 
88
+ #: includes/invitation-code.php:146
89
+ msgid "Add New Invitation Code"
90
+ msgstr "Aggiungi nuovo codice invito"
91
 
92
+ #: includes/messages.php:104
93
+ msgid ""
94
+ "After you register, your request will be sent to the site administrator for "
95
+ "approval. You will then receive an email with further instructions."
96
+ msgstr ""
97
+ "Dopo esservi registrati la vostra richiesta sarà spedita ad un "
98
+ "amministratore. Riceverete ulteriori istruzioni su come procedere via email."
99
 
100
+ #: includes/invitation-code.php:125 includes/invitation-code.php:143
101
+ #: includes/invitation-code.php:144
102
+ msgid "All Codes"
103
+ msgstr "Tutti i codici"
104
 
105
+ #: includes/invitation-code.php:150
106
+ msgid "All Invitation Code"
107
+ msgstr "Tutti i codici di invito"
108
+
109
+ #. Description of the plugin
110
+ msgid ""
111
+ "Allow administrators to approve users once they register. Only approved "
112
+ "users will be allowed to access the site. For support, please go to the <a "
113
+ "href=\"http://wordpress.org/support/plugin/new-user-approve\">support "
114
+ "forums</a> on wordpress.org."
115
+ msgstr ""
116
+ "Consenti agli amministratori di approvare gli utenti una volta registrati. "
117
+ "Solo gli utenti autorizzati potranno accedere al sito. Per assistenza, vai "
118
+ "ai <a href=\"http://wordpress.org/support/plugin/new-user-approve\">forum di "
119
+ "supporto</a> su wordpress.org."
120
 
121
+ #: includes/messages.php:41
122
+ msgid ""
123
+ "An email has been sent to the site administrator. The administrator will "
124
+ "review the information that has been submitted and either approve or deny "
125
+ "your request."
126
+ msgstr ""
127
+ "Una email con la vostra richiesta è stata spedita all'amministratore del "
128
+ "sito. Dopo averla controllata l'amministratore deciderà se approvarla o "
129
+ "negarla."
130
+
131
+ #: includes/admin-approve.php:397
132
+ msgid "API Key: "
133
+ msgstr "Chiave API:"
134
+
135
+ #: includes/admin-approve.php:191 includes/user-list.php:104
136
+ #: includes/user-list.php:257 includes/user-list.php:258
137
  msgid "Approve"
138
  msgstr "Approva"
139
 
140
+ #: includes/admin-approve.php:66
141
+ msgid "Approve New Users"
142
+ msgstr "Gestione Richieste"
 
143
 
144
+ #: includes/admin-approve.php:287
145
+ #, fuzzy
146
+ msgid "Approve Users"
147
+ msgstr "Utenti Approvati"
148
+
149
+ #: includes/admin-approve.php:211 includes/user-list.php:150
150
  msgid "approved"
151
  msgstr "approvato"
152
 
153
+ #: includes/admin-approve.php:121 includes/admin-approve.php:308
154
+ msgid "Approved Users"
155
+ msgstr "Utenti Approvati"
156
+
157
+ #: includes/invitation-code.php:203
158
+ msgid "Auto Generate"
159
+ msgstr "Genera automaticamente"
160
+
161
+ #: includes/user-list.php:399
162
+ msgid "Current user status is <strong>pending</strong>."
163
+ msgstr "Lo stato attuale dell'utente è <strong>in attesa</strong>."
164
+
165
+ #: includes/invitation-code.php:425
166
+ msgid "Date"
167
+ msgstr "Data"
168
+
169
+ #: includes/invitation-code.php:723
170
+ msgid "Deactivate"
171
+ msgstr "Disattivare"
172
+
173
+ #: includes/invitation-code.php:723
174
+ msgid "Delete"
175
+ msgstr "Elimina"
176
+
177
+ #: includes/admin-approve.php:213 includes/user-list.php:152
178
  msgid "denied"
179
  msgstr "bloccato"
180
 
181
+ #: includes/admin-approve.php:117 includes/admin-approve.php:310
182
+ msgid "Denied Users"
183
+ msgstr "Utenti Bloccati"
184
 
185
+ #: includes/admin-approve.php:195 includes/user-list.php:105
186
+ #: includes/user-list.php:260 includes/user-list.php:261
187
+ msgid "Deny"
188
+ msgstr "Blocca"
189
 
190
+ #: includes/admin-approve.php:134
191
+ msgid "E-mail"
192
+ msgstr "E-mail"
 
 
 
193
 
194
+ #: includes/invitation-code.php:723
195
+ msgid "Edit"
196
+ msgstr "Modificare"
 
197
 
198
+ #: includes/invitation-code.php:148
199
+ msgid "Edit Invitation Code"
200
+ msgstr "Modifica codice invito"
201
 
202
+ #: includes/invitation-code.php:191
203
+ msgid "Email"
204
+ msgstr "E-mail"
205
+
206
+ #: includes/admin-approve.php:188
207
+ msgid "email:"
208
+ msgstr "email:"
209
+
210
+ #: includes/invitation-code.php:298
211
+ msgid "Enter one code per line."
212
+ msgstr "Inserisci un codice per riga."
213
+
214
+ #: includes/invitation-code.php:691
215
+ msgid "Expiry"
216
+ msgstr "Scadenza"
217
 
218
+ #: includes/invitation-code.php:310
219
+ msgid "Expiry Date"
220
+ msgstr "Data di scadenza"
221
+
222
+ #: includes/admin-approve.php:289
223
  msgid "Feedback"
224
  msgstr ""
225
 
226
+ #: includes/user-list.php:173
227
+ msgid "Filter"
228
+ msgstr "Filtro"
229
 
230
+ #: includes/email-tags.php:277
231
+ msgid "Generates the password for the user to add to the email"
232
+ msgstr "Genera la password per l'utente da aggiungere all'e-mail"
233
 
234
+ #: includes/messages.php:112
235
+ msgid "Hello,"
236
+ msgstr "Ciao,"
237
 
238
+ #. URI of the plugin
239
+ msgid "http://newuserapprove.com/"
240
  msgstr ""
241
 
242
+ #. Author URI of the plugin
243
+ msgid "https://newuserapprove.com/"
244
  msgstr ""
245
 
246
+ #: includes/user-list.php:396
247
+ msgid "If user has access to sign in or not."
248
  msgstr ""
249
 
250
+ #: includes/invitation-code.php:190
251
+ msgid "Import Codes"
252
+ msgstr "Codici di importazione"
253
 
254
+ #: includes/zapier/includes/rest-api.php:78
255
+ #: includes/zapier/includes/rest-api.php:89
256
+ #: includes/zapier/includes/rest-api.php:105
257
+ msgid "Invalid API Key"
258
+ msgstr "Chiave API non valida"
259
 
260
+ #: includes/invitation-code.php:123 includes/invitation-code.php:141
261
+ #: includes/invitation-code.php:142 includes/invitation-code.php:412
262
+ #: includes/invitation-code.php:521 includes/invitation-code.php:689
263
+ msgid "Invitation Code"
264
+ msgstr "Codice di invito"
265
 
266
+ #: includes/invitation-code.php:392
267
+ msgid "Invitation code for new user"
268
+ msgstr "Codice invito per nuovo utente"
269
+
270
+ #: includes/invitation-code.php:747
271
+ msgid "Invitation Code for user to register"
272
+ msgstr "Codice di invito per la registrazione dell'utente"
273
+
274
+ #: includes/invitation-code.php:183
275
+ msgid "Invitation Code Settings"
276
+ msgstr "Impostazioni del codice di invito"
277
+
278
+ #: includes/invitation-code.php:202
279
+ msgid "Manual Generate"
280
+ msgstr "Generazione manuale"
281
+
282
+ #: includes/admin-approve.php:133
283
+ msgid "Name"
284
+ msgstr "Nome"
285
+
286
+ #: includes/invitation-code.php:147
287
+ msgid "New Invitation Code"
288
+ msgstr "Nuovo codice di invito"
289
+
290
+ #. Name of the plugin
291
+ msgid "New User Approve"
292
  msgstr ""
293
 
294
+ #: new-user-approve.php:169
295
  #, php-format
296
+ msgid "New User Approve requires WordPress %s or newer."
297
+ msgstr ""
298
 
299
+ #: includes/invitation-code.php:476
300
+ msgid "No User Found"
301
+ msgstr "Nessun utente trovato"
302
+
303
+ #: includes/email-tags.php:396
304
  #, php-format
305
  msgid "Password: %s"
306
  msgstr "Password: %s"
307
 
308
+ #: includes/admin-approve.php:215 includes/user-list.php:154
309
+ msgid "pending"
310
+ msgstr "in attesa"
 
311
 
312
+ #: new-user-approve.php:794
313
+ msgid "Pending Approval"
314
+ msgstr "Richiesta in Attesa"
315
+
316
+ #: includes/admin-approve.php:125 includes/admin-approve.php:306
317
+ msgid "Pending Users"
318
+ msgstr "Utenti in attesa"
319
 
320
+ #: includes/admin-approve.php:314
321
+ msgid "Pro Features"
322
+ msgstr "Funzionalità professionali"
323
+
324
+ #: new-user-approve.php:790
325
+ msgid "Registration successful."
326
+ msgstr "Registrazione richiesta."
327
+
328
+ #: includes/zapier/includes/rest-api.php:75
329
+ #: includes/zapier/includes/rest-api.php:86
330
+ #: includes/zapier/includes/rest-api.php:102
331
+ msgid "Required Parameter Missing"
332
+ msgstr "Parametro obbligatorio mancante"
333
+
334
+ #: includes/invitation-code.php:189
335
+ msgid "Settings"
336
+ msgstr "Impostazioni"
337
+
338
+ #: includes/invitation-code.php:429 includes/invitation-code.php:692
339
+ #: includes/user-list.php:127
340
+ msgid "Status"
341
+ msgstr "Stato"
342
+
343
+ #: includes/admin-approve.php:288
344
+ msgid "Support"
345
+ msgstr "Supporto"
346
+
347
+ #: includes/messages.php:118
348
+ msgid "Thank You"
349
+ msgstr "Grazie"
350
+
351
+ #: includes/messages.php:114
352
  msgid ""
353
+ "Thank you for registering on our site. We have successfully received your "
354
+ "request and is currently pending for approval."
 
355
  msgstr ""
356
+ "Grazie per esserti registrato sul nostro sito. Abbiamo ricevuto "
357
+ "correttamente la tua richiesta ed è attualmente in attesa di approvazione."
 
358
 
359
+ #: includes/messages.php:116
360
  msgid ""
361
+ "The administrator will review the information that has been submitted after "
362
+ "which they will either approve or deny your request. You will receive an "
363
+ "email with the instructions on what you will need to do next."
364
  msgstr ""
365
+ "\n"
366
+ "L'amministratore esaminerà le informazioni che sono state inviate dopo di "
367
+ "che approverà o rifiuterà la tua richiesta. Riceverai un'e-mail con le "
368
+ "istruzioni su cosa dovrai fare dopo."
369
 
370
+ #: includes/email-tags.php:271
371
+ msgid "The URL for a user to set/reset their password"
 
 
 
372
  msgstr ""
373
+ "\n"
374
+ "L'URL per un utente per impostare/reimpostare la propria password"
 
375
 
376
+ #: includes/email-tags.php:259
377
+ msgid "The URL to approve/deny users"
378
+ msgstr "L'URL per approvare/rifiutare gli utenti"
379
+
380
+ #: includes/email-tags.php:265
381
+ msgid "The URL to login to the site"
382
+ msgstr "L'URL per accedere al sito"
383
+
384
+ #: includes/email-tags.php:241
385
+ msgid "The user's email address"
386
+ msgstr ""
387
+ "L'indirizzo email dell'utente\n"
388
 
389
+ #: includes/email-tags.php:235
390
+ msgid "The user's username on the site as well as the Username label"
391
+ msgstr "Il nome utente dell'utente sul sito e l'etichetta del nome utente"
392
+
393
+ #: includes/admin-approve.php:220
394
+ #, php-format
395
+ msgid "There are no users with a status of %s"
396
+ msgstr "Non ci sono utenti nello lo stato \"%s\""
397
+
398
+ #: includes/messages.php:89
399
  #, fuzzy
400
  msgid "To approve or deny this user access to {sitename} go to"
401
  msgstr "Per approvare o bloccare questo utente a %s vai su"
402
 
403
+ #: includes/messages.php:12
404
+ msgid "To set or reset your password, visit the following address:"
 
 
405
  msgstr ""
406
+ "Per impostare o reimpostare la password, visitare il seguente indirizzo:"
 
407
 
408
+ #: includes/admin-approve.php:411
409
+ msgid "Triggers"
410
  msgstr ""
411
 
412
+ #: includes/admin-approve.php:379
413
+ msgid "Triggers when a user is Approved."
414
  msgstr ""
415
 
416
+ #: includes/admin-approve.php:380
417
+ msgid "Triggers when a user is Denied."
418
  msgstr ""
419
 
420
+ #: includes/admin-approve.php:67
421
+ msgid "Upgrade"
422
+ msgstr "Aggiornamento"
423
+
424
+ #: includes/invitation-code.php:302 includes/invitation-code.php:421
425
+ msgid "Usage Limit"
426
+ msgstr "Limite di utilizzo"
427
 
428
+ #: includes/user-list.php:359
429
  #, fuzzy, php-format
430
  msgid "User approved."
431
  msgid_plural "%s users approved."
432
  msgstr[0] "Approvazione Nuovo Utente"
433
  msgstr[1] "Approvazione Nuovo Utente"
434
 
435
+ #: includes/user-list.php:354
436
+ #, fuzzy, php-format
437
+ msgid "User denied."
438
+ msgid_plural "%s users denied."
439
+ msgstr[0] "bloccato"
440
+ msgstr[1] "bloccato"
441
+
442
+ #: includes/invitation-code.php:469
443
+ msgid "User Not Found"
444
+ msgstr "Utente non trovato"
445
+
446
+ #: admin/templates/approve.php:11
447
+ msgid "User Registration Approval"
448
+ msgstr "Gestione delle Registrazioni"
449
+
450
+ #: admin/templates/approve.php:6
451
+ msgid "User successfully updated."
452
+ msgstr "Utente correttamente aggiornato"
453
+
454
+ #: includes/admin-approve.php:132
455
+ msgid "Username"
456
+ msgstr "Nome utente"
457
+
458
+ #: includes/email-tags.php:305
459
+ #, php-format
460
+ msgid "Username: %s"
461
+ msgstr "Nome utente : %s"
462
+
463
+ #: new-user-approve.php:522
464
+ msgid "Users"
465
+ msgstr "Utenti"
466
+
467
+ #: includes/invitation-code.php:441
468
+ msgid "Users that have registered by using this invitation code"
469
+ msgstr "Utenti che si sono registrati utilizzando questo codice di invito"
470
+
471
+ #: includes/invitation-code.php:417
472
+ msgid "Uses left"
473
+ msgstr "Usi a sinistra"
474
+
475
+ #: includes/invitation-code.php:690
476
+ msgid "Uses Remaining"
477
+ msgstr "Utilizza rimanente"
478
+
479
+ #: includes/user-list.php:177 includes/user-list.php:179
480
+ msgid "View all users"
481
+ msgstr "Visualizza tutti gli utenti"
482
+
483
+ #: includes/invitation-code.php:149
484
+ msgid "View Invitation Code"
485
+ msgstr "Visualizza il codice di invito"
486
+
487
+ #: includes/admin-approve.php:393
488
+ msgid "Website URL: "
489
+ msgstr "URL del sito:"
490
+
491
+ #: includes/messages.php:74
492
+ #, fuzzy
493
+ msgid ""
494
+ "Welcome to {sitename}. This site is accessible to approved users only. To be "
495
+ "approved, you must first register."
496
  msgstr ""
497
+ "Benvenuto su  %s. Questo sito è accessibile soltanto ad utenti registrati e "
498
+ "approvati da un amministratore. Per chiedere un accesso dovete prima "
499
+ "registrarvi."
500
 
501
+ #. Author of the plugin
502
+ msgid "WPExpertsio"
503
  msgstr ""
504
 
505
+ #: includes/admin-approve.php:260
506
+ #, php-format
507
+ msgid ""
508
+ "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
509
+ "| <a href=\"%2$s\">Hide Notice</a>"
510
  msgstr ""
511
+ "\n"
512
+ "Ora puoi aggiornare lo stato utente nella <a href=\"%1$s\">pagina di "
513
+ "amministrazione degli utenti</a>. | <a href=\"%2$s\">Nascondi avviso</a>"
514
 
515
+ #: includes/messages.php:9
516
+ #, fuzzy
517
+ msgid "You have been approved to access {sitename}"
518
+ msgstr "Il vostro accesso a %s e' stato approvato."
519
+
520
+ #: includes/messages.php:53
521
+ msgid ""
522
+ "You have been approved to access {sitename}. You will receive an email with "
523
+ "instructions on what you will need to do next. Thanks for your patience.\n"
524
+ "\n"
525
+ "\t"
526
  msgstr ""
527
+ "\n"
528
+ "Sei stato autorizzato ad accedere a {sitename}. Riceverai un'e-mail con le "
529
+ "istruzioni su cosa dovrai fare dopo. Grazie per la vostra pazienza."
530
 
531
+ #: includes/messages.php:28
532
+ #, fuzzy
533
+ msgid "You have been denied access to {sitename}."
534
+ msgstr "Vi è stato negato l'accesso a %s"
535
 
536
+ #: includes/messages.php:43 includes/messages.php:57
537
+ msgid ""
538
+ "You will receive an email with instructions on what you will need to do next."
539
+ " Thanks for your patience."
540
+ msgstr ""
541
+ "Riceverete una email con ulteriori istruzioni su come procedere. Grazie "
542
+ "della vostra pazienza."
543
 
544
+ #: new-user-approve.php:631
545
+ #, php-format
546
+ msgid "Your registration is pending for approval - [%s]"
547
+ msgstr "La tua registrazione è in attesa di approvazione - [%s]"
548
 
549
+ #: includes/email-tags.php:247
550
+ msgid "Your site name"
551
+ msgstr ""
552
+ "\n"
553
+ "Il nome del tuo sito"
554
 
555
+ #: includes/email-tags.php:253
556
+ msgid "Your site URL"
557
+ msgstr ""
558
+ "\n"
559
+ "L'URL del tuo sito"
560
 
561
+ #: includes/admin-approve.php:312
562
+ msgid "Zapier"
563
+ msgstr "Zapier"
 
 
 
 
564
 
565
+ #: includes/admin-approve.php:389
566
+ msgid "Zapier Settings"
567
+ msgstr "Impostazioni Zapier"
568
 
569
+ #: includes/messages.php:87
570
+ #, fuzzy
571
+ msgid "{username} ({user_email}) has requested a username at {sitename}"
572
+ msgstr "%1$s (%2$s) ha richiesto un nome utente a %3$s"
localization/new-user-approve.pot CHANGED
@@ -1,299 +1,543 @@
1
- # New User Approve WordPress plugin
2
- # Copyright (C) 2013 Josh Harrison
3
- # This file is distributed under the same license as the parent package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
6
  msgid ""
7
  msgstr ""
 
8
  "Project-Id-Version: New User Approve\n"
9
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/new-user-approve\n"
10
- "POT-Creation-Date: 2014-10-08 23:50-0700\n"
11
- "PO-Revision-Date: 2014-10-09 00:03-0700\n"
12
- "Last-Translator: Josh Harrison <josh@picklewagon.com>\n"
13
- "Language-Team: Picklewagon <josh@picklewagon.com>\n"
14
- "Language: English\n"
15
  "MIME-Version: 1.0\n"
16
  "Content-Type: text/plain; charset=UTF-8\n"
17
  "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=2; plural=n != 1;\n"
19
- "X-Generator: Poedit 1.5.7\n"
 
 
20
  "X-Poedit-SourceCharset: UTF-8\n"
21
- "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
22
- "X-Poedit-Basepath: .\n"
23
- "X-Poedit-SearchPath-0: ..\n"
24
- "X-Poedit-SearchPath-1: ../includes\n"
 
25
 
26
- #: ../new-user-approve.php:98
27
- #, php-format
28
- msgid "New User Approve requires WordPress %s or newer."
29
- msgstr ""
30
-
31
- #: ../new-user-approve.php:145
32
- #, php-format
33
- msgid ""
34
- "The Membership setting must be turned on in order for the New User Approve "
35
- "to work correctly. <a href=\"%1$s\">Update in settings</a>. | <a href=\"%2$s"
36
- "\">Hide Notice</a>"
37
- msgstr ""
38
-
39
- #: ../new-user-approve.php:257
40
- msgid "<strong>ERROR</strong>: Your account is still pending approval."
41
- msgstr ""
42
-
43
- #: ../new-user-approve.php:260
44
- msgid ""
45
- "<strong>ERROR</strong>: Your account has been denied access to this site."
46
- msgstr ""
47
-
48
- #: ../new-user-approve.php:362
49
- msgid "Users"
50
- msgstr ""
51
-
52
- #: ../new-user-approve.php:392
53
- #, php-format
54
- msgid "[%s] User Approval"
55
- msgstr ""
56
-
57
- #: ../new-user-approve.php:454
58
- #, php-format
59
- msgid ""
60
- "<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a "
61
- "href=\"mailto:%s\">webmaster</a> !"
62
- msgstr ""
63
-
64
- #: ../new-user-approve.php:520
65
- #, php-format
66
- msgid "[%s] Registration Approved"
67
  msgstr ""
68
 
69
- #: ../new-user-approve.php:550
70
- #, php-format
71
- msgid "[%s] Registration Denied"
72
  msgstr ""
73
 
74
- #: ../new-user-approve.php:614
75
- msgid "Registration successful."
76
  msgstr ""
77
 
78
- #: ../new-user-approve.php:617
79
- msgid "Pending Approval"
80
  msgstr ""
81
 
82
- #: ../admin/templates/approve.php:6
83
- msgid "User successfully updated."
84
  msgstr ""
85
 
86
- #: ../admin/templates/approve.php:11
87
- msgid "User Registration Approval"
88
  msgstr ""
89
 
90
- #: ../includes/admin-approve.php:50
91
- msgid "Approve New Users"
92
  msgstr ""
93
 
94
- #: ../includes/admin-approve.php:82
95
  msgid "Username"
96
  msgstr ""
97
 
98
- #: ../includes/admin-approve.php:83
99
  msgid "Name"
100
  msgstr ""
101
 
102
- #: ../includes/admin-approve.php:84
103
  msgid "E-mail"
104
  msgstr ""
105
 
106
- #: ../includes/admin-approve.php:86 ../includes/admin-approve.php:88
107
- msgid "Actions"
108
  msgstr ""
109
 
110
- #: ../includes/admin-approve.php:129
111
  msgid "email:"
112
  msgstr ""
113
 
114
- #: ../includes/admin-approve.php:133 ../includes/user-list.php:97
115
- #: ../includes/user-list.php:223 ../includes/user-list.php:224
116
  msgid "Approve"
117
  msgstr ""
118
 
119
- #: ../includes/admin-approve.php:138 ../includes/user-list.php:98
120
- #: ../includes/user-list.php:226 ../includes/user-list.php:227
121
  msgid "Deny"
122
  msgstr ""
123
 
124
- #: ../includes/admin-approve.php:154
125
  msgid "approved"
126
  msgstr ""
127
 
128
- #: ../includes/admin-approve.php:156
129
  msgid "denied"
130
  msgstr ""
131
 
132
- #: ../includes/admin-approve.php:158
133
  msgid "pending"
134
  msgstr ""
135
 
136
- #: ../includes/admin-approve.php:161
137
  #, php-format
138
  msgid "There are no users with a status of %s"
139
  msgstr ""
140
 
141
- #: ../includes/admin-approve.php:197
142
  #, php-format
143
  msgid ""
144
  "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
145
  "| <a href=\"%2$s\">Hide Notice</a>"
146
  msgstr ""
147
 
148
- #: ../includes/admin-approve.php:220
149
  msgid "Approve Users"
150
  msgstr ""
151
 
152
- #: ../includes/admin-approve.php:221
153
- msgid "Updates"
154
- msgstr ""
155
-
156
- #: ../includes/admin-approve.php:222
157
  msgid "Support"
158
  msgstr ""
159
 
160
- #: ../includes/admin-approve.php:223
161
  msgid "Feedback"
162
  msgstr ""
163
 
164
- #: ../includes/admin-approve.php:231
165
- msgid "Users Pending Approval"
166
  msgstr ""
167
 
168
- #: ../includes/admin-approve.php:233
169
- msgid "Approved Users"
170
  msgstr ""
171
 
172
- #: ../includes/admin-approve.php:235
173
- msgid "Denied Users"
 
 
 
 
 
 
 
 
174
  msgstr ""
175
 
176
- #: ../includes/email-tags.php:235
 
 
 
 
 
 
 
 
 
 
 
 
177
  msgid "The user's username on the site as well as the Username label"
178
  msgstr ""
179
 
180
- #: ../includes/email-tags.php:241
181
  msgid "The user's email address"
182
  msgstr ""
183
 
184
- #: ../includes/email-tags.php:247
185
  msgid "Your site name"
186
  msgstr ""
187
 
188
- #: ../includes/email-tags.php:253
189
  msgid "Your site URL"
190
  msgstr ""
191
 
192
- #: ../includes/email-tags.php:259
193
  msgid "The URL to approve/deny users"
194
  msgstr ""
195
 
196
- #: ../includes/email-tags.php:265
197
  msgid "The URL to login to the site"
198
  msgstr ""
199
 
200
- #: ../includes/email-tags.php:271
 
 
 
 
201
  msgid "Generates the password for the user to add to the email"
202
  msgstr ""
203
 
204
- #: ../includes/email-tags.php:299
205
  #, php-format
206
  msgid "Username: %s"
207
  msgstr ""
208
 
209
- #: ../includes/email-tags.php:390
210
  #, php-format
211
  msgid "Password: %s"
212
  msgstr ""
213
 
214
- #: ../includes/messages.php:9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  msgid "You have been approved to access {sitename}"
216
  msgstr ""
217
 
218
- #: ../includes/messages.php:12
219
  msgid "To set or reset your password, visit the following address:"
220
  msgstr ""
221
 
222
- #: ../includes/messages.php:25
223
  msgid "You have been denied access to {sitename}."
224
  msgstr ""
225
 
226
- #: ../includes/messages.php:38
227
  msgid ""
228
  "An email has been sent to the site administrator. The administrator will "
229
  "review the information that has been submitted and either approve or deny "
230
  "your request."
231
  msgstr ""
232
 
233
- #: ../includes/messages.php:40
234
  msgid ""
235
  "You will receive an email with instructions on what you will need to do "
236
  "next. Thanks for your patience."
237
  msgstr ""
238
 
239
- #: ../includes/messages.php:53
 
 
 
 
 
 
 
 
240
  msgid ""
241
  "Welcome to {sitename}. This site is accessible to approved users only. To be "
242
  "approved, you must first register."
243
  msgstr ""
244
 
245
- #: ../includes/messages.php:66
246
  msgid "{username} ({user_email}) has requested a username at {sitename}"
247
  msgstr ""
248
 
249
- #: ../includes/messages.php:68
250
  msgid "To approve or deny this user access to {sitename} go to"
251
  msgstr ""
252
 
253
- #: ../includes/messages.php:83
254
  msgid ""
255
  "After you register, your request will be sent to the site administrator for "
256
  "approval. You will then receive an email with further instructions."
257
  msgstr ""
258
 
259
- #: ../includes/user-list.php:120
260
- msgid "Status"
261
  msgstr ""
262
 
263
- #: ../includes/user-list.php:156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  msgid "Filter"
265
  msgstr ""
266
 
267
- #: ../includes/user-list.php:161 ../includes/user-list.php:163
268
  msgid "View all users"
269
  msgstr ""
270
 
271
- #: ../includes/user-list.php:320
272
  #, php-format
273
  msgid "User denied."
274
  msgid_plural "%s users denied."
275
  msgstr[0] ""
276
  msgstr[1] ""
277
 
278
- #: ../includes/user-list.php:325
279
  #, php-format
280
  msgid "User approved."
281
  msgid_plural "%s users approved."
282
  msgstr[0] ""
283
  msgstr[1] ""
284
 
285
- #: ../includes/user-list.php:349
286
  msgid "Access Status"
287
  msgstr ""
288
 
289
- #: ../includes/user-list.php:354
290
  msgid "-- Status --"
291
  msgstr ""
292
 
293
- #: ../includes/user-list.php:362
294
  msgid "If user has access to sign in or not."
295
  msgstr ""
296
 
297
- #: ../includes/user-list.php:365
298
  msgid "Current user status is <strong>pending</strong>."
299
  msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #, fuzzy
 
 
 
 
2
  msgid ""
3
  msgstr ""
4
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
5
  "Project-Id-Version: New User Approve\n"
6
+ "POT-Creation-Date: 2022-07-15 11:47+0500\n"
7
+ "PO-Revision-Date: 2022-07-15 11:46+0500\n"
8
+ "Last-Translator: \n"
9
+ "Language-Team: \n"
 
 
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Poedit 2.2\n"
14
+ "X-Poedit-Basepath: ..\n"
15
+ "X-Poedit-Flags-xgettext: --add-comments=translators:\n"
16
+ "X-Poedit-WPHeader: new-user-approve.php\n"
17
  "X-Poedit-SourceCharset: UTF-8\n"
18
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
19
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
20
+ "_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
21
+ "X-Poedit-SearchPath-0: .\n"
22
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
23
 
24
+ #: admin/templates/approve.php:6
25
+ msgid "User successfully updated."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  msgstr ""
27
 
28
+ #: admin/templates/approve.php:11
29
+ msgid "User Registration Approval"
 
30
  msgstr ""
31
 
32
+ #: includes/admin-approve.php:66
33
+ msgid "Approve New Users"
34
  msgstr ""
35
 
36
+ #: includes/admin-approve.php:67
37
+ msgid "Upgrade"
38
  msgstr ""
39
 
40
+ #: includes/admin-approve.php:117 includes/admin-approve.php:310
41
+ msgid "Denied Users"
42
  msgstr ""
43
 
44
+ #: includes/admin-approve.php:121 includes/admin-approve.php:308
45
+ msgid "Approved Users"
46
  msgstr ""
47
 
48
+ #: includes/admin-approve.php:125 includes/admin-approve.php:306
49
+ msgid "Pending Users"
50
  msgstr ""
51
 
52
+ #: includes/admin-approve.php:132
53
  msgid "Username"
54
  msgstr ""
55
 
56
+ #: includes/admin-approve.php:133
57
  msgid "Name"
58
  msgstr ""
59
 
60
+ #: includes/admin-approve.php:134
61
  msgid "E-mail"
62
  msgstr ""
63
 
64
+ #: includes/admin-approve.php:136 includes/admin-approve.php:138
65
+ msgid "Action"
66
  msgstr ""
67
 
68
+ #: includes/admin-approve.php:188
69
  msgid "email:"
70
  msgstr ""
71
 
72
+ #: includes/admin-approve.php:191 includes/user-list.php:104
73
+ #: includes/user-list.php:257 includes/user-list.php:258
74
  msgid "Approve"
75
  msgstr ""
76
 
77
+ #: includes/admin-approve.php:195 includes/user-list.php:105
78
+ #: includes/user-list.php:260 includes/user-list.php:261
79
  msgid "Deny"
80
  msgstr ""
81
 
82
+ #: includes/admin-approve.php:211 includes/user-list.php:150
83
  msgid "approved"
84
  msgstr ""
85
 
86
+ #: includes/admin-approve.php:213 includes/user-list.php:152
87
  msgid "denied"
88
  msgstr ""
89
 
90
+ #: includes/admin-approve.php:215 includes/user-list.php:154
91
  msgid "pending"
92
  msgstr ""
93
 
94
+ #: includes/admin-approve.php:220
95
  #, php-format
96
  msgid "There are no users with a status of %s"
97
  msgstr ""
98
 
99
+ #: includes/admin-approve.php:260
100
  #, php-format
101
  msgid ""
102
  "You can now update user status on the <a href=\"%1$s\">users admin page</a>. "
103
  "| <a href=\"%2$s\">Hide Notice</a>"
104
  msgstr ""
105
 
106
+ #: includes/admin-approve.php:287
107
  msgid "Approve Users"
108
  msgstr ""
109
 
110
+ #: includes/admin-approve.php:288
 
 
 
 
111
  msgid "Support"
112
  msgstr ""
113
 
114
+ #: includes/admin-approve.php:289
115
  msgid "Feedback"
116
  msgstr ""
117
 
118
+ #: includes/admin-approve.php:312
119
+ msgid "Zapier"
120
  msgstr ""
121
 
122
+ #: includes/admin-approve.php:314
123
+ msgid "Pro Features"
124
  msgstr ""
125
 
126
+ #: includes/admin-approve.php:379
127
+ msgid "Triggers when a user is Approved."
128
+ msgstr ""
129
+
130
+ #: includes/admin-approve.php:380
131
+ msgid "Triggers when a user is Denied."
132
+ msgstr ""
133
+
134
+ #: includes/admin-approve.php:389
135
+ msgid "Zapier Settings"
136
  msgstr ""
137
 
138
+ #: includes/admin-approve.php:393
139
+ msgid "Website URL: "
140
+ msgstr ""
141
+
142
+ #: includes/admin-approve.php:397
143
+ msgid "API Key: "
144
+ msgstr ""
145
+
146
+ #: includes/admin-approve.php:411
147
+ msgid "Triggers"
148
+ msgstr ""
149
+
150
+ #: includes/email-tags.php:235
151
  msgid "The user's username on the site as well as the Username label"
152
  msgstr ""
153
 
154
+ #: includes/email-tags.php:241
155
  msgid "The user's email address"
156
  msgstr ""
157
 
158
+ #: includes/email-tags.php:247
159
  msgid "Your site name"
160
  msgstr ""
161
 
162
+ #: includes/email-tags.php:253
163
  msgid "Your site URL"
164
  msgstr ""
165
 
166
+ #: includes/email-tags.php:259
167
  msgid "The URL to approve/deny users"
168
  msgstr ""
169
 
170
+ #: includes/email-tags.php:265
171
  msgid "The URL to login to the site"
172
  msgstr ""
173
 
174
+ #: includes/email-tags.php:271
175
+ msgid "The URL for a user to set/reset their password"
176
+ msgstr ""
177
+
178
+ #: includes/email-tags.php:277
179
  msgid "Generates the password for the user to add to the email"
180
  msgstr ""
181
 
182
+ #: includes/email-tags.php:305
183
  #, php-format
184
  msgid "Username: %s"
185
  msgstr ""
186
 
187
+ #: includes/email-tags.php:396
188
  #, php-format
189
  msgid "Password: %s"
190
  msgstr ""
191
 
192
+ #: includes/invitation-code.php:123 includes/invitation-code.php:141
193
+ #: includes/invitation-code.php:142 includes/invitation-code.php:412
194
+ #: includes/invitation-code.php:521 includes/invitation-code.php:689
195
+ msgid "Invitation Code"
196
+ msgstr ""
197
+
198
+ #: includes/invitation-code.php:125 includes/invitation-code.php:143
199
+ #: includes/invitation-code.php:144
200
+ msgid "All Codes"
201
+ msgstr ""
202
+
203
+ #: includes/invitation-code.php:145
204
+ msgid "Add New"
205
+ msgstr ""
206
+
207
+ #: includes/invitation-code.php:146
208
+ msgid "Add New Invitation Code"
209
+ msgstr ""
210
+
211
+ #: includes/invitation-code.php:147
212
+ msgid "New Invitation Code"
213
+ msgstr ""
214
+
215
+ #: includes/invitation-code.php:148
216
+ msgid "Edit Invitation Code"
217
+ msgstr ""
218
+
219
+ #: includes/invitation-code.php:149
220
+ msgid "View Invitation Code"
221
+ msgstr ""
222
+
223
+ #: includes/invitation-code.php:150
224
+ msgid "All Invitation Code"
225
+ msgstr ""
226
+
227
+ #: includes/invitation-code.php:183
228
+ msgid "Invitation Code Settings"
229
+ msgstr ""
230
+
231
+ #: includes/invitation-code.php:187 includes/invitation-code.php:293
232
+ msgid "Add Codes"
233
+ msgstr ""
234
+
235
+ #: includes/invitation-code.php:189
236
+ msgid "Settings"
237
+ msgstr ""
238
+
239
+ #: includes/invitation-code.php:190
240
+ msgid "Import Codes"
241
+ msgstr ""
242
+
243
+ #: includes/invitation-code.php:191
244
+ msgid "Email"
245
+ msgstr ""
246
+
247
+ #: includes/invitation-code.php:202
248
+ msgid "Manual Generate"
249
+ msgstr ""
250
+
251
+ #: includes/invitation-code.php:203
252
+ msgid "Auto Generate"
253
+ msgstr ""
254
+
255
+ #: includes/invitation-code.php:298
256
+ msgid "Enter one code per line."
257
+ msgstr ""
258
+
259
+ #: includes/invitation-code.php:302 includes/invitation-code.php:421
260
+ msgid "Usage Limit"
261
+ msgstr ""
262
+
263
+ #: includes/invitation-code.php:310
264
+ msgid "Expiry Date"
265
+ msgstr ""
266
+
267
+ #: includes/invitation-code.php:392
268
+ msgid "Invitation code for new user"
269
+ msgstr ""
270
+
271
+ #: includes/invitation-code.php:417
272
+ msgid "Uses left"
273
+ msgstr ""
274
+
275
+ #: includes/invitation-code.php:425
276
+ msgid "Date"
277
+ msgstr ""
278
+
279
+ #: includes/invitation-code.php:429 includes/invitation-code.php:692
280
+ #: includes/user-list.php:127
281
+ msgid "Status"
282
+ msgstr ""
283
+
284
+ #: includes/invitation-code.php:441
285
+ msgid "Users that have registered by using this invitation code"
286
+ msgstr ""
287
+
288
+ #: includes/invitation-code.php:469
289
+ msgid "User Not Found"
290
+ msgstr ""
291
+
292
+ #: includes/invitation-code.php:476
293
+ msgid "No User Found"
294
+ msgstr ""
295
+
296
+ #: includes/invitation-code.php:579
297
+ msgid "<strong>ERROR</strong>: The Invitation code is invalid"
298
+ msgstr ""
299
+
300
+ #: includes/invitation-code.php:582
301
+ msgid "<strong>ERROR</strong>: Please add an Invitation code."
302
+ msgstr ""
303
+
304
+ #: includes/invitation-code.php:690
305
+ msgid "Uses Remaining"
306
+ msgstr ""
307
+
308
+ #: includes/invitation-code.php:691
309
+ msgid "Expiry"
310
+ msgstr ""
311
+
312
+ #: includes/invitation-code.php:693
313
+ msgid "Actions"
314
+ msgstr ""
315
+
316
+ #: includes/invitation-code.php:723
317
+ msgid "Deactivate"
318
+ msgstr ""
319
+
320
+ #: includes/invitation-code.php:723
321
+ msgid "Edit"
322
+ msgstr ""
323
+
324
+ #: includes/invitation-code.php:723
325
+ msgid "Delete"
326
+ msgstr ""
327
+
328
+ #: includes/invitation-code.php:747
329
+ msgid "Invitation Code for user to register"
330
+ msgstr ""
331
+
332
+ #: includes/messages.php:9
333
  msgid "You have been approved to access {sitename}"
334
  msgstr ""
335
 
336
+ #: includes/messages.php:12
337
  msgid "To set or reset your password, visit the following address:"
338
  msgstr ""
339
 
340
+ #: includes/messages.php:28
341
  msgid "You have been denied access to {sitename}."
342
  msgstr ""
343
 
344
+ #: includes/messages.php:41
345
  msgid ""
346
  "An email has been sent to the site administrator. The administrator will "
347
  "review the information that has been submitted and either approve or deny "
348
  "your request."
349
  msgstr ""
350
 
351
+ #: includes/messages.php:43 includes/messages.php:57
352
  msgid ""
353
  "You will receive an email with instructions on what you will need to do "
354
  "next. Thanks for your patience."
355
  msgstr ""
356
 
357
+ #: includes/messages.php:53
358
+ msgid ""
359
+ "You have been approved to access {sitename}. You will receive an email with "
360
+ "instructions on what you will need to do next. Thanks for your patience.\n"
361
+ "\n"
362
+ "\t"
363
+ msgstr ""
364
+
365
+ #: includes/messages.php:74
366
  msgid ""
367
  "Welcome to {sitename}. This site is accessible to approved users only. To be "
368
  "approved, you must first register."
369
  msgstr ""
370
 
371
+ #: includes/messages.php:87
372
  msgid "{username} ({user_email}) has requested a username at {sitename}"
373
  msgstr ""
374
 
375
+ #: includes/messages.php:89
376
  msgid "To approve or deny this user access to {sitename} go to"
377
  msgstr ""
378
 
379
+ #: includes/messages.php:104
380
  msgid ""
381
  "After you register, your request will be sent to the site administrator for "
382
  "approval. You will then receive an email with further instructions."
383
  msgstr ""
384
 
385
+ #: includes/messages.php:112
386
+ msgid "Hello,"
387
  msgstr ""
388
 
389
+ #: includes/messages.php:114
390
+ msgid ""
391
+ "Thank you for registering on our site. We have successfully received your "
392
+ "request and is currently pending for approval."
393
+ msgstr ""
394
+
395
+ #: includes/messages.php:116
396
+ msgid ""
397
+ "The administrator will review the information that has been submitted after "
398
+ "which they will either approve or deny your request. You will receive an "
399
+ "email with the instructions on what you will need to do next."
400
+ msgstr ""
401
+
402
+ #: includes/messages.php:118
403
+ msgid "Thank You"
404
+ msgstr ""
405
+
406
+ #: includes/user-list.php:173
407
  msgid "Filter"
408
  msgstr ""
409
 
410
+ #: includes/user-list.php:177 includes/user-list.php:179
411
  msgid "View all users"
412
  msgstr ""
413
 
414
+ #: includes/user-list.php:354
415
  #, php-format
416
  msgid "User denied."
417
  msgid_plural "%s users denied."
418
  msgstr[0] ""
419
  msgstr[1] ""
420
 
421
+ #: includes/user-list.php:359
422
  #, php-format
423
  msgid "User approved."
424
  msgid_plural "%s users approved."
425
  msgstr[0] ""
426
  msgstr[1] ""
427
 
428
+ #: includes/user-list.php:383
429
  msgid "Access Status"
430
  msgstr ""
431
 
432
+ #: includes/user-list.php:388
433
  msgid "-- Status --"
434
  msgstr ""
435
 
436
+ #: includes/user-list.php:396
437
  msgid "If user has access to sign in or not."
438
  msgstr ""
439
 
440
+ #: includes/user-list.php:399
441
  msgid "Current user status is <strong>pending</strong>."
442
  msgstr ""
443
+
444
+ #: includes/zapier/includes/rest-api.php:75
445
+ #: includes/zapier/includes/rest-api.php:86
446
+ #: includes/zapier/includes/rest-api.php:102
447
+ msgid "Required Parameter Missing"
448
+ msgstr ""
449
+
450
+ #: includes/zapier/includes/rest-api.php:78
451
+ #: includes/zapier/includes/rest-api.php:89
452
+ #: includes/zapier/includes/rest-api.php:105
453
+ msgid "Invalid API Key"
454
+ msgstr ""
455
+
456
+ #: new-user-approve.php:169
457
+ #, php-format
458
+ msgid "New User Approve requires WordPress %s or newer."
459
+ msgstr ""
460
+
461
+ #: new-user-approve.php:342
462
+ msgid "<strong>ERROR</strong>: Your account is still pending approval."
463
+ msgstr ""
464
+
465
+ #: new-user-approve.php:347
466
+ msgid ""
467
+ "<strong>ERROR</strong>: Your account has been denied access to this site."
468
+ msgstr ""
469
+
470
+ #: new-user-approve.php:522
471
+ msgid "Users"
472
+ msgstr ""
473
+
474
+ #: new-user-approve.php:559
475
+ #, php-format
476
+ msgid "[%s] User Approval"
477
+ msgstr ""
478
+
479
+ #: new-user-approve.php:624
480
+ #, php-format
481
+ msgid ""
482
+ "<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a "
483
+ "href=\"mailto:%s\">webmaster</a> !"
484
+ msgstr ""
485
+
486
+ #: new-user-approve.php:631
487
+ #, php-format
488
+ msgid "Your registration is pending for approval - [%s]"
489
+ msgstr ""
490
+
491
+ #: new-user-approve.php:698
492
+ #, php-format
493
+ msgid "[%s] Registration Approved"
494
+ msgstr ""
495
+
496
+ #: new-user-approve.php:728
497
+ #, php-format
498
+ msgid "[%s] Registration Denied"
499
+ msgstr ""
500
+
501
+ #: new-user-approve.php:790
502
+ msgid "Registration successful."
503
+ msgstr ""
504
+
505
+ #: new-user-approve.php:794
506
+ msgid "Pending Approval"
507
+ msgstr ""
508
+
509
+ #: new-user-approve.php:825
510
+ msgid "<strong>ERROR</strong>: User has not been approved."
511
+ msgstr ""
512
+
513
+ #: new-user-approve.php:959
514
+ msgid ""
515
+ " To start using New User Approve Options, please <a href=\"https://users."
516
+ "freemius.com\" target=\"_blank\"> login to your freemius account</a> in "
517
+ "order to download the premium version <br /> For more details <a target="
518
+ "\"_blank\" href=\"https://newuserapprove.com/\">Click here</a>!"
519
+ msgstr ""
520
+
521
+ #. Plugin Name of the plugin/theme
522
+ msgid "New User Approve"
523
+ msgstr ""
524
+
525
+ #. Plugin URI of the plugin/theme
526
+ msgid "http://newuserapprove.com/"
527
+ msgstr ""
528
+
529
+ #. Description of the plugin/theme
530
+ msgid ""
531
+ "Allow administrators to approve users once they register. Only approved "
532
+ "users will be allowed to access the site. For support, please go to the <a "
533
+ "href=\"http://wordpress.org/support/plugin/new-user-approve\">support "
534
+ "forums</a> on wordpress.org."
535
+ msgstr ""
536
+
537
+ #. Author of the plugin/theme
538
+ msgid "WPExpertsio"
539
+ msgstr ""
540
+
541
+ #. Author URI of the plugin/theme
542
+ msgid "https://newuserapprove.com/"
543
+ msgstr ""
new-user-approve.php CHANGED
@@ -5,14 +5,14 @@
5
  Plugin URI: http://newuserapprove.com/
6
  Description: Allow administrators to approve users once they register. Only approved users will be allowed to access the site. For support, please go to the <a href="http://wordpress.org/support/plugin/new-user-approve">support forums</a> on wordpress.org.
7
  Author: WPExpertsio
8
- Version: 2.4.1
9
  Author URI: https://newuserapprove.com/
10
  Text Domain: new-user-approve
11
  */
12
 
13
 
14
  if ( !defined( 'NUA_VERSION' ) ) {
15
- define( 'NUA_VERSION', '2.4.1' );
16
  }
17
 
18
  if ( !function_exists( 'nua_fs' ) ) {
@@ -624,17 +624,20 @@ class pw_new_user_approve
624
  $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
625
  } else {
626
  // User Registeration welcome email
627
- $message = nua_default_registeration_welcome_email();
628
- $message = apply_filters( 'new_user_approve_welcome_user_message', $message, $user_email );
629
- $subject = sprintf( __( 'Your registration is pending for approval - [%s]', 'new-user-approve' ), get_option( 'blogname' ) );
630
- $subject = apply_filters( 'new_user_approve_welcome_user_subject', $subject );
631
-
632
- wp_mail(
633
- $user_email,
634
- $subject,
635
- $message,
636
- $this->email_message_headers()
637
- );
 
 
 
638
  }
639
  }
640
 
5
  Plugin URI: http://newuserapprove.com/
6
  Description: Allow administrators to approve users once they register. Only approved users will be allowed to access the site. For support, please go to the <a href="http://wordpress.org/support/plugin/new-user-approve">support forums</a> on wordpress.org.
7
  Author: WPExpertsio
8
+ Version: 2.5
9
  Author URI: https://newuserapprove.com/
10
  Text Domain: new-user-approve
11
  */
12
 
13
 
14
  if ( !defined( 'NUA_VERSION' ) ) {
15
+ define( 'NUA_VERSION', '2.5' );
16
  }
17
 
18
  if ( !function_exists( 'nua_fs' ) ) {
624
  $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
625
  } else {
626
  // User Registeration welcome email
627
+ $disable = apply_filters('nua_disable_welcome_email',false, $user_id);
628
+ if(false===$disable) {
629
+ $message = nua_default_registeration_welcome_email();
630
+ $message = apply_filters( 'new_user_approve_welcome_user_message', $message, $user_email );
631
+ $subject = sprintf( __( 'Your registration is pending for approval - [%s]', 'new-user-approve' ), get_option( 'blogname' ) );
632
+ $subject = apply_filters( 'new_user_approve_welcome_user_subject', $subject );
633
+
634
+ wp_mail(
635
+ $user_email,
636
+ $subject,
637
+ $message,
638
+ $this->email_message_headers()
639
+ );
640
+ }
641
  }
642
  }
643
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: wpexpertsio
3
  Donate link: https://newuserapprove.com
4
  Tags: users, registration, sign up, user management, login, user approval
5
  Requires at least: 4.0
6
- Tested up to: 6.0
7
- Stable tag: 2.4.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -55,7 +55,7 @@ The clean and easy user interface always helps the existing and the new customer
55
  [youtube https://www.youtube.com/watch?v=RowV3wmD_jg]
56
 
57
  **Compatibility**
58
- New User Approve is compatible with [Post SMTP](https://wordpress.org/plugins/post-smtp/), [WooCommerce](https://woocommerce.com/), [MemberPress](https://memberpress.com/), [WP-Foro](https://wpforo.com/), [Learndash](https://www.learndash.com/), and [Ultimate Member](https://ultimatemember.com/), [BuddyPress](https://buddypress.org/), [Zapier](https://zapier.com/).
59
 
60
  **[Follow New User Approve on Github](https://github.com/wpexpertsio/new-user-approve)**
61
 
@@ -193,6 +193,14 @@ We are aware of a few issues with multisite
193
 
194
  == Changelog ==
195
 
 
 
 
 
 
 
 
 
196
  = 2.4.1 =
197
  * Tweak – Security Fixes
198
 
3
  Donate link: https://newuserapprove.com
4
  Tags: users, registration, sign up, user management, login, user approval
5
  Requires at least: 4.0
6
+ Tested up to: 6.1.1
7
+ Stable tag: 2.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
55
  [youtube https://www.youtube.com/watch?v=RowV3wmD_jg]
56
 
57
  **Compatibility**
58
+ New User Approve is compatible with [WooCommerce](https://woocommerce.com/), [MemberPress](https://memberpress.com/), [WP-Foro](https://wpforo.com/), [Learndash](https://www.learndash.com/), and [Ultimate Member](https://ultimatemember.com/), [BuddyPress](https://buddypress.org/), [Zapier](https://zapier.com/).
59
 
60
  **[Follow New User Approve on Github](https://github.com/wpexpertsio/new-user-approve)**
61
 
193
 
194
  == Changelog ==
195
 
196
+ = 2.5 =
197
+ * Updated localization - pot file updated, French and Italian po mo updated.
198
+ * Fixed - Approve button color issue.
199
+ * Fixed - Duplicate text message on user registration by invitation code.
200
+ * Fixed - Rest API notice.
201
+ * Improvement - When using invitation code user will not be created if invition code is not given or incorrect invitation code is used.
202
+ * Improvement - When user successfully registers via invitation code the welcome email not sent, instead Approve email is sent and success message appears.
203
+
204
  = 2.4.1 =
205
  * Tweak – Security Fixes
206